jxxghp
61179abada
fix(plex): retry paged media library reads
2026-09-25 12:04:10 +08:00
jxxghp
44f4656fc6
chore(architecture): sync network probe startup counts
2026-09-24 13:35:30 +08:00
jxxghp
419423de74
chore(architecture): record websocket probe thread owner
2026-09-24 13:11:20 +08:00
jxxghp
7abc420c90
chore(architecture): refresh network probe dependency baseline
2026-09-24 12:57:59 +08:00
jxxghp
027b4fe75f
fix(system): preserve network probe service contracts
2026-09-24 12:41:17 +08:00
jxxghp
bae7445011
Update subtitle transfer dependency baseline
2026-09-24 07:54:19 +08:00
jxxghp
bbaec9d6b3
fix: preserve v3 architecture complexity budget
2026-09-23 18:49:00 +08:00
jxxghp
58bb4961af
fix: bound downloader connection retries for v3.0.8
2026-09-23 18:13:39 +08:00
jxxghp
05a53657a6
fix(indexer): parse PterClub seeding stats
2026-09-23 16:15:19 +08:00
jxxghp
1422f41c6c
fix(indexer): paginate M-Team seeding statistics
2026-09-23 15:45:52 +08:00
InfinityPacer
19e062c178
feat(plugin): attribute free-threaded GIL fallback to plugins ( #6767 )
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-23 13:12:02 +08:00
InfinityPacer
0bb033afe7
feat(plugin): preflight plugin dependencies on free-threaded runtime ( #6766 )
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-23 12:53:46 +08:00
InfinityPacer
3cef2149d0
fix(plugin): read the runtime compatibility gate from the declared snapshot ( #6761 )
...
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
2026-09-23 01:44:45 +08:00
InfinityPacer
0238351071
fix(plugin): v3t 下不再隐藏不兼容插件,改为提示不支持 ( #6760 )
...
* feat(plugin): surface v3t incompatibility instead of hiding plugins
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* chore(architecture): refresh dependency baseline after plugin gate split
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* fix(plugin): keep runtime-incompatible plugins out of startup sync
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* fix(plugin): annotate runtime compatibility ports without bare dict
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
2026-09-23 00:35:20 +08:00
ranzhigg
b134840102
fix(network): retry proxied HTTPS with TLS 1.2 ( #6758 )
...
* fix(network): retry proxied HTTPS with TLS 1.2
* test: refresh egress architecture fingerprints
* chore: refresh host architecture baseline
* fix(network): satisfy mypy ratchet for TLS fallback
---------
Co-authored-by: ranzhigg <51039935+ranzhigg@users.noreply.github.com >
2026-09-22 19:53:23 +08:00
moviepilot-codex[bot]
3c516ddbe1
chore: refresh architecture dependency baseline
2026-09-21 18:45:08 +08:00
moviepilot-codex[bot]
d96f00113c
feat: add GitHub Token device authorization
2026-09-21 18:30:15 +08:00
moviepilot-codex[bot]
7ffb626620
chore(architecture): update dependency baseline
2026-09-21 09:09:00 +08:00
jxxghp
f14eddfa03
fix(cache): type async Redis loop registries
2026-09-19 18:36:16 +08:00
freeman
542f893123
fix(plugins): 启动时自愈被旧版本实现遮蔽的插件安装包根 ( #6718 )
2026-09-17 15:57:48 +08:00
jxxghp
2f952c371e
fix(metainfo): type subtitle matcher inputs
2026-09-17 12:51:53 +08:00
jxxghp
4f716c442c
chore(architecture): record ruff cleanup
2026-09-16 18:51:54 +08:00
jxxghp
67cd412d82
chore(architecture): refresh host dependency baseline
2026-09-16 18:42:58 +08:00
jxxghp
3eb339b8e0
feat(agent): unify memory retrieval and activity history
2026-09-16 18:24:30 +08:00
jxxghp
11eea66d27
fix(architecture): 移除整理任务兼容时钟门面
2026-09-16 07:27:20 +08:00
jxxghp
9f75f54b74
fix(architecture): 清理重构门禁诊断
2026-09-16 07:17:07 +08:00
jxxghp
0afc5e2349
fix(architecture): 同步模块迁移门禁引用
2026-09-16 07:01:10 +08:00
jxxghp
b99b4fe2c3
chore(architecture): 同步模块路径与质量门禁
2026-09-16 00:12:16 +08:00
jxxghp
4ec8d4c961
chore(architecture): refresh dependency baseline
2026-09-15 18:26:49 +08:00
jxxghp
71fffde878
feat(agent): 完善系统设置机器可读合同
2026-09-15 13:11:29 +08:00
jxxghp
880cef2c88
fix(config): 使用公共日志模块记录配置恢复
2026-09-15 11:43:12 +08:00
jxxghp
4a777f1410
fix: 补齐 Bangumi 客户端类型标注
2026-09-15 07:53:44 +08:00
Aqr-K
61aa3cd649
refactor(sdk): 插件契约基类迁入 SDK 并由 Compat 承接旧包根符号 ( #6701 )
2026-09-15 07:01:00 +08:00
jxxghp
ebbc0d4520
chore(architecture): refresh dependency baseline
2026-09-14 19:47:03 +08:00
jxxghp
4df910990f
test(architecture): refresh startup module baseline
2026-09-14 13:55:45 +08:00
jxxghp
4af54fcf5f
test(architecture): refresh dependency baseline
2026-09-14 13:35:07 +08:00
jxxghp
6d82f44fc8
fix(music): split core recognition and organization optimizations ( #6686 )
2026-09-14 13:04:58 +08:00
jxxghp
6f9ad991d5
chore(architecture): sync host baseline metrics
2026-09-14 08:20:11 +08:00
Aqr-K
dd4ae3e8d5
refactor(plugin): 移除已无调用者的物理分身源码改写器 ( #6683 )
...
物理分身是早期实现:复制整个插件目录,再用字符串替换改写副本源码里的类名、
plugin_config_prefix 和联邦构建产物。虚拟实例接管后,分身不再复制目录,
由装载器改写类身份、按实例 ID 隔离配置与数据,这套改写器随之失去调用者。
求证依据(全仓 git grep,覆盖 app/、tests/、scripts/、docs/、skills/):
- PluginPackageManager.clone() 无任何生产调用者。分身的唯一生产路径是
POST /api/v1/plugin/clone/{plugin_id} -> PluginManager.clone_plugin()
-> PluginCloneService.clone(),后者只写 PluginInstance 记录与隔离配置,
不碰包适配器。clone() 也没有经 PluginSystemServices 暴露出去。
- clone() 的四个私有实现 _modify_plugin_files / _modify_python_file /
_modify_federation_files / _rename_federation_assets,消费者只有 clone()
自身与 PluginSystemServices 的同名透传。
- PluginSystemServices 的四个透传,消费者只有 PluginManager 的 _modify_* shim。
- PluginManager 的四个 shim 无任何调用者。动态可达性已单独排查:
全仓没有 getattr/字符串反射指向这些名字;app/runtime/compat/manifest.py
不登记它们的别名(只有 app.core.plugin -> 本模块的模块级映射);
app/sdk/ 不再导出;PluginManager 与 PluginPackageManager 都没有
__getattr__ 兜底,属性不存在即 AttributeError;官方插件基线
official-plugin-baseline.json 零命中。
- @observe_compat_facade("PluginManager") 只包装类上已存在的方法,
不会凭空合成属性,因此 shim 删除后 enforce_facade 再也匹配不到
notices.py 里那四条 key,登记随之成为不可达数据,一并删除。
替代路径:这四条弃用声明当初承诺的替代目标是
get_plugin_system().package._modify_*(),那是一次「门面搬到适配器」的
重定位登记,本次连同能力一起下线;分身能力本身的替代路径是虚拟实例
PluginCloneService.clone(),它已在生产链路上,见
docs/v2-to-v3-overview.md §3.6「不复制插件源码,也能保持各实例配置隔离」。
既有磁盘上的旧物理分身不受影响:卸载路径读取 is_clone 属性并调用
remove_plugin_package() 的逻辑原样保留,只是不再产生新的物理分身。
这是对已公告弃用 API(DeprecationStage.SILENT,since v3.0.0)的正式移除。
连带改动:
- package.py 的 import re 仅服务于 _modify_python_file,同步移除;模块
docstring 去掉「分身处理」。
- system.py 的 typing.cast 仅服务于被删透传,同步移除。
- tests/test_plugin_package_manager.py::test_clone_rewrites_python_and_federation_assets
是这套改写器的唯一测试,且只覆盖已无调用者的路径,随实现一并删除。
(删的是测试函数不是测试文件,tests/run.py 的分片装箱不变。)
- mypy 低水位随实现下降:app/runtime/extensions/plugin/manager.py 的
assignment 8->4(四个 shim 的 version/icon 参数 str = None)、
no-untyped-def 12->11(_rename_federation_assets 缺返回标注),
fixture 与 docs/refactor/optimization-checklist.md 的全量 mypy 计数
9,371 -> 9,366 同步更新。依赖、复杂度、ruff、并发等其余基线无变化。
Co-authored-by: jxxghp <jxxghp@gmail.com >
2026-09-14 07:19:46 +08:00
Aqr-K
5e232ca14d
fix(plugin): 安装记录大小写不敏感查询、游标物化,site 端点改从 Application 取 ( #6682 )
...
* fix(plugin): 安装 journal 按大小写不敏感列出事务记录
create 用 func.lower 判定同一物理插件并据此拒绝重复占位,list 却还是等值过滤。
判据分叉后,恢复流程查不到那条被 create 认定为未收尾的 journal,会认为没有待恢复
事务,而新事务又永远被同一行挡住。list 改用与 create 相同的 func.lower 判据。
* fix(plugin): 批量读插件身份时在事务内物化游标
list_by_plugin_ids 无会话调用时由组合根另开短事务,会话在 lambda 返回后立即关闭,
外层再 list() 消费惰性游标会撞上 "identity map is no longer valid",一行都读不到。
补上 .all(),让行在事务内取完。
* refactor(api): site 端点从 Application 取插件路由刷新
register_plugin_api 的唯一拥有者是 app.application.plugin.routes,
dependencies/plugin.py、scheduler/reconcile.py 与 initializers/plugins.py 都已从那里
取用,只剩 site 端点还在向 plugin 端点横向借。改为同一来源,并加门禁锁住这条判据。
依赖基线相应下降一条边(8650 -> 8649:site 不再到达 app.api.endpoints 与
app.api.endpoints.plugin,改为到达 app.application.plugin.routes),mypy 低水位同步
下降一条 attr-defined,两处文档数字随之更新。
---------
Co-authored-by: jxxghp <jxxghp@gmail.com >
2026-09-14 07:18:50 +08:00
Aqr-K
5c01cdddb3
fix(plugin): 插件安装改为暂存后原子换入,避免下载失败删掉已装插件 ( #6678 )
2026-09-14 07:00:50 +08:00
Aqr-K
57fb96fc3c
feat(plugin): 分身后缀可留空自动分配,并支持按后缀恢复已停用的分身 ( #6673 )
2026-09-14 07:00:31 +08:00
Aqr-K
5fd04505c1
feat(plugin): 分身彻底清理,并按包含性校验收口插件数据目录解析 ( #6671 )
2026-09-13 21:05:04 +08:00
Aqr-K
af3c78c7dc
chore(architecture): 固化 Ruff 低水位至 519 ( #6669 )
2026-09-13 19:42:45 +08:00
Aqr-K
d44480d739
Merge pull request #6666 from Aqr-K/feat/plugin-instance-target-enablement
...
feat(plugin): 插件实例默认调用目标与启停,未指定实例时不再兜底取第一个
2026-09-13 16:37:27 +08:00
jxxghp
30d6d9e146
chore(architecture): align complexity baseline with formatting
2026-09-13 14:55:22 +08:00
jxxghp
c60949ffff
Merge branch 'v3' into feat/plugin-instance-config-logging
2026-09-13 14:30:42 +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
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