jxxghp
|
8a6d54204d
|
chore(architecture): keep chain files within complexity budget
|
2026-09-13 14:51:11 +08:00 |
|
jxxghp
|
c1a2e11941
|
chore(architecture): sync mypy diagnostic count
|
2026-09-13 14:41:40 +08:00 |
|
jxxghp
|
b67454eb29
|
Merge pull request #6662 from Aqr-K/feat/plugin-instance-config-logging
feat(plugin): 插件配置与实例描述符迁入独立表,实例可各自设置日志等级
|
2026-09-13 14:30:57 +08:00 |
|
jxxghp
|
c60949ffff
|
Merge branch 'v3' into feat/plugin-instance-config-logging
|
2026-09-13 14:30:42 +08:00 |
|
jxxghp
|
0ae26e3a4d
|
docs: synchronize Ruff diagnostic count
|
2026-09-13 14:26:31 +08:00 |
|
jxxghp
|
c868faf0cf
|
fix(synologychat): skip unsupported command menu registration
|
2026-09-13 14:22:59 +08:00 |
|
Aqr-K
|
3d594ecee3
|
refactor(plugin): 插件配置改走独立通道,SystemConfig 不再按键值分支
插件配置此前借用 systemconfig 的 plugin.<实例ID> 单键,为了换表又在
SystemConfigOper 的 set/delete/load_snapshot 里按该前缀开分支。这是反向依赖:
一个对所有键一视同仁的通用键值存储被迫知道「插件」这个概念,读写路径依键值而
异,「这个键落在哪张表」只有读代码才说得清;规范方法按值加特例,也让此后任何新
键都要先确认自己会不会被拦截。
本次把插件配置整条链拆出,形状与本分支日志等级那条链一致:
- SystemConfigOper 整体回退到官方实现,与 f70d7c141 逐字节相同,对所有键一视同仁。
- 配置端口改按实例 ID 寻址:PluginStorage 新增 read_config / write_config /
async_write_config / delete_config,PluginConfigStore 去掉 key_prefix 与 _key,
不再有任何字符串键经过;plugin_exists 存在性规则、空键过滤与 force 语义不变。
- PluginInstanceOper 补齐读取与异步写入原语 get_config_data /
async_save_config_data,同步与异步共用同一份落库决策,避免两条路径对「值未变化
不写」和「建行用哪个源插件」各自分叉。
- _PluginBase 的 get_config / update_config 直连 PluginInstanceOper,方法名、签名、
返回与 docstring 不变;self.systemconfig 保留,插件读 SystemConfigKey 枚举值仍
然合法,插件公开面没有扩大。
插件直接用 SystemConfig 存取自身配置不予支持。它本就不是封装过的插件配置通道,
为它设计兼容或加守卫拦截,等于再把「插件」塞回通用存储里——那正是本次要拆掉的东
西。拆开后 plugin.<ID> 只是一个与插件无关的普通 systemconfig 键:迁移已经把旧的
plugin.* 行搬进插件实例表,读它拿到 None,写它会新增一条谁也不读的 systemconfig
记录,插件配置通道既不读也不写它,两边不会再有任何交叉。
代价是读取从内存快照变成一次按实例 ID 的主键查询。调用点都不在热路径上:宿主侧
只有插件启动/重载、配置表单接口与分身创建三处,插件侧 get_config() 惯例在
init_plugin 里取一次。写入侧没有变化,本来就是一次事务。
回归防线:新增用例断言 SystemConfigOper 对 plugin. 前缀没有任何特殊行为——写进去
就是一行普通 systemconfig 记录,读出来就是刚写的值,不会被路由到插件实例表。
兼容层零改动,三个 alembic 迁移一行未改。
|
2026-09-13 01:41:57 -04:00 |
|
jxxghp
|
8072b7d78f
|
Refactor application architecture and compatibility boundaries
|
2026-09-13 12:53:00 +08:00 |
|
jxxghp
|
990e3ac3ae
|
fix(module): enhance documentation for transfer plan checkpoint method parameters
|
2026-09-13 12:38:20 +08:00 |
|
jxxghp
|
765b185d42
|
fix(module): add preview parameter to transfer plan checkpoint method
|
2026-09-13 12:33:50 +08:00 |
|
Aqr-K
|
e1b961b88e
|
fix(log): 回调换实例重绑时从原始回调重包
防止包装链随重载次数无限增长的幂等守卫只判断「是否已被包装」,没判断「是不是
为同一个实例包装的」。已为实例 A 包装的回调再为实例 B 包装时,外层先绑定 B,
调用旧包装器后内层又绑回 A,原始回调仍在 A 的上下文中执行,B 的日志按 A 的
覆盖等级过滤,实例日志设置互相隔离的合同被破坏。插件的 `get_api`/`get_service`
返回同一份缓存声明、被多个分身依次注册即可触发。
改为在包装标记里一并记住最内层的原始回调,换实例重绑时剥回原始回调重新包装,
同实例重复包装仍返回原对象。标记值用私有 NamedTuple 承载并以 `isinstance` 校验,
`Mock` 之类会为任意属性名凭空造值的回调才不会让重绑取到与包装无关的垃圾。
|
2026-09-13 00:14:56 -04:00 |
|
Aqr-K
|
3eee49659d
|
fix(plugin): 旧实例键回滚往返新增的分身要能合并进独立表
`PluginInstances` 旧键刻意保留作回滚依据、从不清理,旧版本只认它,因此它在
迁移之后仍可能长出新条目或被改写。原判据是「一条一次性的永久标记」加「整表
是否为空」:标记落下且表非空之后,回滚到旧版本新建的分身会被永久跳过,保留
旧键作回滚依据的承诺随之落空。两个条件都表达不出「旧载荷相对已导入内容有没有
新增或变化」。
改为按条目记住导入时的内容指纹(`PluginInstancesImported` 的载荷从布尔改为
`{实例ID: 摘要}`):指纹对得上就跳过,独立表里那行用户怎么改都不会被旧副本盖
回去;指纹对不上说明旧版本改写过,合并;指纹没记过且表里也没有该行说明旧版本
新增过,导入;指纹没记过但表里已有该行(alembic 刚搬过去的那一批)只认领指纹
不覆盖。指纹取自原始载荷而非模型 dump,模型字段将来增减才不会让全部指纹一起
失配、把用户改动整批盖回去。指纹表与旧键内容对齐后无变化的启动不再产生写入,
也不额外查表。
|
2026-09-13 00:14:47 -04:00 |
|
jxxghp
|
9ba513debc
|
fix(classification): initialize defaults in fresh v3 environments
|
2026-09-13 11:31:54 +08:00 |
|
jxxghp
|
5f050f35b6
|
fix(jellyfin): fallback when collection type is missing
|
2026-09-13 11:11:40 +08:00 |
|
jxxghp
|
2d446e0f57
|
fix: 修复更新重启工作目录
|
2026-09-13 08:20:40 +08:00 |
|
Aqr-K
|
617179b560
|
test(plugin): 为日志等级路由补真实路由表解析防遮蔽回归测试
pluginloglevel.router 与 plugin.router 共享 /plugin 前缀且后者先注册、含
GET/PUT/DELETE /{plugin_id} 通配路由;现有端点测试均直接调用函数、绕开路由
匹配,未来在 plugin.py 新增两段式或三段式路由可能悄悄遮蔽三条日志等级路由而
测试全绿。新增测试用生产同款组合根装配真实 FastAPI 应用,复用既有的
effective_route_contexts 展平方式按真实注册顺序解析三条 URL,断言命中
pluginloglevel 端点而非 plugin.py 的通配端点,失败时报出具体抢先命中的路由。
|
2026-09-12 20:14:15 -04:00 |
|
Aqr-K
|
d6509f092c
|
chore(plugin): 技能表目录登记补进生成脚本并补迁移往返验证
技能文档 skills/database-operation/SKILL.md 的核心表清单是
scripts/generate_agent_skill_docs.py 里 DATABASE_TABLE_GUIDES 的生成物,
前面两笔改动却是手改产物登记 plugininstance,任何人重跑生成器都会把它弄丢。
把条目补进字典,再用生成器重出该文档。
同时补上 agentinvocation:官方 v3 已有该表但字典里没有,生成器因此直接抛
ValueError,不补就根本跑不起来。它的说明照抄文档里现有的那份手写文案,
避免登记动作反而把已有描述改瘦。
迁移测试原本只按单个 revision 直接调 upgrade(),绕过了 Alembic 自己的版本
解析与记账,链接错的 down_revision、少写的 downgrade、重复升级时的重复建表
都测不出来。新增用例改走 alembic.command,在落盘的临时库上从官方 head
b2d4f6a8c1e3 升到链尾 487f7e681955 再降回去,验证配置与描述符确实落到
plugininstance、旧 plugin.* 键就地移除而 PluginInstances 键按回滚依据保留。
|
2026-09-12 19:48:57 -04:00 |
|
jxxghp
|
2edf20433a
|
test: update backup filename expectations for v3.0.1
|
2026-09-13 07:18:12 +08:00 |
|
jxxghp
|
daf8096430
|
chore: bump moviepilot version to v3.0.1
|
2026-09-13 07:08:35 +08:00 |
|
Aqr-K
|
e47d7defe7
|
feat(plugin): 插件本体与分身可各自设置独立日志等级
全局日志等级是一个开关,调试单个插件时只能整体下调。一旦下调,被调试插件那几行
日志会淹没在其他几十个插件与宿主自身的 DEBUG 输出里,找不出来;不下调又什么都
看不见。插件实例数量只会继续增长,这个矛盾不会自己消失。
因此把等级下放到实例:plugininstance 行加 log_level / log_expires_at 两列,本体与
分身共用同一张表、同一套语义。等级落在实例自己那一行而不是另起一张按实例 ID 索引
的表——它和业务参数一样是用户按实例设置的东西,同一个生命周期,实例被删时应当随行
一起消失。清除覆盖后若本体行只剩一对身份列,整行按 carries_only_identity 回收,与
清空业务参数同一规则。
覆盖带失效时间,因为它是调试设置不是长期配置:开了 DEBUG 忘记关,下次谁也想不起
某个插件为什么一直在刷日志。过期判定在读取时惰性执行并就地清理,不另起后台线程去
扫一张最多几十条的表。expires_at 在写入侧先归一到 UTC 再分发给缓存与落盘两处:客户端
提交的时间可能不带时区,两处各按进程时区折算一次,就会与读取口返回的 UTC 值差出一个
时区,表现为「提交的失效时刻和读回来的对不上」。
运行期用 ContextVar 在宿主自己控制的四类调用点绑定当前实例——构造与 init_plugin、
事件处理器、定时服务回调、插件声明的 HTTP 端点——而不是沿用 logger() 已有的栈帧内省。
内省认的是栈顶的模块与类,插件通过宿主公共方法转发调用时栈顶是宿主而不是发起调用的
插件,会把日志记到错误的来源上;分身更甚:分身共享源码,类的 __qualname__ 保持源类名
不变,内省根本分不出是哪一个分身在打日志。内省结果继续只用于文件路由,不参与等级判定。
等级过滤必须排在全局等级判定之前。官方现状是先按全局等级短路、之后才做内省,先短路
就会把实例调低的等级挡在门外,后面再怎么识别来源都看不到这条日志。
回调在注册时被捕获、稍后才由调度器或 FastAPI 调用,那时已经不在任何绑定作用域内,
故这两处改用 wrap_for_plugin_instance 把绑定包进回调自身;同一实例重复包装直接返回
原对象,避免插件缓存声明时包装链随重载次数无限增长。
进程内覆盖表按实例 ID 常驻,删分身时必须一并清掉:只删库里那一行的话,同一进程内用
相同后缀重建的分身会继承上一个分身的等级,界面显示「跟随全局」而实际仍按旧等级输出。
进程重启后反向从库预热缓存。
迁移链在 F1 之后追加:c4e1a7b9d2f6(3.0.35)-> 487f7e681955(3.0.36 加两列)。
顺带补了 agent 策略里缺失的 media.classification.policy.get 的 template 字段说明:
少了它,api_mcp_schema.json 与技能文档的两个生成脚本都跑不起来。
|
2026-09-12 19:05:05 -04:00 |
|
jxxghp
|
fcce6ac2bf
|
Merge pull request #6661 from kosmo888/fix/scraping-douban-image-referer
|
2026-09-13 06:34:22 +08:00 |
|
Aqr-K
|
4dbb8b8204
|
feat(plugin): 插件配置与实例描述符迁入独立表
插件配置此前寄存在 systemconfig 的 plugin.<实例ID> 单键下,实例描述符则整份挤在
PluginInstances 这一个 JSON 键里,两者都不成立:
- plugin.<ID> 是裸字符串 key,而仓库规则本身禁止用裸字符串做 SystemConfig key,
只允许先定义 SystemConfigKey 枚举项;插件 ID 由用户安装决定,永远枚举不出常量。
条目数随安装量增长,混在系统设置表里会把主程序自己的设置项淹掉。
- 那个键存的其实是实例 ID,表里没有任何一列说得出它属于哪个插件,想列出某个插件
的全部实例配置只能靠字符串前缀去猜。
- 实例描述符整份读出再整份写回,改一个分身要重写全部分身。
改为 plugininstance 一实例一行:instance_id 与 source_plugin_id 构成身份,本体与
分身由两者是否相等派生而不设模式列——模式列会是这个等式的冗余副本,两者一旦失步
同一行就会在不同读取口被判成不同角色。展示信息与业务参数同存一行,属于同一个
生命周期,分表只会让建分身、删分身退化成两张表之间的协调问题。
读写路由落在 SystemConfigOper.get/set/delete,而不是在各个调用方各改一处:第三方
插件可能直接用 self.systemconfig.get("plugin.xxx") 读写自己的配置,只改
PluginConfigStore 与 _PluginBase.get_config/update_config 必然漏掉它们。路由只做
前缀识别,插入、更新与空本体行回收都委托 PluginInstanceOper,不在配置层重抄一遍。
PluginInstances 旧键迁移后不删,留作回滚依据,并以
SystemConfigKey.PluginInstancesImported 标志防止重复导入;判据不能是「表当前为空」,
否则用户把分身全部删光后,下次启动会把它们整批导回来。
迁移链:b2d4f6a8c1e3 -> 281965691a20(3.0.34 建表并搬描述符)
-> c4e1a7b9d2f6(3.0.35 加 config_data 并搬 plugin.* 配置)。
依赖基线与启动模块数随两个新模块重算,架构文档与数据库技能表目录同步登记新表。
|
2026-09-12 17:39:36 -04:00 |
|
kosmo888
|
3ea745e058
|
fix(scraping): supply douban referer to avoid 418 anti-hotlinking on image scraping
|
2026-09-13 04:06:38 +08:00 |
|
jxxghp
|
f70d7c1410
|
feat(agent): stream non-verbose tool progress
|
2026-09-13 00:22:58 +08:00 |
|
jxxghp
|
0c28ed82da
|
fix(docker): refresh vulnerable runtime packages
|
2026-09-12 23:18:00 +08:00 |
|
jxxghp
|
ef51cf6da4
|
fix(agent): honor verbose mode in WebAgent tool display
|
2026-09-12 23:09:48 +08:00 |
|
jxxghp
|
aae90b1cdb
|
chore(architecture): sync reduced mypy baseline
|
2026-09-12 21:43:55 +08:00 |
|
jxxghp
|
527d8b638d
|
Merge pull request #6659 from jxxghp/fix/issue-6628-authenticated-site-refresh
fix(site): report unauthenticated userdata refresh failures
|
2026-09-12 21:34:12 +08:00 |
|
jxxghp
|
f6c647ce5b
|
chore(architecture): keep subscription query within budget
|
2026-09-12 21:29:55 +08:00 |
|
InfinityPacer
|
4491610adb
|
修复插件来源仲裁与数据库备份 review 问题
合并 PR #6658。业务相关检查已通过;剩余失败为 PR-Agent 外部 API 日限额与上游既有复杂度 ratchet,不属于本次改动。
|
2026-09-12 21:22:01 +08:00 |
|
jxxghp
|
4d4327e25a
|
fix(site): report unauthenticated userdata refresh failures
|
2026-09-12 21:19:58 +08:00 |
|
jxxghp
|
ee4dcd9d89
|
docs: sync architecture dependency metrics
|
2026-09-12 21:14:45 +08:00 |
|
jxxghp
|
e87b2d9ea9
|
chore: update architecture dependency baseline
|
2026-09-12 21:05:27 +08:00 |
|
jxxghp
|
1ba4d087c5
|
fix: scope subscription maintenance by media type
|
2026-09-12 20:56:05 +08:00 |
|
jxxghp
|
c0158b1f63
|
fix(plugin): isolate startup recovery failures
|
2026-09-12 20:39:19 +08:00 |
|
InfinityPacer
|
b3f748ffa8
|
feat(database): support plugin database backup
支持插件 SQLite 数据库备份并校验 PostgreSQL schema 权限
|
2026-09-12 20:22:33 +08:00 |
|
InfinityPacer
|
999f9cf963
|
fix(database): align backup store protocol
|
2026-09-12 20:12:27 +08:00 |
|
InfinityPacer
|
427271b1ac
|
chore(architecture): update database backup dependency baseline
|
2026-09-12 20:04:03 +08:00 |
|
InfinityPacer
|
1ec7005b51
|
feat(database): back up plugin sqlite databases
|
2026-09-12 19:53:38 +08:00 |
|
InfinityPacer
|
20bf902046
|
Merge pull request #6656 from InfinityPacer/pr/plugin-source-binding-v3
修复 V3 插件本地来源优先级与更新索引刷新
|
2026-09-12 19:52:08 +08:00 |
|
InfinityPacer
|
ad94e8de2a
|
chore(architecture): update plugin sync dependency baseline
|
2026-09-12 19:31:41 +08:00 |
|
InfinityPacer
|
d6c1111930
|
test(plugin): align local source projection contract
|
2026-09-12 19:20:55 +08:00 |
|
jxxghp
|
ba0b737783
|
fix(site): use list default for seeding info
|
2026-09-12 19:20:48 +08:00 |
|
InfinityPacer
|
814da86028
|
fix(plugin): avoid refreshing all repositories on update
|
2026-09-12 19:11:08 +08:00 |
|
InfinityPacer
|
747f9f921f
|
fix(plugin): prioritize local plugin sources
|
2026-09-12 19:11:08 +08:00 |
|
jxxghp
|
a13a201ae9
|
fix(docker): refresh vulnerable libevent package
|
2026-09-12 18:59:44 +08:00 |
|
jxxghp
|
7d1f2eb10e
|
docs(architecture): refresh startup module baseline
|
2026-09-12 18:37:56 +08:00 |
|
jxxghp
|
4192585969
|
fix(classification): satisfy type and module contracts
|
2026-09-12 18:28:31 +08:00 |
|
jxxghp
|
761d02ba68
|
fix(classification): satisfy architecture complexity ratchets
|
2026-09-12 18:18:13 +08:00 |
|
jxxghp
|
7d4e4f7658
|
docs(architecture): refresh dependency edge metrics
|
2026-09-12 18:00:09 +08:00 |
|