@menghuan1918/dsh-apollo 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/docs/DEVELOPMENT.md +18 -13
- package/package.json +3 -3
- package/src/admission.js +36 -0
- package/src/index.js +3 -1
- package/src/migrate.js +54 -14
package/README.md
CHANGED
|
@@ -86,13 +86,13 @@ flowchart TB
|
|
|
86
86
|
|
|
87
87
|
```sh
|
|
88
88
|
# npm 安装(发布后)
|
|
89
|
-
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.
|
|
89
|
+
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.2
|
|
90
90
|
|
|
91
91
|
# 或从 GitHub main 源码安装(备选)
|
|
92
92
|
dsh plugin --profile <profile> add github:Menghuan1918/dsh-apollo
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
> **发布状态(诚实说明)**:Apollo `0.5.0` 已发布,`dsh-better-subagent@0.1.0` / `dsh-better-compact@0.1.
|
|
95
|
+
> **发布状态(诚实说明)**:Apollo `0.5.0` 已发布,`dsh-better-subagent@0.1.0` / `dsh-better-compact@0.1.1` 作为其精确依赖已可从 npm 取得。当前版本 `0.5.2` 是 compact 0.1.1 的设置表单 schema 修复版;本仓库 0.5.1 的验证使用本地 tarball `npm install --no-save`,提交的 manifest 中**没有** `file:` / `link:` / Git 说明符。
|
|
96
96
|
|
|
97
97
|
安装、升级或换包都会改变运行的代码,必须重启对应 profile 的 DSH 进程;只刷新网页不够。目标行、子代理行与压缩行由 Apollo 的 bundle patch 插入,不需要再单独 `add` 三个子包。
|
|
98
98
|
|
|
@@ -102,14 +102,14 @@ dsh plugin --profile <profile> add github:Menghuan1918/dsh-apollo
|
|
|
102
102
|
|
|
103
103
|
```sh
|
|
104
104
|
dsh plugin --profile <profile> remove dsh-apollo
|
|
105
|
-
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.
|
|
105
|
+
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.2
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
> `dsh-apollo` 只是旧入口名;unscoped 的 `dsh-apollo` 已被其他项目占用,不要从 npm 安装它。
|
|
109
109
|
|
|
110
110
|
## 从 0.4.x 升级
|
|
111
111
|
|
|
112
|
-
0.5.0 把子代理与压缩能力移出 Apollo,0.5.1 修复旧 profile 行的 `name` guard
|
|
112
|
+
0.5.0 把子代理与压缩能力移出 Apollo,0.5.1 修复旧 profile 行的 `name` guard 迁移缺口;0.5.2 依赖 compact 0.1.1,修复 Web 设置表单的 schema rehydrate。旧 profile 不需要手工重填配置:Apollo 启动后在 settings/loader 可用时运行一次**幂等迁移**([src/migrate.js](src/migrate.js))。
|
|
113
113
|
|
|
114
114
|
> **0.5.1 迁移修复**:如果旧 profile patch 的 `apollo-skills` 覆盖还带历史名称 `name: dsh-apollo`,DSH 会把 `name` 当 guard 并跳过该覆盖,导致有效配置看起来仍是默认值。0.5.1 从 `configEditor.configuration().override` 恢复这些显式值(含 `false` / `0` / `""` / `[]`),再合并到迁移来源;被跳过的旧预设覆盖(`preset-eng` / `preset-eng-ptc`)同样处理。无需手工修改旧行;升级后重启 profile 即可。
|
|
115
115
|
|
|
@@ -171,7 +171,7 @@ flowchart LR
|
|
|
171
171
|
dsh plugin --profile <profile> add @menghuan1918/dsh-better-subagent@0.1.0
|
|
172
172
|
|
|
173
173
|
# 只装压缩
|
|
174
|
-
dsh plugin --profile <profile> add dsh-better-compact@0.1.
|
|
174
|
+
dsh plugin --profile <profile> add dsh-better-compact@0.1.1
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
独立安装时的行、页面和提示词与 Apollo 集成完全相同;行 id/name 也是同一组稳定值。区别只在**由谁插入这些行**:Apollo 的 bundle patch 自己携带同样的行,因为 DSH 不会自动应用传递依赖的 bundle patch。
|
|
@@ -226,7 +226,7 @@ dsh plugin --profile <profile> remove dsh-better-compact
|
|
|
226
226
|
- `package.json` 的 `files` 只列入 `docs/DEVELOPMENT.md`,并额外用 [.npmignore](.npmignore) 排除 `docs/specs/`;
|
|
227
227
|
- `tests/packaging.test.mjs` 直接运行 `npm pack --dry-run --json`,断言发布清单没有 Specs、测试、脚本、快照或 tarball。
|
|
228
228
|
|
|
229
|
-
发布顺序:**先发布并验证两个独立包(`@menghuan1918/dsh-better-subagent@0.1.0`、`dsh-better-compact@0.1.
|
|
229
|
+
发布顺序:**先发布并验证两个独立包(`@menghuan1918/dsh-better-subagent@0.1.0`、`dsh-better-compact@0.1.1`),再发布 Apollo 0.5.2**。两个 0.1.0 已随 0.5.0 发布;0.5.1 可只发布本包。Apollo 的精确依赖指向尚不存在的版本时,`npm install` 会失败;不要用开发 `file:`/`link:` 依赖发布。两个子仓各自有 trusted publishing workflow;Apollo 的 [release workflow](.github/workflows/release.yml) 只发布本包。
|
|
230
230
|
|
|
231
231
|
## 验证状态(诚实记录)
|
|
232
232
|
|
|
@@ -239,7 +239,7 @@ dsh plugin --profile <profile> remove dsh-better-compact
|
|
|
239
239
|
|
|
240
240
|
**未验证 / 明确限制**:
|
|
241
241
|
|
|
242
|
-
-
|
|
242
|
+
- 子包 `@menghuan1918/dsh-better-subagent@0.1.0` 与 `dsh-better-compact@0.1.1` 已可从 npm 取得。
|
|
243
243
|
- 未修改或重启用户当前运行的 profile,未验证当前 GUI(`http://127.0.0.1:3384`)的设置页/卡片;S3 视觉设置页的 GUI 验收归 S3/最终宿主验收。
|
|
244
244
|
- 未运行真实 Codex/Claude CLI 的真实模型回合(那属于两个子包自己的验证;Apollo 侧本轮只用脚本化适配器)。
|
|
245
245
|
- 真实模型摘要保真、缓存命中率与跨版本预设漂移仍需按实际环境复验。
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
面向维护者、集成者和需要排查装配问题的用户。用户安装与配置请看 [README](../README.md);本文保留 DSH 插件的实现细节、旧配置迁移、组合安装边界与验证方法。
|
|
4
4
|
|
|
5
|
-
当前实现版本:`0.5.
|
|
5
|
+
当前实现版本:`0.5.3`;npm 包名是 `@menghuan1918/dsh-apollo`。纯 ESM,无构建步骤;宿主浏览器半边是直接加载的闭包工厂。
|
|
6
6
|
|
|
7
7
|
## 目录
|
|
8
8
|
|
|
@@ -34,16 +34,15 @@
|
|
|
34
34
|
| 依赖 | 版本 | 所有权 |
|
|
35
35
|
|---|---|---|
|
|
36
36
|
| `dsh-better-goal` | `0.2.0` | 目标域 |
|
|
37
|
-
| `@menghuan1918/dsh-better-subagent` | `0.1.
|
|
38
|
-
| `dsh-better-compact` | `0.1.
|
|
37
|
+
| `@menghuan1918/dsh-better-subagent` | `0.1.1` | 子代理 CLI/等待/child guard/分档/设置页 |
|
|
38
|
+
| `dsh-better-compact` | `0.1.2` | 压缩 companion + engine + 设置页/诊断 |
|
|
39
39
|
| `@deepseek-ai/schemastery` | `~3.18.4` | Apollo 行 Config |
|
|
40
40
|
| `react` | peer | 宿主提供 |
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
正式安装从 npm registry 获取上述精确版本,不需要本地 tarball 或 link:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
45
|
npm install
|
|
46
|
-
npm install --no-save /path/to/menghuan1918-dsh-better-subagent-0.1.0.tgz /path/to/dsh-better-compact-0.1.0.tgz
|
|
47
46
|
```
|
|
48
47
|
|
|
49
48
|
发布顺序必须是先两个子包、后 Apollo(见[发布](#实现入口打包与发布))。
|
|
@@ -192,7 +191,7 @@ npm install --no-save /path/to/menghuan1918-dsh-better-subagent-0.1.0.tgz /path/
|
|
|
192
191
|
1. 有 Loader 时等待装配完成(`loader.await()`,有界);
|
|
193
192
|
2. 等待 `legacyImport`(旧 eng.json)完成;
|
|
194
193
|
3. 有界轮询 `settings.describe()`,直到 `dsh-better-subagent` 与 `dsh-better-compact` 两个命名空间都出现(默认 5s,50ms 间隔);
|
|
195
|
-
4. 子代理迁移 → 压缩迁移,各自写入后重读验证;
|
|
194
|
+
4. 子代理迁移 → 恢复 Apollo job 开关 → 压缩迁移,各自写入后重读验证;
|
|
196
195
|
5. 返回状态并记录日志(complete / pending / blocked / error)。
|
|
197
196
|
|
|
198
197
|
若目标命名空间一直不可读/不可写(例如双显式 bundle 导致写入被拒),日志明确要求重载 profile,迁移保持幂等,下次启动会再试;不宣告成功。迁移不删除旧值,也不创建迁移 sidecar。
|
|
@@ -205,6 +204,8 @@ npm install --no-save /path/to/menghuan1918-dsh-better-subagent-0.1.0.tgz /path/
|
|
|
205
204
|
|
|
206
205
|
**0.5.1 修复**:DSH 把 profile 覆盖行的 `name` 当 guard。旧 profile 若保留历史 `name: dsh-apollo`,Loader 会跳过该覆盖,`describe().value` 只剩默认值(例如用户显式 `subagents.eng: false` 会被看成默认 `true`)。迁移现在额外读取 `configEditor.configuration()` 中该行的 `override`,递归合并到有效配置之上:普通对象逐键合并,数组与所有标量(含 `false`/`0`/`""`/`[]`)整体覆盖。这样被跳过的显式值仍会迁移。`preset-eng` / `preset-eng-ptc` 的预设覆盖也按同样方式合并(`plugins` 数组整体替换),再读取原生 `compaction-basic`。
|
|
207
206
|
|
|
207
|
+
历史 name guard 同样会让仍活跃的 Apollo job `exitGuard` 静默回退到默认 false。现在迁移还会只把这个开关经 `settings.update` 恢复到 Apollo,并重读验证;不会激活其他已弃用字段。宿主 `describe().user` 会投影被跳过的旧覆盖,因此优先检查活动 Apollo entry 的 raw config:它已声明 `exitGuard` 时(尤其当前 scoped 行显式 false),不覆盖。child 目标仍按自己的 `user.childExitGuard` 存在性判断,不让两个开关互相覆盖。旧 unscoped 行保留,重复执行不重写。仅在子代理迁移完成/无需写入后恢复 job 开关,避免新 scoped 行遮蔽尚未导入的旧来源;写入拒绝为 pending,重读不一致为 error,均纳入顶层状态。
|
|
208
|
+
|
|
208
209
|
目标:`dsh-better-subagent` 的 `settings.describe()`:
|
|
209
210
|
|
|
210
211
|
- `target.user` 的存在性表示显式值(含 false/0/""/[]);
|
|
@@ -218,7 +219,7 @@ npm install --no-save /path/to/menghuan1918-dsh-better-subagent-0.1.0.tgz /path/
|
|
|
218
219
|
| `tiers.fast` / `tiers.quality` | 同名 | 目标该档已有任一显式字段 → 整档不混写;否则来源档与目标默认不同才写 |
|
|
219
220
|
| `subagents.eng` / `global` | 同名 | 目标缺字段且值不同才写;显式 false 是值 |
|
|
220
221
|
| `subagents.codex/claude.*` | 同名 | 逐叶补齐:enabled、executable、profile(仅 codex)、permissionMode、defaultModel、models(含顺序/effort 元数据) |
|
|
221
|
-
| `exitGuard` | `
|
|
222
|
+
| `exitGuard` | Apollo `exitGuard` + `childExitGuard` | 两份相同初值,随后独立配置;当前目标显式值(含 false)各自优先 |
|
|
222
223
|
| `trustedHosts` | `trustedHosts` | 非 volatile;目标 raw config 未声明且来源非空时用 `configEditor.edit` 写 |
|
|
223
224
|
|
|
224
225
|
写入:volatile 用 `settings.update(ns, patch, revision)`;非 volatile 用 target entry 的 `configEditor.edit`。`settings.update` 会触发 reconcile,可能替换目标 entry 对象,因此写 `trustedHosts` 前重新从 `entries()` 取目标 entry。写后重新 `describe()`/读 raw config 校验,任何字段不一致按 `error` 报告。
|
|
@@ -240,6 +241,10 @@ npm install --no-save /path/to/menghuan1918-dsh-better-subagent-0.1.0.tgz /path/
|
|
|
240
241
|
|
|
241
242
|
原生默认值不会变成目标显式值:只有来源行里显式存在的键才会被携带。压缩配置是 volatile 保存、引擎载入时冻结快照;迁移后的设置需要重载 profile 才会被运行中引擎采用(inspect 的 `requiresReload` 可观察)。
|
|
242
243
|
|
|
244
|
+
Apollo 在迁移挂载时先登记启动门禁:验证完成前,`agent/pre-step` 阻止任务步骤,`llm/stream` 同时阻止不经过 pre-step 的手动摘要调用。迁移 pending/blocked/error 不得按默认配置继续执行;应检查日志后修复来源或目标并重载。若本次迁移改变 compact 的载入快照,持久化验证完成后仍要求重载,重载后确认无差异才放行。普通后续设置保存不关闭已通过的启动门禁,仍按原有“当前快照继续、重载后应用新值”语义处理。
|
|
245
|
+
|
|
246
|
+
宿主行明确 `disabled: true` 时,跳过该增强的迁移,不将其缺少 settings namespace 误判为全宿主故障;活动行缺失 namespace 仍报 pending。子代理增强被禁用时保留尚未迁出的旧来源,并暂缓会遮蔽该来源的旧 job 开关恢复,待重新启用后再迁移;已生效的 Apollo job 配置不变。停用 compact 增强时仍需按卸载说明启用原生 `compaction-basic`,以恢复 `/compact`;启动门禁不替用户改写禁用选择。
|
|
247
|
+
|
|
243
248
|
### 迁移测试
|
|
244
249
|
|
|
245
250
|
- [tests/migrate.test.mjs](../tests/migrate.test.mjs):纯函数与 fake host 编排。覆盖显式 false/空值、目标优先(分档整档、models 空列表、保留方式二选一)、缺失来源、ambiguity、trustedHosts、写入拒绝、幂等、重读验证、有界等待。
|
|
@@ -308,10 +313,10 @@ DSH_PACKAGE_ROOT="/…/node_modules/@deepseek-ai/dsh" npm run prompts
|
|
|
308
313
|
### npm 安装
|
|
309
314
|
|
|
310
315
|
```sh
|
|
311
|
-
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.
|
|
316
|
+
dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.2
|
|
312
317
|
```
|
|
313
318
|
|
|
314
|
-
包发布后即可用此命令安装,并带入三个精确依赖、应用三份 bundle patch。安装后需要重启对应 profile 的 DSH 进程。0.5.0 已发布;0.5.1
|
|
319
|
+
包发布后即可用此命令安装,并带入三个精确依赖、应用三份 bundle patch。安装后需要重启对应 profile 的 DSH 进程。0.5.0 已发布;0.5.1 是迁移修复版本;0.5.2 依赖 compact 0.1.1,修复 Web 设置表单的 schema rehydrate。
|
|
315
320
|
|
|
316
321
|
### GitHub 源码安装
|
|
317
322
|
|
|
@@ -319,7 +324,7 @@ dsh plugin --profile <profile> add @menghuan1918/dsh-apollo@0.5.1
|
|
|
319
324
|
dsh plugin --profile <profile> add github:Menghuan1918/dsh-apollo
|
|
320
325
|
```
|
|
321
326
|
|
|
322
|
-
GitHub main 仍是源码安装选项。它同样按 `package.json`
|
|
327
|
+
GitHub main 仍是源码安装选项。它同样按 `package.json` 解析精确依赖;子包 0.1.0/0.1.1 在 registry 可取得前,源码安装会因依赖 404 失败。
|
|
323
328
|
|
|
324
329
|
### 本地 link 安装
|
|
325
330
|
|
|
@@ -363,9 +368,9 @@ dsh plugin --profile <profile> remove @menghuan1918/dsh-apollo
|
|
|
363
368
|
|
|
364
369
|
两个子仓和 Apollo 都用 GitHub Release 触发 `.github/workflows/release.yml`,通过 npm trusted publishing(OIDC)发布,仓库里不存 npm token。tag 必须是 `v<package.json 的 version>`,CI 会先校验再跑测试和 `npm publish --provenance`。
|
|
365
370
|
|
|
366
|
-
1. 先发布 `@menghuan1918/dsh-better-subagent@0.1.0` 与 `dsh-better-compact@0.1.
|
|
371
|
+
1. 先发布 `@menghuan1918/dsh-better-subagent@0.1.0` 与 `dsh-better-compact@0.1.1`(各自仓库的 Release);
|
|
367
372
|
2. 在官方 registry(`https://registry.npmjs.org/`)确认两个版本可取得、可安装;
|
|
368
|
-
3. 再把 Apollo 的精确依赖指向已发布版本,推 main 并发布 Apollo Release(0.5.0 已发布;本轮为 `v0.5.
|
|
373
|
+
3. 再把 Apollo 的精确依赖指向已发布版本,推 main 并发布 Apollo Release(0.5.0 已发布;本轮为 `v0.5.2`);
|
|
369
374
|
4. 子包版本可取得前,不要把指向它们的精确依赖推到 Apollo main,否则 `npm install` / GitHub 源码安装会 404。
|
|
370
375
|
|
|
371
376
|
## 测试与冒烟
|
|
@@ -424,7 +429,7 @@ DSH_PACKAGE_ROOT=/path/to/node_modules/@deepseek-ai/dsh node scripts/runtime-smo
|
|
|
424
429
|
- 本仓库不运行真实 Codex/Claude CLI;两个子包各自的 `cli-smoke` / runtime smoke 负责真实 CLI 生命周期。
|
|
425
430
|
- 真实模型摘要保真、缓存命中率、S3 可视化页面的 GUI 验收不在 Apollo 侧冒烟内。
|
|
426
431
|
- 未修改用户当前运行的 profile,未验证当前 GUI;当前 URL 以执行时 runtime context 为准。
|
|
427
|
-
- 单元测试通过不等于 registry
|
|
432
|
+
- 单元测试通过不等于 registry 发布/安装路径通过;子包 0.1.0/0.1.1 已发布;registry 安装路径已用 fresh cache 验证。
|
|
428
433
|
|
|
429
434
|
## 历史兼容
|
|
430
435
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@menghuan1918/dsh-apollo",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "DSH plugin bundle: workflow skills, engineering presets, independent better-goal / better-subagent / better-compact integration, and a minimal job exit guard. Pure ESM, no build step.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@deepseek-ai/schemastery": "~3.18.4",
|
|
57
|
-
"@menghuan1918/dsh-better-subagent": "0.1.
|
|
58
|
-
"dsh-better-compact": "0.1.
|
|
57
|
+
"@menghuan1918/dsh-better-subagent": "0.1.1",
|
|
58
|
+
"dsh-better-compact": "0.1.2",
|
|
59
59
|
"dsh-better-goal": "0.2.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
package/src/admission.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
|
+
|
|
3
|
+
/** Do not run a turn or manual summary using pre-migration defaults. */
|
|
4
|
+
export function mountMigrationAdmission(ctx) {
|
|
5
|
+
let report = { status: 'pending' }
|
|
6
|
+
let requiresReload = false
|
|
7
|
+
const assertReady = () => {
|
|
8
|
+
if (report.status !== 'complete') {
|
|
9
|
+
const detail = report.error ?? report.compact?.error ?? report.compact?.reason ?? report.subagent?.error
|
|
10
|
+
const error = new Error('Apollo 配置迁移尚未完成(' + report.status + ')。请检查迁移诊断,修复配置后重载 profile。' + (detail ? ' ' + detail : ''))
|
|
11
|
+
error.code = 'APOLLO_MIGRATION_PENDING'
|
|
12
|
+
throw error
|
|
13
|
+
}
|
|
14
|
+
if (requiresReload) {
|
|
15
|
+
const error = new Error('Apollo 已迁移压缩配置,但当前引擎仍使用旧快照。请重载 profile 后继续;刷新网页不会应用压缩配置。')
|
|
16
|
+
error.code = 'APOLLO_MIGRATION_RELOAD_REQUIRED'
|
|
17
|
+
throw error
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
ctx.on('agent/pre-step', (_payload, next) => {
|
|
21
|
+
assertReady()
|
|
22
|
+
return next()
|
|
23
|
+
}, { prepend: true })
|
|
24
|
+
// Manual /compact does not enter pre-step. Guard its provider boundary too,
|
|
25
|
+
// without replacing the compaction service or changing any request messages.
|
|
26
|
+
ctx.on('llm/stream', async function* (_options, next) {
|
|
27
|
+
assertReady()
|
|
28
|
+
yield* next()
|
|
29
|
+
}, { prepend: true })
|
|
30
|
+
return (result) => {
|
|
31
|
+
report = result
|
|
32
|
+
const compact = ctx.get?.('betterCompactConfig')
|
|
33
|
+
requiresReload = result.status === 'complete' && result.compact?.fields?.length > 0
|
|
34
|
+
&& compact !== undefined && !isDeepStrictEqual(compact.snapshot(), compact.current())
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { readFile, readdir } from 'node:fs/promises'
|
|
|
14
14
|
import { dirname, join } from 'node:path'
|
|
15
15
|
import { fileURLToPath } from 'node:url'
|
|
16
16
|
import { mountMigration } from './migrate.js'
|
|
17
|
+
import { mountMigrationAdmission } from './admission.js'
|
|
17
18
|
import { mountSettings } from './settings.js'
|
|
18
19
|
export { Config } from './config.js'
|
|
19
20
|
|
|
@@ -33,8 +34,9 @@ export const inject = ['skills']
|
|
|
33
34
|
export function apply(ctx, config) {
|
|
34
35
|
ctx.skills.registerProvider(() => createProvider(ctx))
|
|
35
36
|
if (typeof ctx.inject === 'function') {
|
|
37
|
+
const onResult = typeof ctx.on === 'function' ? mountMigrationAdmission(ctx) : undefined
|
|
36
38
|
const settings = mountSettings(ctx, config)
|
|
37
|
-
mountMigration(ctx, config, { legacyImport: settings.legacyImport })
|
|
39
|
+
mountMigration(ctx, config, { legacyImport: settings.legacyImport, onResult })
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
package/src/migrate.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* - `apollo-skills` 的 `tiers.fast/quality`、`subagents.{eng,global}`、
|
|
9
9
|
* `subagents.{codex,claude}.*`、`trustedHosts` → `dsh-better-subagent`
|
|
10
|
-
* 相同路径;`exitGuard` → `childExitGuard`。旧 `exitGuard`
|
|
11
|
-
* 作为 job
|
|
10
|
+
* 相同路径;`exitGuard` → `childExitGuard`。旧 `exitGuard` 同时保留/恢复到
|
|
11
|
+
* Apollo 作为 job 守卫开关;两边目标显式配置(含 false)各自优先。
|
|
12
12
|
* - 旧 `eng` / `eng-ptc` 预设里原生 `compaction-basic` 的显式配置 →
|
|
13
13
|
* `dsh-better-compact` 同名原生键;目标缺失的 `mode` 采用默认 `goal`。
|
|
14
14
|
*
|
|
@@ -524,6 +524,28 @@ export async function migrateSubagent({ settings, configEditor, descriptors, sou
|
|
|
524
524
|
return { status: 'complete', fields }
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
/** Restore only the job switch lost to a historical Apollo name guard. */
|
|
528
|
+
async function migrateJobExitGuard({ settings, descriptors, source, rawSource }) {
|
|
529
|
+
const target = descriptors.find((row) => row?.ns === APOLLO_NS)
|
|
530
|
+
// user also projects skipped overrides, so the active raw config is the
|
|
531
|
+
// authority for an already configured job switch (including explicit false).
|
|
532
|
+
if (hasOwn(rawSource, 'exitGuard')
|
|
533
|
+
|| (hasOwn(target?.user, 'exitGuard') && target.user.exitGuard !== source.exitGuard)
|
|
534
|
+
|| target?.value?.exitGuard === source.exitGuard) {
|
|
535
|
+
return { status: 'no-change' }
|
|
536
|
+
}
|
|
537
|
+
if (target === undefined) return { status: 'pending', error: 'Apollo namespace is not readable' }
|
|
538
|
+
try {
|
|
539
|
+
await settings.update(APOLLO_NS, { exitGuard: source.exitGuard }, target.revision)
|
|
540
|
+
} catch (error) {
|
|
541
|
+
return { status: 'pending', error: errorMessage(error) }
|
|
542
|
+
}
|
|
543
|
+
const after = (await settings.describe()).find((row) => row?.ns === APOLLO_NS)
|
|
544
|
+
return after?.value?.exitGuard === source.exitGuard
|
|
545
|
+
? { status: 'complete' }
|
|
546
|
+
: { status: 'error', error: 'unverified: exitGuard' }
|
|
547
|
+
}
|
|
548
|
+
|
|
527
549
|
/**
|
|
528
550
|
* Apply the compaction migration.
|
|
529
551
|
*
|
|
@@ -570,7 +592,8 @@ function errorMessage(error) {
|
|
|
570
592
|
* Run the one-time (idempotent) migration.
|
|
571
593
|
*
|
|
572
594
|
* Order: Loader settlement → legacy `eng.json` import → bounded wait for both
|
|
573
|
-
* target namespaces → subagent plan/write/verify →
|
|
595
|
+
* target namespaces → subagent plan/write/verify → job switch recovery →
|
|
596
|
+
* compact plan/write/verify.
|
|
574
597
|
* A missing target namespace yields `pending`; errors are reported, never
|
|
575
598
|
* silently claimed as success, and no source value is deleted.
|
|
576
599
|
*
|
|
@@ -588,7 +611,12 @@ export async function runMigration(ctx, options = {}) {
|
|
|
588
611
|
const loader = loaderOf(ctx)
|
|
589
612
|
if (loader !== undefined) await bounded(Promise.resolve(loader.await()).catch(() => undefined), timeoutMs)
|
|
590
613
|
if (options.legacyImport !== undefined) await bounded(options.legacyImport, timeoutMs)
|
|
591
|
-
const
|
|
614
|
+
const configEditor = options.configEditor ?? serviceOf(ctx, 'configEditor')
|
|
615
|
+
// A deliberately disabled row is not an unloaded/failed active plugin. Keep
|
|
616
|
+
// its legacy source intact for a later re-enable instead of blocking native work.
|
|
617
|
+
const disabled = new Set([SUBAGENT_NS, COMPACT_NS].filter((ns) => targetEntryOf(configEditor, ns)?.options?.disabled === true))
|
|
618
|
+
const targets = [SUBAGENT_NS, COMPACT_NS].filter((ns) => !disabled.has(ns))
|
|
619
|
+
const descriptors = await waitForDescriptors(settings, targets, {
|
|
592
620
|
timeoutMs,
|
|
593
621
|
intervalMs: options.intervalMs,
|
|
594
622
|
})
|
|
@@ -599,7 +627,6 @@ export async function runMigration(ctx, options = {}) {
|
|
|
599
627
|
return { status: 'pending', error: message }
|
|
600
628
|
}
|
|
601
629
|
const sourceDescriptor = descriptors.find((row) => row?.ns === APOLLO_NS)
|
|
602
|
-
const configEditor = options.configEditor ?? serviceOf(ctx, 'configEditor')
|
|
603
630
|
const agentPresets = options.agentPresets ?? serviceOf(ctx, 'agentPresets')
|
|
604
631
|
// describe().value only projects the *volatile* form, so read the Apollo
|
|
605
632
|
// row's raw config for non-volatile fields (trustedHosts) and overlay the
|
|
@@ -617,23 +644,34 @@ export async function runMigration(ctx, options = {}) {
|
|
|
617
644
|
effectiveSource,
|
|
618
645
|
configurationOverrideOf(configEditor, APOLLO_NS),
|
|
619
646
|
))
|
|
620
|
-
const subagent =
|
|
621
|
-
|
|
622
|
-
|
|
647
|
+
const subagent = disabled.has(SUBAGENT_NS)
|
|
648
|
+
? { status: 'disabled', fields: [] }
|
|
649
|
+
: await migrateSubagent({ settings, configEditor, descriptors, source, log })
|
|
650
|
+
// A scoped job write would become the last override and hide the skipped
|
|
651
|
+
// source from configuration().override. Wait until its child fields are safe.
|
|
652
|
+
const job = subagent.status === 'disabled'
|
|
653
|
+
? { status: 'deferred', reason: 'subagent is disabled; preserve the legacy source until it is re-enabled' }
|
|
654
|
+
: ['complete', 'no-change'].includes(subagent.status)
|
|
655
|
+
? await migrateJobExitGuard({ settings, descriptors, source, rawSource })
|
|
656
|
+
: { status: 'pending', error: 'waiting for the subagent migration before restoring the job switch' }
|
|
657
|
+
const compact = disabled.has(COMPACT_NS)
|
|
658
|
+
? { status: 'disabled', fields: [] }
|
|
659
|
+
: await migrateCompact({ settings, configEditor, descriptors, agentPresets, log })
|
|
660
|
+
const status = [job.status, subagent.status, compact.status].some((value) => value === 'error')
|
|
623
661
|
? 'error'
|
|
624
|
-
: [subagent.status, compact.status].some((value) => value === 'pending')
|
|
662
|
+
: [job.status, subagent.status, compact.status].some((value) => value === 'pending')
|
|
625
663
|
? 'pending'
|
|
626
664
|
: ['ambiguous', 'invalid', 'source-missing'].includes(compact.status) ? 'blocked'
|
|
627
665
|
: 'complete'
|
|
628
|
-
for (const [name, section] of [['subagent', subagent], ['compact', compact]]) {
|
|
666
|
+
for (const [name, section] of [['job', job], ['subagent', subagent], ['compact', compact]]) {
|
|
629
667
|
if (section.error !== undefined) {
|
|
630
668
|
log?.warn?.(`apollo-migration: ${name} is ${section.status}: ${section.error}`)
|
|
631
669
|
}
|
|
632
670
|
}
|
|
633
671
|
log?.[status === 'complete' ? 'info' : 'warn']?.(
|
|
634
|
-
`apollo-migration: ${status} (subagent=${subagent.status}, compact=${compact.status})`,
|
|
672
|
+
`apollo-migration: ${status} (job=${job.status}, subagent=${subagent.status}, compact=${compact.status})`,
|
|
635
673
|
)
|
|
636
|
-
return { status, source: sourceDescriptor === undefined ? 'apply-config' : 'settings', subagent, compact }
|
|
674
|
+
return { status, source: sourceDescriptor === undefined ? 'apply-config' : 'settings', job, subagent, compact }
|
|
637
675
|
}
|
|
638
676
|
|
|
639
677
|
/**
|
|
@@ -641,7 +679,8 @@ export async function runMigration(ctx, options = {}) {
|
|
|
641
679
|
*
|
|
642
680
|
* @param ctx - plugin context.
|
|
643
681
|
* @param config - Apollo row config (fallback source when describe() is not ready).
|
|
644
|
-
* @param options - `{ legacyImport, env, timeoutMs, intervalMs }`.
|
|
682
|
+
* @param options - `{ legacyImport, env, timeoutMs, intervalMs, onResult }`.
|
|
683
|
+
* `onResult` receives the settled report without blocking the Loader callback.
|
|
645
684
|
*/
|
|
646
685
|
export function mountMigration(ctx, config, options = {}) {
|
|
647
686
|
let started = false
|
|
@@ -656,7 +695,8 @@ export function mountMigration(ctx, config, options = {}) {
|
|
|
656
695
|
log: settingsCtx.logger ?? ctx.logger,
|
|
657
696
|
}).catch((error) => {
|
|
658
697
|
settingsCtx.logger?.warn?.(`apollo-migration: skipped: ${errorMessage(error)}`)
|
|
659
|
-
|
|
698
|
+
return { status: 'error', error: errorMessage(error) }
|
|
699
|
+
}).then((result) => options.onResult?.(result))
|
|
660
700
|
}
|
|
661
701
|
ctx.inject(['settings'], start)
|
|
662
702
|
}
|