@ai-agent-forge/agent-forge 0.88.5 → 0.88.7

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.
Files changed (202) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  3. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  4. package/bundled-plugins/alignment/agent-forge.json +19 -0
  5. package/bundled-plugins/alignment/dist/baseline.d.ts +12 -0
  6. package/bundled-plugins/alignment/dist/baseline.d.ts.map +1 -0
  7. package/bundled-plugins/alignment/dist/baseline.js +68 -0
  8. package/bundled-plugins/alignment/dist/baseline.js.map +1 -0
  9. package/bundled-plugins/alignment/dist/engine.d.ts +102 -0
  10. package/bundled-plugins/alignment/dist/engine.d.ts.map +1 -0
  11. package/bundled-plugins/alignment/dist/engine.js +654 -0
  12. package/bundled-plugins/alignment/dist/engine.js.map +1 -0
  13. package/bundled-plugins/alignment/dist/entry.d.ts +14 -0
  14. package/bundled-plugins/alignment/dist/entry.d.ts.map +1 -0
  15. package/bundled-plugins/alignment/dist/entry.js +23 -0
  16. package/bundled-plugins/alignment/dist/entry.js.map +1 -0
  17. package/bundled-plugins/alignment/dist/export.d.ts +15 -0
  18. package/bundled-plugins/alignment/dist/export.d.ts.map +1 -0
  19. package/bundled-plugins/alignment/dist/export.js +122 -0
  20. package/bundled-plugins/alignment/dist/export.js.map +1 -0
  21. package/bundled-plugins/alignment/dist/http-server.d.ts +33 -0
  22. package/bundled-plugins/alignment/dist/http-server.d.ts.map +1 -0
  23. package/bundled-plugins/alignment/dist/http-server.js +119 -0
  24. package/bundled-plugins/alignment/dist/http-server.js.map +1 -0
  25. package/bundled-plugins/alignment/dist/index.d.ts +24 -0
  26. package/bundled-plugins/alignment/dist/index.d.ts.map +1 -0
  27. package/bundled-plugins/alignment/dist/index.js +719 -0
  28. package/bundled-plugins/alignment/dist/index.js.map +1 -0
  29. package/bundled-plugins/alignment/dist/page.d.ts +15 -0
  30. package/bundled-plugins/alignment/dist/page.d.ts.map +1 -0
  31. package/bundled-plugins/alignment/dist/page.js +857 -0
  32. package/bundled-plugins/alignment/dist/page.js.map +1 -0
  33. package/bundled-plugins/alignment/dist/render.d.ts +40 -0
  34. package/bundled-plugins/alignment/dist/render.d.ts.map +1 -0
  35. package/bundled-plugins/alignment/dist/render.js +194 -0
  36. package/bundled-plugins/alignment/dist/render.js.map +1 -0
  37. package/bundled-plugins/alignment/dist/types.d.ts +217 -0
  38. package/bundled-plugins/alignment/dist/types.d.ts.map +1 -0
  39. package/bundled-plugins/alignment/dist/types.js +30 -0
  40. package/bundled-plugins/alignment/dist/types.js.map +1 -0
  41. package/bundled-plugins/alignment/plugin.json +12 -0
  42. package/bundled-plugins/browser-playwright/MANUAL.md +60 -0
  43. package/bundled-plugins/browser-playwright/agent-forge.json +25 -0
  44. package/bundled-plugins/browser-playwright/dist/capability.d.ts +25 -0
  45. package/bundled-plugins/browser-playwright/dist/capability.d.ts.map +1 -0
  46. package/bundled-plugins/browser-playwright/dist/capability.js +612 -0
  47. package/bundled-plugins/browser-playwright/dist/capability.js.map +1 -0
  48. package/bundled-plugins/browser-playwright/dist/entry.d.ts +13 -0
  49. package/bundled-plugins/browser-playwright/dist/entry.d.ts.map +1 -0
  50. package/bundled-plugins/browser-playwright/dist/entry.js +14 -0
  51. package/bundled-plugins/browser-playwright/dist/entry.js.map +1 -0
  52. package/bundled-plugins/browser-playwright/dist/index.d.ts +7 -0
  53. package/bundled-plugins/browser-playwright/dist/index.d.ts.map +1 -0
  54. package/bundled-plugins/browser-playwright/dist/index.js +5 -0
  55. package/bundled-plugins/browser-playwright/dist/index.js.map +1 -0
  56. package/bundled-plugins/browser-playwright/dist/operations.d.ts +69 -0
  57. package/bundled-plugins/browser-playwright/dist/operations.d.ts.map +1 -0
  58. package/bundled-plugins/browser-playwright/dist/operations.js +149 -0
  59. package/bundled-plugins/browser-playwright/dist/operations.js.map +1 -0
  60. package/bundled-plugins/browser-playwright/dist/playwright-driver.d.ts +275 -0
  61. package/bundled-plugins/browser-playwright/dist/playwright-driver.d.ts.map +1 -0
  62. package/bundled-plugins/browser-playwright/dist/playwright-driver.js +953 -0
  63. package/bundled-plugins/browser-playwright/dist/playwright-driver.js.map +1 -0
  64. package/bundled-plugins/browser-playwright/dist/setup.d.ts +88 -0
  65. package/bundled-plugins/browser-playwright/dist/setup.d.ts.map +1 -0
  66. package/bundled-plugins/browser-playwright/dist/setup.js +252 -0
  67. package/bundled-plugins/browser-playwright/dist/setup.js.map +1 -0
  68. package/bundled-plugins/browser-playwright/dist/types.d.ts +270 -0
  69. package/bundled-plugins/browser-playwright/dist/types.d.ts.map +1 -0
  70. package/bundled-plugins/browser-playwright/dist/types.js +2 -0
  71. package/bundled-plugins/browser-playwright/dist/types.js.map +1 -0
  72. package/bundled-plugins/browser-playwright/plugin.json +20 -0
  73. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  74. package/bundled-plugins/coding-tools/dist/bash.d.ts +2 -7
  75. package/bundled-plugins/coding-tools/dist/bash.d.ts.map +1 -1
  76. package/bundled-plugins/coding-tools/dist/bash.js +2 -34
  77. package/bundled-plugins/coding-tools/dist/bash.js.map +1 -1
  78. package/bundled-plugins/coding-tools/dist/read.d.ts +2 -0
  79. package/bundled-plugins/coding-tools/dist/read.d.ts.map +1 -1
  80. package/bundled-plugins/coding-tools/dist/read.js +11 -0
  81. package/bundled-plugins/coding-tools/dist/read.js.map +1 -1
  82. package/bundled-plugins/coding-tools/plugin.json +1 -1
  83. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  84. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  85. package/bundled-plugins/mcp-http/dist/mcp-http.d.ts.map +1 -1
  86. package/bundled-plugins/mcp-http/dist/mcp-http.js +84 -31
  87. package/bundled-plugins/mcp-http/dist/mcp-http.js.map +1 -1
  88. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  89. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  90. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  91. package/bundled-plugins/provider-failover/plugin.json +1 -1
  92. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  93. package/bundled-plugins/retry-policy/plugin.json +1 -1
  94. package/dist/bundle/.build-manifest.json +60 -58
  95. package/dist/bundle/chunks/{anthropic-messages-3FJHRAJL.js → anthropic-messages-NL4Y6WPB.js} +1 -1
  96. package/dist/bundle/chunks/{azure-openai-responses-GCL47IDS.js → azure-openai-responses-CPXC42HO.js} +1 -1
  97. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  98. package/dist/bundle/chunks/chunk-5LRQFZFE.js +2 -0
  99. package/dist/bundle/chunks/{chunk-HTEVUY7F.js → chunk-7HSJPQKN.js} +1 -1
  100. package/dist/bundle/chunks/{chunk-AC2FIS4G.js → chunk-EDO7Q6XR.js} +1 -1
  101. package/dist/bundle/chunks/{chunk-755VNWIF.js → chunk-ISLHFRER.js} +6 -6
  102. package/dist/bundle/chunks/{chunk-HV64ASMT.js → chunk-K3S6GTL7.js} +1 -1
  103. package/dist/bundle/chunks/{chunk-HEL6TAWE.js → chunk-L2SXIPI5.js} +37 -36
  104. package/dist/bundle/chunks/{chunk-V3ACW7VD.js → chunk-WJSKB3FC.js} +1 -1
  105. package/dist/bundle/chunks/{chunk-32YDZI4J.js → chunk-ZS5JEI76.js} +1 -1
  106. package/dist/bundle/chunks/{google-generative-ai-6BMXWA44.js → google-generative-ai-UMZ53EFA.js} +1 -1
  107. package/dist/bundle/chunks/{google-vertex-6H7NLRTK.js → google-vertex-ZNR5NS6H.js} +1 -1
  108. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  109. package/dist/bundle/chunks/{mistral-conversations-IXUHSFSJ.js → mistral-conversations-IT66WUNN.js} +1 -1
  110. package/dist/bundle/chunks/{openai-codex-responses-YHUAEVCM.js → openai-codex-responses-FOVCVG6I.js} +1 -1
  111. package/dist/bundle/chunks/{openai-completions-ULQCFC72.js → openai-completions-FLQ7CBOL.js} +1 -1
  112. package/dist/bundle/chunks/{openai-responses-NLLAJDPS.js → openai-responses-ABGYHS2T.js} +1 -1
  113. package/dist/bundle/chunks/{pi-messages-EJTI2EJ3.js → pi-messages-6K5W6LUN.js} +1 -1
  114. package/dist/bundle/chunks/{virtual-modules-TQWEGNNZ.js → virtual-modules-2QGILFV7.js} +1 -1
  115. package/dist/bundle/cli.js +1 -1
  116. package/dist/bundle/client.js +1 -1
  117. package/dist/bundle/index.js +1 -1
  118. package/dist/bundle/rpc-entry.js +1 -1
  119. package/dist/client/remote-session.d.ts.map +1 -1
  120. package/dist/client/remote-session.js +65 -6
  121. package/dist/client/remote-session.js.map +1 -1
  122. package/dist/core/agent-session-store.d.ts.map +1 -1
  123. package/dist/core/agent-session-store.js +20 -3
  124. package/dist/core/agent-session-store.js.map +1 -1
  125. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  126. package/dist/core/extensions/agent-composition.js +20 -1
  127. package/dist/core/extensions/agent-composition.js.map +1 -1
  128. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  129. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -0
  130. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  131. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  132. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +10 -3
  133. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  134. package/dist/core/keybindings.d.ts +35 -0
  135. package/dist/core/keybindings.d.ts.map +1 -1
  136. package/dist/core/keybindings.js +34 -0
  137. package/dist/core/keybindings.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +62 -15
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts.map +1 -1
  142. package/dist/core/session-manager.js +11 -3
  143. package/dist/core/session-manager.js.map +1 -1
  144. package/dist/core/system-prompt.d.ts.map +1 -1
  145. package/dist/core/system-prompt.js +2 -2
  146. package/dist/core/system-prompt.js.map +1 -1
  147. package/dist/core/tools/capability-mount.d.ts.map +1 -1
  148. package/dist/core/tools/capability-mount.js +4 -21
  149. package/dist/core/tools/capability-mount.js.map +1 -1
  150. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/assistant-message.js +2 -2
  152. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  153. package/dist/modes/interactive/components/bash-execution.d.ts +2 -0
  154. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/bash-execution.js +25 -0
  156. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  157. package/dist/modes/interactive/components/changelog-pager.d.ts +53 -0
  158. package/dist/modes/interactive/components/changelog-pager.d.ts.map +1 -0
  159. package/dist/modes/interactive/components/changelog-pager.js +239 -0
  160. package/dist/modes/interactive/components/changelog-pager.js.map +1 -0
  161. package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
  162. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  163. package/dist/modes/interactive/components/tool-execution.js +12 -0
  164. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  165. package/dist/modes/interactive/components/tool-run-group.d.ts +41 -11
  166. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -1
  167. package/dist/modes/interactive/components/tool-run-group.js +126 -14
  168. package/dist/modes/interactive/components/tool-run-group.js.map +1 -1
  169. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  170. package/dist/modes/interactive/interactive-commands.js +23 -13
  171. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  172. package/dist/modes/interactive/interactive-events.d.ts +14 -4
  173. package/dist/modes/interactive/interactive-events.d.ts.map +1 -1
  174. package/dist/modes/interactive/interactive-events.js +94 -12
  175. package/dist/modes/interactive/interactive-events.js.map +1 -1
  176. package/dist/modes/interactive/interactive-mode.d.ts +6 -1
  177. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  178. package/dist/modes/interactive/interactive-mode.js +21 -5
  179. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/dist/plugins/ecosystem/node-local-package-source.d.ts +2 -1
  181. package/dist/plugins/ecosystem/node-local-package-source.d.ts.map +1 -1
  182. package/dist/plugins/ecosystem/node-local-package-source.js +110 -4
  183. package/dist/plugins/ecosystem/node-local-package-source.js.map +1 -1
  184. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  185. package/dist/plugins/ecosystem/node-package-install-host.js +106 -39
  186. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  187. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  188. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +85 -2
  189. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  190. package/dist/suites/builtin-suites.d.ts.map +1 -1
  191. package/dist/suites/builtin-suites.js +2 -2
  192. package/dist/suites/builtin-suites.js.map +1 -1
  193. package/dist/utils/changelog.d.ts +27 -0
  194. package/dist/utils/changelog.d.ts.map +1 -1
  195. package/dist/utils/changelog.js +110 -0
  196. package/dist/utils/changelog.js.map +1 -1
  197. package/docs/keybindings.md +14 -0
  198. package/examples/extensions/with-deps/package-lock.json +2 -2
  199. package/examples/extensions/with-deps/package.json +1 -1
  200. package/examples/extensions/with-deps/plugin.json +1 -1
  201. package/package.json +1 -1
  202. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
@@ -49,6 +49,26 @@ function readActiveVersions(store, scope, scopeRef, signal) {
49
49
  return versions;
50
50
  })();
51
51
  }
52
+ /**
53
+ * Previous active installation record for one plugin id in the bootstrap's
54
+ * global installation scope, or undefined when the plugin has no active
55
+ * global installation. Mirrors the CLI update transaction's previous lookup
56
+ * (cli.ts `findCurrentStateRecord`): same plugin id, same scope/scopeRef,
57
+ * lifecycle active — bootstrap installs exclusively into this scope, so only
58
+ * a record here can have had its runtime disposed by host.activate.
59
+ */
60
+ async function readPreviousActiveRecord(store, pluginId, signal) {
61
+ const result = await store.read({ ...(signal === undefined ? {} : { signal }) });
62
+ if (result.status !== "ok" && result.status !== "missing")
63
+ throw new Error(t("plugin state read failed ({detail}) for the {scope} scope", {
64
+ detail: result.diagnostics[0]?.code ?? result.status,
65
+ scope: "global",
66
+ }));
67
+ return result.snapshot.records.find((record) => record.pluginId === pluginId &&
68
+ record.state.scope === "global" &&
69
+ record.state.scopeRef === DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1 &&
70
+ record.state.lifecycle === "active");
71
+ }
52
72
  /**
53
73
  * Run the startup bootstrap for one agent directory. The function resolves
54
74
  * with a structured result and never throws for per-plugin failures; only a
@@ -199,6 +219,40 @@ export async function runNodePluginBootstrapV1(options) {
199
219
  ...(signal === undefined ? {} : { signal }),
200
220
  });
201
221
  if (activated.status !== "succeeded") {
222
+ // CLI update-transaction alignment (cli.ts activate-failure
223
+ // path): host.activate disposed the previous runtime for this
224
+ // installation key before the new candidate failed to commit,
225
+ // so restore the previous active installation through the
226
+ // installer rollback. Rollback runs before the failed
227
+ // candidate is removed because host.rollback requires the
228
+ // failed record to still exist.
229
+ let restoreFailure;
230
+ try {
231
+ const previous = await readPreviousActiveRecord(active.stateStore, acquired.manifest.id, signal);
232
+ if (previous !== undefined) {
233
+ const rolledBack = await active.installer.rollback({
234
+ failed: installed.installation,
235
+ previous: {
236
+ version: 1,
237
+ pluginId: previous.pluginId,
238
+ pluginVersion: previous.pluginVersion,
239
+ manifestDigest: previous.manifestDigest,
240
+ scope: previous.state.scope,
241
+ scopeRef: previous.state.scopeRef,
242
+ installationRef: previous.installationRef,
243
+ state: "active",
244
+ },
245
+ scope: "global",
246
+ scopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,
247
+ ...(signal === undefined ? {} : { signal }),
248
+ });
249
+ if (rolledBack.status !== "succeeded")
250
+ restoreFailure = rolledBack.error.code;
251
+ }
252
+ }
253
+ catch (error) {
254
+ restoreFailure = error instanceof Error ? error.message : String(error);
255
+ }
202
256
  await active.installer
203
257
  .remove({
204
258
  installation: installed.installation,
@@ -206,10 +260,13 @@ export async function runNodePluginBootstrapV1(options) {
206
260
  scopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,
207
261
  })
208
262
  .catch(() => undefined);
209
- throw new Error(t("plugin activation failed ({code}) for {pluginId}", {
263
+ const activationMessage = t("plugin activation failed ({code}) for {pluginId}", {
210
264
  code: activated.error.code,
211
265
  pluginId: acquired.manifest.id,
212
- }));
266
+ });
267
+ throw new Error(restoreFailure === undefined
268
+ ? activationMessage
269
+ : `${activationMessage}; previous version restore failed: ${restoreFailure}`);
213
270
  }
214
271
  const persisted = await active.stateStore.upsert({
215
272
  installation: activated.installation,
@@ -231,6 +288,32 @@ export async function runNodePluginBootstrapV1(options) {
231
288
  pluginId: acquired.manifest.id,
232
289
  }));
233
290
  }
291
+ // 出厂对齐语义(duplicate_active 修复,2026-10-08):stateStore 的 upsert
292
+ // 按 scope:scopeRef:pluginId@version 去重,多版本并存是 store 的合法形态;
293
+ // 但 bootstrap 把该插件在 global scope 对齐到工厂 range——升级成功后同插件
294
+ // 其他版本的 active binding 必须退役,否则 active-bindings 解析遇
295
+ // duplicate_active 拒选(真实升级 0.88.5→0.88.6 实证)。只退役 state 记录、
296
+ // 不删安装目录;退役失败降级保留残留(等同修复前状态,下次启动重试)。
297
+ const allRecords = await active.stateStore.read({ ...(signal === undefined ? {} : { signal }) });
298
+ if (allRecords.status === "ok") {
299
+ for (const record of allRecords.snapshot.records) {
300
+ if (record.pluginId === activated.installation.pluginId &&
301
+ record.pluginVersion !== activated.installation.pluginVersion &&
302
+ record.state.scope === "global" &&
303
+ record.state.scopeRef === DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1 &&
304
+ record.state.lifecycle === "active") {
305
+ await active.stateStore
306
+ .remove({
307
+ pluginId: record.pluginId,
308
+ pluginVersion: record.pluginVersion,
309
+ scope: "global",
310
+ scopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,
311
+ ...(signal === undefined ? {} : { signal }),
312
+ })
313
+ .catch(() => undefined);
314
+ }
315
+ }
316
+ }
234
317
  return { pluginVersion: activated.installation.pluginVersion, source: acquired.source };
235
318
  }
236
319
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"node-plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport {\n\ttype PluginBootstrapActionV1,\n\ttype PluginBootstrapDepsV1,\n\ttype PluginBootstrapResultV1,\n\trunPluginBootstrapV1,\n} from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Overrides the per-plugin progress renderer (stderr) for tests and hosts.\n\t * The default prints one line per installed/aligned/failed entry and stays\n\t * silent for satisfied entries.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t\t...(options.onAction === undefined ? {} : { onAction: options.onAction }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\t// Download retry (设计 §4.4 下载重试, 2026-10-04): transient registry\n\t\t\t// failures retried with backoff at this wiring layer so the decision\n\t\t\t// loop stays pure. Abort propagates immediately between attempts.\n\t\t\tlet lastError: unknown;\n\t\t\tfor (let attempt = 1; attempt <= 3; attempt++) {\n\t\t\t\tif (signal?.aborted === true) throw lastError ?? new Error(\"install aborted\");\n\t\t\t\ttry {\n\t\t\t\t\treturn await installFromNpmOnce({ npmName, range, signal });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlastError = error;\n\t\t\t\t\t// Abort during the attempt surfaces as the attempt's own error;\n\t\t\t\t\t// the loop-top check and the backoff listener cover the pauses.\n\t\t\t\t\tif (attempt === 3) throw error;\n\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tconst timer = setTimeout(resolve, 400 * 2 ** (attempt - 1));\n\t\t\t\t\t\tsignal?.addEventListener(\n\t\t\t\t\t\t\t\"abort\",\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\t\t\treject(lastError);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ once: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastError;\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\tconst installFromNpmOnce = async (input: {\n\t\treadonly npmName: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<{ readonly pluginVersion: string; readonly source: string }> => {\n\t\tconst { npmName, range, signal } = input;\n\t\t{\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t}\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t\t// Per-plugin progress (设计 §4.4 逐插件进度, 2026-10-04): one stderr\n\t\t\t// line per installed/aligned/failed entry; satisfied entries stay\n\t\t\t// silent so an all-green startup prints nothing extra.\n\t\t\tonAction:\n\t\t\t\toptions.onAction ??\n\t\t\t\t((action: PluginBootstrapActionV1) => {\n\t\t\t\t\tif (action.status === \"installed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\"{pluginId}: installed {version}\", {\n\t\t\t\t\t\t\t\tpluginId: action.pluginId,\n\t\t\t\t\t\t\t\tversion: action.installedVersion ?? \"\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (action.status === \"failed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\n\t\t\t\t\t\t\t\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\",\n\t\t\t\t\t\t\t\t{ pluginId: action.pluginId, code: action.errorCode ?? \"install_failed\" },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"node-plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport {\n\ttype PluginBootstrapActionV1,\n\ttype PluginBootstrapDepsV1,\n\ttype PluginBootstrapResultV1,\n\trunPluginBootstrapV1,\n} from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateRecordV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Overrides the per-plugin progress renderer (stderr) for tests and hosts.\n\t * The default prints one line per installed/aligned/failed entry and stays\n\t * silent for satisfied entries.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Previous active installation record for one plugin id in the bootstrap's\n * global installation scope, or undefined when the plugin has no active\n * global installation. Mirrors the CLI update transaction's previous lookup\n * (cli.ts `findCurrentStateRecord`): same plugin id, same scope/scopeRef,\n * lifecycle active — bootstrap installs exclusively into this scope, so only\n * a record here can have had its runtime disposed by host.activate.\n */\nasync function readPreviousActiveRecord(\n\tstore: PluginStateStoreV1,\n\tpluginId: string,\n\tsignal: AbortSignal | undefined,\n): Promise<PluginStateRecordV1 | undefined> {\n\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\tthrow new Error(\n\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\tscope: \"global\",\n\t\t\t}),\n\t\t);\n\treturn result.snapshot.records.find(\n\t\t(record) =>\n\t\t\trecord.pluginId === pluginId &&\n\t\t\trecord.state.scope === \"global\" &&\n\t\t\trecord.state.scopeRef === DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1 &&\n\t\t\trecord.state.lifecycle === \"active\",\n\t);\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t\t...(options.onAction === undefined ? {} : { onAction: options.onAction }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\t// Download retry (设计 §4.4 下载重试, 2026-10-04): transient registry\n\t\t\t// failures retried with backoff at this wiring layer so the decision\n\t\t\t// loop stays pure. Abort propagates immediately between attempts.\n\t\t\tlet lastError: unknown;\n\t\t\tfor (let attempt = 1; attempt <= 3; attempt++) {\n\t\t\t\tif (signal?.aborted === true) throw lastError ?? new Error(\"install aborted\");\n\t\t\t\ttry {\n\t\t\t\t\treturn await installFromNpmOnce({ npmName, range, signal });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlastError = error;\n\t\t\t\t\t// Abort during the attempt surfaces as the attempt's own error;\n\t\t\t\t\t// the loop-top check and the backoff listener cover the pauses.\n\t\t\t\t\tif (attempt === 3) throw error;\n\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tconst timer = setTimeout(resolve, 400 * 2 ** (attempt - 1));\n\t\t\t\t\t\tsignal?.addEventListener(\n\t\t\t\t\t\t\t\"abort\",\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\t\t\treject(lastError);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ once: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastError;\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\tconst installFromNpmOnce = async (input: {\n\t\treadonly npmName: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<{ readonly pluginVersion: string; readonly source: string }> => {\n\t\tconst { npmName, range, signal } = input;\n\t\t{\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\t// CLI update-transaction alignment (cli.ts activate-failure\n\t\t\t\t\t// path): host.activate disposed the previous runtime for this\n\t\t\t\t\t// installation key before the new candidate failed to commit,\n\t\t\t\t\t// so restore the previous active installation through the\n\t\t\t\t\t// installer rollback. Rollback runs before the failed\n\t\t\t\t\t// candidate is removed because host.rollback requires the\n\t\t\t\t\t// failed record to still exist.\n\t\t\t\t\tlet restoreFailure: string | undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst previous = await readPreviousActiveRecord(active.stateStore, acquired.manifest.id, signal);\n\t\t\t\t\t\tif (previous !== undefined) {\n\t\t\t\t\t\t\tconst rolledBack = await active.installer.rollback({\n\t\t\t\t\t\t\t\tfailed: installed.installation,\n\t\t\t\t\t\t\t\tprevious: {\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\tpluginId: previous.pluginId,\n\t\t\t\t\t\t\t\t\tpluginVersion: previous.pluginVersion,\n\t\t\t\t\t\t\t\t\tmanifestDigest: previous.manifestDigest,\n\t\t\t\t\t\t\t\t\tscope: previous.state.scope,\n\t\t\t\t\t\t\t\t\tscopeRef: previous.state.scopeRef,\n\t\t\t\t\t\t\t\t\tinstallationRef: previous.installationRef,\n\t\t\t\t\t\t\t\t\tstate: \"active\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (rolledBack.status !== \"succeeded\") restoreFailure = rolledBack.error.code;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\trestoreFailure = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t}\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tconst activationMessage = t(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t});\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\trestoreFailure === undefined\n\t\t\t\t\t\t\t? activationMessage\n\t\t\t\t\t\t\t: `${activationMessage}; previous version restore failed: ${restoreFailure}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// 出厂对齐语义(duplicate_active 修复,2026-10-08):stateStore 的 upsert\n\t\t\t\t// 按 scope:scopeRef:pluginId@version 去重,多版本并存是 store 的合法形态;\n\t\t\t\t// 但 bootstrap 把该插件在 global scope 对齐到工厂 range——升级成功后同插件\n\t\t\t\t// 其他版本的 active binding 必须退役,否则 active-bindings 解析遇\n\t\t\t\t// duplicate_active 拒选(真实升级 0.88.5→0.88.6 实证)。只退役 state 记录、\n\t\t\t\t// 不删安装目录;退役失败降级保留残留(等同修复前状态,下次启动重试)。\n\t\t\t\tconst allRecords = await active.stateStore.read({ ...(signal === undefined ? {} : { signal }) });\n\t\t\t\tif (allRecords.status === \"ok\") {\n\t\t\t\t\tfor (const record of allRecords.snapshot.records) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\trecord.pluginId === activated.installation.pluginId &&\n\t\t\t\t\t\t\trecord.pluginVersion !== activated.installation.pluginVersion &&\n\t\t\t\t\t\t\trecord.state.scope === \"global\" &&\n\t\t\t\t\t\t\trecord.state.scopeRef === DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1 &&\n\t\t\t\t\t\t\trecord.state.lifecycle === \"active\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tawait active.stateStore\n\t\t\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\t\t\tpluginId: record.pluginId,\n\t\t\t\t\t\t\t\t\tpluginVersion: record.pluginVersion,\n\t\t\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t}\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t\t// Per-plugin progress (设计 §4.4 逐插件进度, 2026-10-04): one stderr\n\t\t\t// line per installed/aligned/failed entry; satisfied entries stay\n\t\t\t// silent so an all-green startup prints nothing extra.\n\t\t\tonAction:\n\t\t\t\toptions.onAction ??\n\t\t\t\t((action: PluginBootstrapActionV1) => {\n\t\t\t\t\tif (action.status === \"installed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\"{pluginId}: installed {version}\", {\n\t\t\t\t\t\t\t\tpluginId: action.pluginId,\n\t\t\t\t\t\t\t\tversion: action.installedVersion ?? \"\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (action.status === \"failed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\n\t\t\t\t\t\t\t\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\",\n\t\t\t\t\t\t\t\t{ pluginId: action.pluginId, code: action.errorCode ?? \"install_failed\" },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-suites.d.ts","sourceRoot":"","sources":["../../src/suites/builtin-suites.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builtin suite (方案) declarations and suite.json (schemaVersion 1)\n * serialization, parsing, and validation — 方案系统设计.md v2 §5/§6/§9, M1a.\n *\n * Suites are pure data plus default policy: both builtin suites share the same\n * unrestricted tool surface and differ only in orientation and memory strategy\n * (the orientation persona text is injected into the system prompt, M2).\n * Nothing here touches the packages/agent kernel; association resolution is\n * declaration-only until M1b.\n */\n\nexport const SUITE_SCHEMA_VERSION = 1;\n\n/**\n * Factory contents revision (M4): the revision of the factory builtin\n * declarations, independent of SUITE_SCHEMA_VERSION. Bump it (and update both\n * builtin declarations' `factoryRevision`) whenever the factory contents\n * change; the registry upgrade proposal then offers `--suite-reset` for\n * workspaces still on an older revision. Suite schema evolution keeps using\n * SUITE_SCHEMA_VERSION.\n *\n * Revision 2 (统一修复轮集成收口, 2026-09-08): assistant and coding now share\n * the same active 8-tool surface in full-control — the sdk `suiteToolOverride`\n * DEFAULT_SUITE_ID exemption was removed (方案设计 §5 + user decision). Existing\n * workspaces provisioned at revision 1 receive the upgrade-proposal diagnostic\n * and adopt via `--suite-reset`.\n *\n * Revision 3 (2026-09-18): `builtin.session-share` joins both builtin suites\n * (开发计划 §216: session-share productized from the example plugin into a\n * first-party default-distributed capability) once the agent-dir config\n * channel for embedded capabilities landed\n * (`<agentDir>/capabilities/<short-id>.json`, see capabilities/builtin.ts).\n * Existing workspaces provisioned at revision 2 receive the upgrade-proposal\n * diagnostic and adopt via `--suite-reset`.\n *\n * Revision 4 (2026-09-18): `builtin.subagent-delegate` joins both builtin\n * suites — the first-party subagent delegation tool (`subagent_run`) now ships\n * by default in shared mode (zero extra processes; pooled runner processes stay\n * opt-in through the capability config channel). Existing workspaces\n * provisioned at revision 3 receive the upgrade-proposal diagnostic and adopt\n * via `--suite-reset`.\n *\n * Revision 5 (2026-09-20): subagent role profiles land on disk only\n * (`<agentDir>/roles/<id>.json` — the factory seeds explore/reviewer and never\n * overwrites user edits) and both builtin suites associate them by default via\n * the new `suite.associations.roles` field, with skill/MCP-isomorphic\n * visibility: unassociated roles stay invisible, associated-but-missing files\n * surface as dangling diagnostics. Existing workspaces provisioned at\n * revision 4 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n *\n * Revision 6 (D-077, 2026-10-02): `builtin.workflow` joins both builtin suites\n * — the workflow orchestration plugin enters the factory bootstrap manifest\n * (ninth package) and the suite capability declaration at goal/plan/todo-set\n * parity, keeping its plugin form. Existing workspaces provisioned at revision\n * 5 receive the upgrade-proposal diagnostic and adopt via `--suite-reset`.\n *\n * Revision 7 (视觉保底, 2026-10-04): the two visual baseline roles\n * `design-proposer` / `visual-reviewer` join the factory seeds and the default\n * `associations.roles` (user ruling \"术有专攻、角色隔离\"; role files are\n * disk-only and the seeds never overwrite user edits — see\n * `docs/plans/视觉保底角色设计注记.md`). Existing workspaces provisioned at\n * revision 6 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n */\nexport const FACTORY_CONTENTS_VERSION = 7;\n\n/**\n * Factory default suite used when no suite is configured anywhere (设计 §9).\n * 2026-10-02 user ruling: the product is a coding agent, so the factory\n * default flipped from \"assistant\" to \"coding\"; assistant stays as the\n * explicit-switch fallback suite.\n */\nexport const DEFAULT_SUITE_ID = \"coding\";\n\n/** Suite ids become directory names: lowercase letters, digits, hyphens (设计 §9). */\nexport const SUITE_ID_MAX_LENGTH = 64;\n\n/** The single unrestricted tool surface shared by both builtin suites (设计 §5/§6). */\nexport const BUILTIN_SUITE_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"write\",\n\t\"edit\",\n\t\"bash\",\n\t\"ls\",\n\t\"find\",\n\t\"grep\",\n\t\"powershell\",\n];\n\n/**\n * Builtin capability plugins associated with both suites. Declaration-only\n * data in M1a; the actual plugin wiring is delivered in M3. `builtin.memory`\n * joins in the 统一修复轮 A 路 (方案系统设计 §6.1: both suites share the same\n * memory tool surface; the strategy difference lives in the suiteId domain\n * isolation and the assistant preference card). `builtin.session-share` joins\n * in the session-share productization slice (开发计划 §216); its\n * target/gateway/viewerUrl are configured through the agent-dir config\n * channel (`<agentDir>/capabilities/builtin.session-share.json`), and the\n * unconfigured default answers `/share` with the explicit configuration\n * prompt — never an implicit Radius/Gist fallback. `builtin.workflow` joins\n * at goal/plan/todo-set parity (D-077, 2026-10-02: factory default install\n * plus this suite declaration, plugin form unchanged). `builtin.coding-tools`\n * joins with the D-082 batch-1 tool split (2026-10-03): the default coding\n * tools assemble from the `plugins/coding-tools` package through the bundled\n * distribution channel (插件独立分发与启动装配设计 §4.9), not the install\n * store.\n */\nexport const BUILTIN_SUITE_CAPABILITIES: readonly string[] = [\n\t\"builtin.goal\",\n\t\"builtin.plan\",\n\t\"builtin.todo-set\",\n\t\"builtin.workflow\",\n\t\"builtin.memory\",\n\t\"builtin.session-share\",\n\t\"builtin.subagent-delegate\",\n\t\"builtin.coding-tools\",\n];\n\nexport type SuiteMemoryStrategy = \"assistant\" | \"code\";\nexport type SuiteOrientation = \"assistant\" | \"coding\" | \"custom\";\n\n/**\n * Orientation persona texts injected into the system prompt (设计 §6.2, M2).\n * The strings are verbatim from the design spec: the assistant persona is the\n * companion style, the coding persona is the rigor-first style. Both are\n * session-nature declarations, so they ride every system prompt branch\n * (default and customPrompt). The custom orientation is not in this table: its\n * persona text comes from the suite workspace persona.md (设计 §6.3, resolved\n * by suite-loader).\n */\nexport const ORIENTATION_PROMPTS: Record<\"assistant\" | \"coding\", string> = {\n\tassistant: `You are the user's thoughtful companion — warm, patient, and helpful.\n- Understand the intent behind the question, including the unspoken parts; when something that matters is ambiguous, ask one short clarifying question instead of assuming.\n- Pay attention to detail: notice what the user might have missed and gently point it out.\n- Be proactive and divergent: after answering, offer next steps, related ideas, or creative alternatives — without being pushy.\n- Adapt tone to the user; stay natural and flexible, never robotic or formulaic.\n- When you can help by doing, act through tools autonomously (minimal interruption).\n- Structure longer answers clearly: short paragraphs, lists where they help, and a concrete \"what you can do next\" at the end.`,\n\tcoding: `You are an autonomous software engineering agent with a rigor-first mindset.\n- Never guess. Ground every claim in code you have read, commands you have run, or documented evidence; cite file paths and line numbers. If the evidence is insufficient, investigate, and report what is unverified — or \"unknown\" — instead of a plausible invention.\n- First principles: trace problems to the earliest reasonable root cause and fix that; do not patch symptoms.\n- No over-engineering: add no abstraction, options, or defensive handling for imagined future needs; generalise only when a second concrete case demands it.\n- Tests first: pin expected behavior with a failing or updated test before or alongside the fix, then run the smallest sufficient relevant checks; the work is not done until they pass.\n- Reproducible: prefer deterministic tests and mocks over ad-hoc verification, and report the exact commands and results so others can re-run them.\n- Docs as code: repository documentation is part of the change — keep design docs, READMEs, and changelogs consistent with the behavior they describe.\n- Self-review before finishing: re-check your changes for correctness, edge cases, regressions, and missing tests; prefer a second review pass over shipping the first draft.\n- Cautious: weigh side effects, compatibility, and failure modes; when in doubt, take the safer path.`,\n};\n\nexport interface SuiteAssociations {\n\treadonly skills: readonly string[];\n\treadonly mcp: readonly string[];\n\treadonly plugins: readonly string[];\n\t/**\n\t * 子代理角色关联(D-044 角色机制):关联的是 `<agentDir>/roles/<id>.json` 里的角色 id。\n\t * 角色定义只在磁盘上(工厂仅做种子落盘),方案只决定哪些角色对主代理可见——与\n\t * skill/MCP/插件同构,第一方与第三方角色没有区别。\n\t */\n\treadonly roles: readonly string[];\n}\n\nexport interface SuiteClonedFrom {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly at: number;\n}\n\n/** The serializable suite definition persisted as suite.json (设计 §5). */\nexport interface SuiteDefinition {\n\treadonly schemaVersion: number;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly builtin: boolean;\n\treadonly tools: readonly string[];\n\treadonly capabilities: readonly string[];\n\treadonly associations: SuiteAssociations;\n\treadonly inheritSystemAgentsMd: boolean;\n\treadonly memory: SuiteMemoryStrategy;\n\treadonly orientation: SuiteOrientation;\n\treadonly model: string | null;\n\treadonly thinking: string | null;\n\treadonly clonedFrom: SuiteClonedFrom | null;\n\t/**\n\t * Factory contents revision this declaration was written at (M4). Builtin\n\t * declarations carry it; on-disk builtin suite.json may omit it (pre-M4\n\t * files parse as FACTORY_CONTENTS_VERSION). User suites are outside factory\n\t * upgrade governance: the key stays optional and may be absent.\n\t */\n\treadonly factoryRevision?: number;\n}\n\nconst EMPTY_ASSOCIATIONS: SuiteAssociations = { skills: [], mcp: [], plugins: [], roles: [] };\n\n/**\n * 默认方案关联的子代理角色(开箱即用):这四个 id 对应工厂种子落盘的四个普通角色文件\n * (`<agentDir>/roles/{explore,reviewer,design-proposer,visual-reviewer}.json`,用户可改可删)。\n * design-proposer / visual-reviewer 是视觉保底角色(2026-10-04 用户裁决\"术有专攻、角色隔离\"),\n * 档案 readonly + 只读工具收窄,与编码角色结构性隔离——见 docs/plans/视觉保底角色设计注记.md。\n * 工厂不在运行期回退到任何编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\n\t\"explore\",\n\t\"reviewer\",\n\t\"design-proposer\",\n\t\"visual-reviewer\",\n];\n\nconst assistantSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"assistant\",\n\tname: \"Assistant\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"assistant\",\n\torientation: \"assistant\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\nconst codingSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"coding\",\n\tname: \"Coding\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"code\",\n\torientation: \"coding\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\n/** The factory builtin pair: coding (factory default 尖刀) and assistant (fallback). */\nexport const BUILTIN_SUITES: readonly SuiteDefinition[] = [assistantSuite, codingSuite];\n\nexport function getBuiltinSuite(id: string): SuiteDefinition | undefined {\n\treturn BUILTIN_SUITES.find((suite) => suite.id === id);\n}\n\nexport function isBuiltinSuiteId(id: string): boolean {\n\treturn BUILTIN_SUITES.some((suite) => suite.id === id);\n}\n\nconst WINDOWS_RESERVED_IDS = new Set([\n\t\"con\",\n\t\"prn\",\n\t\"aux\",\n\t\"nul\",\n\t\"com1\",\n\t\"com2\",\n\t\"com3\",\n\t\"com4\",\n\t\"com5\",\n\t\"com6\",\n\t\"com7\",\n\t\"com8\",\n\t\"com9\",\n\t\"lpt1\",\n\t\"lpt2\",\n\t\"lpt3\",\n\t\"lpt4\",\n\t\"lpt5\",\n\t\"lpt6\",\n\t\"lpt7\",\n\t\"lpt8\",\n\t\"lpt9\",\n\t\"conin$\",\n\t\"conout$\",\n]);\n\n/** Suite id rule (设计 §9): `a-z0-9-`, no leading/trailing hyphen, no Windows reserved names. */\nexport function isValidSuiteId(id: string): boolean {\n\tif (id.length === 0 || id.length > SUITE_ID_MAX_LENGTH) return false;\n\tif (!/^[a-z0-9-]+$/.test(id)) return false;\n\tif (id.startsWith(\"-\") || id.endsWith(\"-\")) return false;\n\tif (WINDOWS_RESERVED_IDS.has(id)) return false;\n\treturn true;\n}\n\n/** Serializes a suite to the canonical suite.json text (stable field order, trailing newline). */\nexport function serializeSuiteJson(suite: SuiteDefinition): string {\n\tconst ordered = {\n\t\tschemaVersion: suite.schemaVersion,\n\t\tid: suite.id,\n\t\tname: suite.name,\n\t\tbuiltin: suite.builtin,\n\t\ttools: [...suite.tools],\n\t\tcapabilities: [...suite.capabilities],\n\t\tassociations: {\n\t\t\tskills: [...suite.associations.skills],\n\t\t\tmcp: [...suite.associations.mcp],\n\t\t\tplugins: [...suite.associations.plugins],\n\t\t\troles: [...suite.associations.roles],\n\t\t},\n\t\tinheritSystemAgentsMd: suite.inheritSystemAgentsMd,\n\t\tmemory: suite.memory,\n\t\torientation: suite.orientation,\n\t\tmodel: suite.model,\n\t\tthinking: suite.thinking,\n\t\tclonedFrom: suite.clonedFrom\n\t\t\t? { id: suite.clonedFrom.id, digest: suite.clonedFrom.digest, at: suite.clonedFrom.at }\n\t\t\t: null,\n\t\tfactoryRevision: suite.factoryRevision,\n\t};\n\treturn `${JSON.stringify(ordered, null, 2)}\\n`;\n}\n\nexport interface SuiteJsonParseResult {\n\treadonly valid: boolean;\n\treadonly suite?: SuiteDefinition;\n\treadonly errors: readonly string[];\n}\n\n/**\n * Parses suite.json text. Never throws: an invalid result carries every\n * validation error so callers can apply the corruption policy (设计 §9) —\n * builtin suites fall back to factory content, user suites fail fast.\n */\nexport function parseSuiteJson(\n\traw: string,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string },\n): SuiteJsonParseResult {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(raw);\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors: [`invalid JSON: ${error instanceof Error ? error.message : String(error)}`],\n\t\t};\n\t}\n\treturn validateSuiteJson(value, options);\n}\n\nexport function validateSuiteJson(\n\tvalue: unknown,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string } = {},\n): SuiteJsonParseResult {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn { valid: false, errors: [\"suite.json must be a JSON object\"] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst errors: string[] = [];\n\n\tif (record.schemaVersion !== SUITE_SCHEMA_VERSION) {\n\t\terrors.push(`schemaVersion must be ${SUITE_SCHEMA_VERSION}, found ${JSON.stringify(record.schemaVersion)}`);\n\t}\n\n\t// Each field keeps a typed local: valid values land here, invalid ones only\n\t// contribute errors. The suite below is constructed exclusively when\n\t// `errors` is empty, so the fallbacks/coercions at that point are dead.\n\tconst idValue = record.id;\n\tconst id = typeof idValue === \"string\" && isValidSuiteId(idValue) ? idValue : undefined;\n\tif (id === undefined) {\n\t\terrors.push(\n\t\t\t`id must be a suite id (^[a-z0-9-]+$, no leading/trailing hyphen, Windows reserved names rejected), found ${JSON.stringify(idValue)}`,\n\t\t);\n\t} else if (options.expectedId !== undefined && id !== options.expectedId) {\n\t\terrors.push(`id \"${id}\" does not match the suite workspace directory id \"${options.expectedId}\"`);\n\t}\n\n\tconst nameValue = record.name;\n\tconst name = typeof nameValue === \"string\" && nameValue.trim().length > 0 ? nameValue : undefined;\n\tif (name === undefined) {\n\t\terrors.push(`name must be a non-empty string, found ${JSON.stringify(nameValue)}`);\n\t}\n\n\tconst builtinValue = record.builtin;\n\tconst builtin = typeof builtinValue === \"boolean\" ? builtinValue : undefined;\n\tif (builtin === undefined) {\n\t\terrors.push(`builtin must be a boolean, found ${JSON.stringify(builtinValue)}`);\n\t} else if (options.expectedBuiltin === true && builtin !== true) {\n\t\terrors.push(`builtin must be true for a builtin suite workspace, found ${builtin}`);\n\t}\n\n\tconst tools = readStringArray(record, \"tools\", errors);\n\tconst capabilities = readStringArray(record, \"capabilities\", errors);\n\tconst associations = readAssociations(record.associations, errors);\n\n\tconst inheritValue = record.inheritSystemAgentsMd;\n\tconst inheritSystemAgentsMd = typeof inheritValue === \"boolean\" ? inheritValue : undefined;\n\tif (inheritSystemAgentsMd === undefined) {\n\t\terrors.push(`inheritSystemAgentsMd must be a boolean, found ${JSON.stringify(inheritValue)}`);\n\t}\n\n\tconst memoryValue = record.memory;\n\tconst memory = memoryValue === \"assistant\" || memoryValue === \"code\" ? memoryValue : undefined;\n\tif (memory === undefined) {\n\t\terrors.push(`memory must be \"assistant\" or \"code\", found ${JSON.stringify(memoryValue)}`);\n\t}\n\n\tconst orientationValue = record.orientation;\n\tconst orientation =\n\t\torientationValue === \"assistant\" || orientationValue === \"coding\" || orientationValue === \"custom\"\n\t\t\t? orientationValue\n\t\t\t: undefined;\n\tif (orientationValue !== undefined && orientation === undefined) {\n\t\terrors.push(`orientation must be \"assistant\", \"coding\", or \"custom\", found ${JSON.stringify(orientationValue)}`);\n\t}\n\n\tconst model = readOptionalString(record, \"model\", errors);\n\tconst thinking = readOptionalString(record, \"thinking\", errors);\n\tconst clonedFrom = readClonedFrom(record.clonedFrom, errors);\n\tconst factoryRevision = readFactoryRevision(record.factoryRevision, options.expectedBuiltin === true, errors);\n\n\tif (errors.length > 0) return { valid: false, errors };\n\n\treturn {\n\t\tvalid: true,\n\t\terrors: [],\n\t\tsuite: {\n\t\t\tschemaVersion: SUITE_SCHEMA_VERSION,\n\t\t\tid: id!,\n\t\t\tname: name!,\n\t\t\tbuiltin: builtin!,\n\t\t\ttools,\n\t\t\tcapabilities,\n\t\t\tassociations,\n\t\t\tinheritSystemAgentsMd: inheritSystemAgentsMd!,\n\t\t\tmemory: memory!,\n\t\t\torientation: orientation ?? \"assistant\",\n\t\t\tmodel,\n\t\t\tthinking,\n\t\t\tclonedFrom,\n\t\t\t...(factoryRevision === undefined ? {} : { factoryRevision }),\n\t\t},\n\t};\n}\n\nfunction readStringArray(record: Record<string, unknown>, key: string, errors: string[]): readonly string[] {\n\tconst value = record[key];\n\tif (!Array.isArray(value)) {\n\t\terrors.push(`${key} must be an array of strings, found ${JSON.stringify(value)}`);\n\t\treturn [];\n\t}\n\tconst entries: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\" || item.trim().length === 0) {\n\t\t\terrors.push(`${key} entries must be non-empty strings, found ${JSON.stringify(item)}`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\terrors.push(`${key} contains duplicate entry \"${item}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tentries.push(item);\n\t}\n\treturn entries;\n}\n\nfunction readAssociations(value: unknown, errors: string[]): SuiteAssociations {\n\tif (value === undefined) return { skills: [], mcp: [], plugins: [], roles: [] };\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(\n\t\t\t`associations must be an object with skills/mcp/plugins/roles arrays, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn { skills: [], mcp: [], plugins: [], roles: [] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\t// A key left out entirely means an empty list, consistent with a fully\n\t// absent `associations` object; a key that is present but malformed still\n\t// reports its errors. The removed legacy `extensions` kind is ignored on\n\t// read (it lost its loader with the old ExtensionAPI surface).\n\treturn {\n\t\tskills: record.skills === undefined ? [] : readStringArray(record, \"skills\", errors),\n\t\tmcp: record.mcp === undefined ? [] : readStringArray(record, \"mcp\", errors),\n\t\tplugins: record.plugins === undefined ? [] : readStringArray(record, \"plugins\", errors),\n\t\troles: record.roles === undefined ? [] : readStringArray(record, \"roles\", errors),\n\t};\n}\n\nfunction readOptionalString(record: Record<string, unknown>, key: string, errors: string[]): string | null {\n\tconst value = record[key];\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\terrors.push(`${key} must be a non-empty string or null, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\treturn value;\n}\n\n/**\n * Reads the optional `factoryRevision` key (M4). A missing key means\n * FACTORY_CONTENTS_VERSION for builtin workspaces (pre-M4 on-disk files stay\n * compatible) and stays absent for user suites (outside factory upgrade\n * governance). A present key must be a positive integer.\n */\nfunction readFactoryRevision(value: unknown, expectedBuiltin: boolean, errors: string[]): number | undefined {\n\tif (value === undefined) return expectedBuiltin ? FACTORY_CONTENTS_VERSION : undefined;\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\terrors.push(`factoryRevision must be a positive integer, found ${JSON.stringify(value)}`);\n\t\treturn undefined;\n\t}\n\treturn value;\n}\n\nfunction readClonedFrom(value: unknown, errors: string[]): SuiteClonedFrom | null {\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(`clonedFrom must be an object with id/digest/at, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\ttypeof record.id !== \"string\" ||\n\t\trecord.id.trim().length === 0 ||\n\t\ttypeof record.digest !== \"string\" ||\n\t\trecord.digest.trim().length === 0 ||\n\t\ttypeof record.at !== \"number\" ||\n\t\t!Number.isSafeInteger(record.at)\n\t) {\n\t\terrors.push(\n\t\t\t`clonedFrom must be an object with non-empty id/digest strings and an integer at, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn null;\n\t}\n\treturn { id: record.id, digest: record.digest, at: record.at };\n}\n"]}
1
+ {"version":3,"file":"builtin-suites.d.ts","sourceRoot":"","sources":["../../src/suites/builtin-suites.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builtin suite (方案) declarations and suite.json (schemaVersion 1)\n * serialization, parsing, and validation — 方案系统设计.md v2 §5/§6/§9, M1a.\n *\n * Suites are pure data plus default policy: both builtin suites share the same\n * unrestricted tool surface and differ only in orientation and memory strategy\n * (the orientation persona text is injected into the system prompt, M2).\n * Nothing here touches the packages/agent kernel; association resolution is\n * declaration-only until M1b.\n */\n\nexport const SUITE_SCHEMA_VERSION = 1;\n\n/**\n * Factory contents revision (M4): the revision of the factory builtin\n * declarations, independent of SUITE_SCHEMA_VERSION. Bump it (and update both\n * builtin declarations' `factoryRevision`) whenever the factory contents\n * change; the registry upgrade proposal then offers `--suite-reset` for\n * workspaces still on an older revision. Suite schema evolution keeps using\n * SUITE_SCHEMA_VERSION.\n *\n * Revision 2 (统一修复轮集成收口, 2026-09-08): assistant and coding now share\n * the same active 8-tool surface in full-control — the sdk `suiteToolOverride`\n * DEFAULT_SUITE_ID exemption was removed (方案设计 §5 + user decision). Existing\n * workspaces provisioned at revision 1 receive the upgrade-proposal diagnostic\n * and adopt via `--suite-reset`.\n *\n * Revision 3 (2026-09-18): `builtin.session-share` joins both builtin suites\n * (开发计划 §216: session-share productized from the example plugin into a\n * first-party default-distributed capability) once the agent-dir config\n * channel for embedded capabilities landed\n * (`<agentDir>/capabilities/<short-id>.json`, see capabilities/builtin.ts).\n * Existing workspaces provisioned at revision 2 receive the upgrade-proposal\n * diagnostic and adopt via `--suite-reset`.\n *\n * Revision 4 (2026-09-18): `builtin.subagent-delegate` joins both builtin\n * suites — the first-party subagent delegation tool (`subagent_run`) now ships\n * by default in shared mode (zero extra processes; pooled runner processes stay\n * opt-in through the capability config channel). Existing workspaces\n * provisioned at revision 3 receive the upgrade-proposal diagnostic and adopt\n * via `--suite-reset`.\n *\n * Revision 5 (2026-09-20): subagent role profiles land on disk only\n * (`<agentDir>/roles/<id>.json` — the factory seeds explore/reviewer and never\n * overwrites user edits) and both builtin suites associate them by default via\n * the new `suite.associations.roles` field, with skill/MCP-isomorphic\n * visibility: unassociated roles stay invisible, associated-but-missing files\n * surface as dangling diagnostics. Existing workspaces provisioned at\n * revision 4 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n *\n * Revision 6 (D-077, 2026-10-02): `builtin.workflow` joins both builtin suites\n * — the workflow orchestration plugin enters the factory bootstrap manifest\n * (ninth package) and the suite capability declaration at goal/plan/todo-set\n * parity, keeping its plugin form. Existing workspaces provisioned at revision\n * 5 receive the upgrade-proposal diagnostic and adopt via `--suite-reset`.\n *\n * Revision 7 (视觉保底, 2026-10-04): the two visual baseline roles\n * `design-proposer` / `visual-reviewer` join the factory seeds and the default\n * `associations.roles` (user ruling \"术有专攻、角色隔离\"; role files are\n * disk-only and the seeds never overwrite user edits — see\n * `docs/plans/视觉保底角色设计注记.md`). Existing workspaces provisioned at\n * revision 6 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n */\nexport const FACTORY_CONTENTS_VERSION = 7;\n\n/**\n * Factory default suite used when no suite is configured anywhere (设计 §9).\n * 2026-10-02 user ruling: the product is a coding agent, so the factory\n * default flipped from \"assistant\" to \"coding\"; assistant stays as the\n * explicit-switch fallback suite.\n */\nexport const DEFAULT_SUITE_ID = \"coding\";\n\n/** Suite ids become directory names: lowercase letters, digits, hyphens (设计 §9). */\nexport const SUITE_ID_MAX_LENGTH = 64;\n\n/** The single unrestricted tool surface shared by both builtin suites (设计 §5/§6). */\nexport const BUILTIN_SUITE_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"write\",\n\t\"edit\",\n\t\"bash\",\n\t\"ls\",\n\t\"find\",\n\t\"grep\",\n\t\"powershell\",\n];\n\n/**\n * Builtin capability plugins associated with both suites. Declaration-only\n * data in M1a; the actual plugin wiring is delivered in M3. `builtin.memory`\n * joins in the 统一修复轮 A 路 (方案系统设计 §6.1: both suites share the same\n * memory tool surface; the strategy difference lives in the suiteId domain\n * isolation and the assistant preference card). `builtin.session-share` joins\n * in the session-share productization slice (开发计划 §216); its\n * target/gateway/viewerUrl are configured through the agent-dir config\n * channel (`<agentDir>/capabilities/builtin.session-share.json`), and the\n * unconfigured default answers `/share` with the explicit configuration\n * prompt — never an implicit Radius/Gist fallback. `builtin.workflow` joins\n * at goal/plan/todo-set parity (D-077, 2026-10-02: factory default install\n * plus this suite declaration, plugin form unchanged). `builtin.coding-tools`\n * joins with the D-082 batch-1 tool split (2026-10-03): the default coding\n * tools assemble from the `plugins/coding-tools` package through the bundled\n * distribution channel (插件独立分发与启动装配设计 §4.9), not the install\n * store.\n */\nexport const BUILTIN_SUITE_CAPABILITIES: readonly string[] = [\n\t\"builtin.goal\",\n\t\"builtin.plan\",\n\t\"builtin.todo-set\",\n\t\"builtin.workflow\",\n\t\"builtin.memory\",\n\t\"builtin.session-share\",\n\t\"builtin.subagent-delegate\",\n\t\"builtin.coding-tools\",\n];\n\nexport type SuiteMemoryStrategy = \"assistant\" | \"code\";\nexport type SuiteOrientation = \"assistant\" | \"coding\" | \"custom\";\n\n/**\n * Orientation persona texts injected into the system prompt (设计 §6.2, M2).\n * The strings are verbatim from the design spec: the assistant persona is the\n * companion style, the coding persona is the rigor-first style. Both are\n * session-nature declarations, so they ride every system prompt branch\n * (default and customPrompt). The custom orientation is not in this table: its\n * persona text comes from the suite workspace persona.md (设计 §6.3, resolved\n * by suite-loader).\n */\nexport const ORIENTATION_PROMPTS: Record<\"assistant\" | \"coding\", string> = {\n\tassistant: `You are the user's thoughtful companion — warm, patient, and helpful.\n- Understand the intent behind the question, including the unspoken parts; when something that matters is ambiguous, ask one short clarifying question instead of assuming.\n- Pay attention to detail: notice what the user might have missed and gently point it out.\n- Be proactive and divergent: after answering, offer next steps, related ideas, or creative alternatives — without being pushy.\n- Adapt tone to the user; stay natural and flexible, never robotic or formulaic.\n- When you can help by doing, act through tools autonomously (minimal interruption).\n- Structure longer answers clearly: short paragraphs, lists where they help, and a concrete \"what you can do next\" at the end.`,\n\tcoding: `You are an autonomous software engineering agent with a rigor-first mindset.\n- Never guess. Ground every claim in code you have read, commands you have run, or documented evidence; cite file paths and line numbers. If the evidence is insufficient, investigate, and report what is unverified — or \"unknown\" — instead of a plausible invention.\n- First principles: trace problems to the earliest reasonable root cause and fix that; do not patch symptoms.\n- No over-engineering: add no abstraction, options, or defensive handling for imagined future needs; generalise only when a second concrete case demands it.\n- Tests first: pin expected behavior with a failing or updated test before or alongside the fix, then run the smallest sufficient relevant checks; the work is not done until they pass.\n- Reproducible: prefer deterministic tests and mocks over ad-hoc verification, and report the exact commands and results so others can re-run them.\n- Docs as code: follow the repository's documentation conventions; where the project treats design docs, READMEs, and changelogs as part of the change, keep them consistent with the behavior they describe.\n- Self-review before finishing: re-check your changes for correctness, edge cases, regressions, and missing tests; prefer a second review pass over shipping the first draft.\n- Cautious: weigh side effects, compatibility, and failure modes; when in doubt, gather evidence and verify before changing — doubt is never resolved by making the fix smaller.`,\n};\n\nexport interface SuiteAssociations {\n\treadonly skills: readonly string[];\n\treadonly mcp: readonly string[];\n\treadonly plugins: readonly string[];\n\t/**\n\t * 子代理角色关联(D-044 角色机制):关联的是 `<agentDir>/roles/<id>.json` 里的角色 id。\n\t * 角色定义只在磁盘上(工厂仅做种子落盘),方案只决定哪些角色对主代理可见——与\n\t * skill/MCP/插件同构,第一方与第三方角色没有区别。\n\t */\n\treadonly roles: readonly string[];\n}\n\nexport interface SuiteClonedFrom {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly at: number;\n}\n\n/** The serializable suite definition persisted as suite.json (设计 §5). */\nexport interface SuiteDefinition {\n\treadonly schemaVersion: number;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly builtin: boolean;\n\treadonly tools: readonly string[];\n\treadonly capabilities: readonly string[];\n\treadonly associations: SuiteAssociations;\n\treadonly inheritSystemAgentsMd: boolean;\n\treadonly memory: SuiteMemoryStrategy;\n\treadonly orientation: SuiteOrientation;\n\treadonly model: string | null;\n\treadonly thinking: string | null;\n\treadonly clonedFrom: SuiteClonedFrom | null;\n\t/**\n\t * Factory contents revision this declaration was written at (M4). Builtin\n\t * declarations carry it; on-disk builtin suite.json may omit it (pre-M4\n\t * files parse as FACTORY_CONTENTS_VERSION). User suites are outside factory\n\t * upgrade governance: the key stays optional and may be absent.\n\t */\n\treadonly factoryRevision?: number;\n}\n\nconst EMPTY_ASSOCIATIONS: SuiteAssociations = { skills: [], mcp: [], plugins: [], roles: [] };\n\n/**\n * 默认方案关联的子代理角色(开箱即用):这四个 id 对应工厂种子落盘的四个普通角色文件\n * (`<agentDir>/roles/{explore,reviewer,design-proposer,visual-reviewer}.json`,用户可改可删)。\n * design-proposer / visual-reviewer 是视觉保底角色(2026-10-04 用户裁决\"术有专攻、角色隔离\"),\n * 档案 readonly + 只读工具收窄,与编码角色结构性隔离——见 docs/plans/视觉保底角色设计注记.md。\n * 工厂不在运行期回退到任何编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\n\t\"explore\",\n\t\"reviewer\",\n\t\"design-proposer\",\n\t\"visual-reviewer\",\n];\n\nconst assistantSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"assistant\",\n\tname: \"Assistant\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"assistant\",\n\torientation: \"assistant\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\nconst codingSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"coding\",\n\tname: \"Coding\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"code\",\n\torientation: \"coding\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\n/** The factory builtin pair: coding (factory default 尖刀) and assistant (fallback). */\nexport const BUILTIN_SUITES: readonly SuiteDefinition[] = [assistantSuite, codingSuite];\n\nexport function getBuiltinSuite(id: string): SuiteDefinition | undefined {\n\treturn BUILTIN_SUITES.find((suite) => suite.id === id);\n}\n\nexport function isBuiltinSuiteId(id: string): boolean {\n\treturn BUILTIN_SUITES.some((suite) => suite.id === id);\n}\n\nconst WINDOWS_RESERVED_IDS = new Set([\n\t\"con\",\n\t\"prn\",\n\t\"aux\",\n\t\"nul\",\n\t\"com1\",\n\t\"com2\",\n\t\"com3\",\n\t\"com4\",\n\t\"com5\",\n\t\"com6\",\n\t\"com7\",\n\t\"com8\",\n\t\"com9\",\n\t\"lpt1\",\n\t\"lpt2\",\n\t\"lpt3\",\n\t\"lpt4\",\n\t\"lpt5\",\n\t\"lpt6\",\n\t\"lpt7\",\n\t\"lpt8\",\n\t\"lpt9\",\n\t\"conin$\",\n\t\"conout$\",\n]);\n\n/** Suite id rule (设计 §9): `a-z0-9-`, no leading/trailing hyphen, no Windows reserved names. */\nexport function isValidSuiteId(id: string): boolean {\n\tif (id.length === 0 || id.length > SUITE_ID_MAX_LENGTH) return false;\n\tif (!/^[a-z0-9-]+$/.test(id)) return false;\n\tif (id.startsWith(\"-\") || id.endsWith(\"-\")) return false;\n\tif (WINDOWS_RESERVED_IDS.has(id)) return false;\n\treturn true;\n}\n\n/** Serializes a suite to the canonical suite.json text (stable field order, trailing newline). */\nexport function serializeSuiteJson(suite: SuiteDefinition): string {\n\tconst ordered = {\n\t\tschemaVersion: suite.schemaVersion,\n\t\tid: suite.id,\n\t\tname: suite.name,\n\t\tbuiltin: suite.builtin,\n\t\ttools: [...suite.tools],\n\t\tcapabilities: [...suite.capabilities],\n\t\tassociations: {\n\t\t\tskills: [...suite.associations.skills],\n\t\t\tmcp: [...suite.associations.mcp],\n\t\t\tplugins: [...suite.associations.plugins],\n\t\t\troles: [...suite.associations.roles],\n\t\t},\n\t\tinheritSystemAgentsMd: suite.inheritSystemAgentsMd,\n\t\tmemory: suite.memory,\n\t\torientation: suite.orientation,\n\t\tmodel: suite.model,\n\t\tthinking: suite.thinking,\n\t\tclonedFrom: suite.clonedFrom\n\t\t\t? { id: suite.clonedFrom.id, digest: suite.clonedFrom.digest, at: suite.clonedFrom.at }\n\t\t\t: null,\n\t\tfactoryRevision: suite.factoryRevision,\n\t};\n\treturn `${JSON.stringify(ordered, null, 2)}\\n`;\n}\n\nexport interface SuiteJsonParseResult {\n\treadonly valid: boolean;\n\treadonly suite?: SuiteDefinition;\n\treadonly errors: readonly string[];\n}\n\n/**\n * Parses suite.json text. Never throws: an invalid result carries every\n * validation error so callers can apply the corruption policy (设计 §9) —\n * builtin suites fall back to factory content, user suites fail fast.\n */\nexport function parseSuiteJson(\n\traw: string,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string },\n): SuiteJsonParseResult {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(raw);\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors: [`invalid JSON: ${error instanceof Error ? error.message : String(error)}`],\n\t\t};\n\t}\n\treturn validateSuiteJson(value, options);\n}\n\nexport function validateSuiteJson(\n\tvalue: unknown,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string } = {},\n): SuiteJsonParseResult {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn { valid: false, errors: [\"suite.json must be a JSON object\"] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst errors: string[] = [];\n\n\tif (record.schemaVersion !== SUITE_SCHEMA_VERSION) {\n\t\terrors.push(`schemaVersion must be ${SUITE_SCHEMA_VERSION}, found ${JSON.stringify(record.schemaVersion)}`);\n\t}\n\n\t// Each field keeps a typed local: valid values land here, invalid ones only\n\t// contribute errors. The suite below is constructed exclusively when\n\t// `errors` is empty, so the fallbacks/coercions at that point are dead.\n\tconst idValue = record.id;\n\tconst id = typeof idValue === \"string\" && isValidSuiteId(idValue) ? idValue : undefined;\n\tif (id === undefined) {\n\t\terrors.push(\n\t\t\t`id must be a suite id (^[a-z0-9-]+$, no leading/trailing hyphen, Windows reserved names rejected), found ${JSON.stringify(idValue)}`,\n\t\t);\n\t} else if (options.expectedId !== undefined && id !== options.expectedId) {\n\t\terrors.push(`id \"${id}\" does not match the suite workspace directory id \"${options.expectedId}\"`);\n\t}\n\n\tconst nameValue = record.name;\n\tconst name = typeof nameValue === \"string\" && nameValue.trim().length > 0 ? nameValue : undefined;\n\tif (name === undefined) {\n\t\terrors.push(`name must be a non-empty string, found ${JSON.stringify(nameValue)}`);\n\t}\n\n\tconst builtinValue = record.builtin;\n\tconst builtin = typeof builtinValue === \"boolean\" ? builtinValue : undefined;\n\tif (builtin === undefined) {\n\t\terrors.push(`builtin must be a boolean, found ${JSON.stringify(builtinValue)}`);\n\t} else if (options.expectedBuiltin === true && builtin !== true) {\n\t\terrors.push(`builtin must be true for a builtin suite workspace, found ${builtin}`);\n\t}\n\n\tconst tools = readStringArray(record, \"tools\", errors);\n\tconst capabilities = readStringArray(record, \"capabilities\", errors);\n\tconst associations = readAssociations(record.associations, errors);\n\n\tconst inheritValue = record.inheritSystemAgentsMd;\n\tconst inheritSystemAgentsMd = typeof inheritValue === \"boolean\" ? inheritValue : undefined;\n\tif (inheritSystemAgentsMd === undefined) {\n\t\terrors.push(`inheritSystemAgentsMd must be a boolean, found ${JSON.stringify(inheritValue)}`);\n\t}\n\n\tconst memoryValue = record.memory;\n\tconst memory = memoryValue === \"assistant\" || memoryValue === \"code\" ? memoryValue : undefined;\n\tif (memory === undefined) {\n\t\terrors.push(`memory must be \"assistant\" or \"code\", found ${JSON.stringify(memoryValue)}`);\n\t}\n\n\tconst orientationValue = record.orientation;\n\tconst orientation =\n\t\torientationValue === \"assistant\" || orientationValue === \"coding\" || orientationValue === \"custom\"\n\t\t\t? orientationValue\n\t\t\t: undefined;\n\tif (orientationValue !== undefined && orientation === undefined) {\n\t\terrors.push(`orientation must be \"assistant\", \"coding\", or \"custom\", found ${JSON.stringify(orientationValue)}`);\n\t}\n\n\tconst model = readOptionalString(record, \"model\", errors);\n\tconst thinking = readOptionalString(record, \"thinking\", errors);\n\tconst clonedFrom = readClonedFrom(record.clonedFrom, errors);\n\tconst factoryRevision = readFactoryRevision(record.factoryRevision, options.expectedBuiltin === true, errors);\n\n\tif (errors.length > 0) return { valid: false, errors };\n\n\treturn {\n\t\tvalid: true,\n\t\terrors: [],\n\t\tsuite: {\n\t\t\tschemaVersion: SUITE_SCHEMA_VERSION,\n\t\t\tid: id!,\n\t\t\tname: name!,\n\t\t\tbuiltin: builtin!,\n\t\t\ttools,\n\t\t\tcapabilities,\n\t\t\tassociations,\n\t\t\tinheritSystemAgentsMd: inheritSystemAgentsMd!,\n\t\t\tmemory: memory!,\n\t\t\torientation: orientation ?? \"assistant\",\n\t\t\tmodel,\n\t\t\tthinking,\n\t\t\tclonedFrom,\n\t\t\t...(factoryRevision === undefined ? {} : { factoryRevision }),\n\t\t},\n\t};\n}\n\nfunction readStringArray(record: Record<string, unknown>, key: string, errors: string[]): readonly string[] {\n\tconst value = record[key];\n\tif (!Array.isArray(value)) {\n\t\terrors.push(`${key} must be an array of strings, found ${JSON.stringify(value)}`);\n\t\treturn [];\n\t}\n\tconst entries: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\" || item.trim().length === 0) {\n\t\t\terrors.push(`${key} entries must be non-empty strings, found ${JSON.stringify(item)}`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\terrors.push(`${key} contains duplicate entry \"${item}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tentries.push(item);\n\t}\n\treturn entries;\n}\n\nfunction readAssociations(value: unknown, errors: string[]): SuiteAssociations {\n\tif (value === undefined) return { skills: [], mcp: [], plugins: [], roles: [] };\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(\n\t\t\t`associations must be an object with skills/mcp/plugins/roles arrays, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn { skills: [], mcp: [], plugins: [], roles: [] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\t// A key left out entirely means an empty list, consistent with a fully\n\t// absent `associations` object; a key that is present but malformed still\n\t// reports its errors. The removed legacy `extensions` kind is ignored on\n\t// read (it lost its loader with the old ExtensionAPI surface).\n\treturn {\n\t\tskills: record.skills === undefined ? [] : readStringArray(record, \"skills\", errors),\n\t\tmcp: record.mcp === undefined ? [] : readStringArray(record, \"mcp\", errors),\n\t\tplugins: record.plugins === undefined ? [] : readStringArray(record, \"plugins\", errors),\n\t\troles: record.roles === undefined ? [] : readStringArray(record, \"roles\", errors),\n\t};\n}\n\nfunction readOptionalString(record: Record<string, unknown>, key: string, errors: string[]): string | null {\n\tconst value = record[key];\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\terrors.push(`${key} must be a non-empty string or null, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\treturn value;\n}\n\n/**\n * Reads the optional `factoryRevision` key (M4). A missing key means\n * FACTORY_CONTENTS_VERSION for builtin workspaces (pre-M4 on-disk files stay\n * compatible) and stays absent for user suites (outside factory upgrade\n * governance). A present key must be a positive integer.\n */\nfunction readFactoryRevision(value: unknown, expectedBuiltin: boolean, errors: string[]): number | undefined {\n\tif (value === undefined) return expectedBuiltin ? FACTORY_CONTENTS_VERSION : undefined;\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\terrors.push(`factoryRevision must be a positive integer, found ${JSON.stringify(value)}`);\n\t\treturn undefined;\n\t}\n\treturn value;\n}\n\nfunction readClonedFrom(value: unknown, errors: string[]): SuiteClonedFrom | null {\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(`clonedFrom must be an object with id/digest/at, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\ttypeof record.id !== \"string\" ||\n\t\trecord.id.trim().length === 0 ||\n\t\ttypeof record.digest !== \"string\" ||\n\t\trecord.digest.trim().length === 0 ||\n\t\ttypeof record.at !== \"number\" ||\n\t\t!Number.isSafeInteger(record.at)\n\t) {\n\t\terrors.push(\n\t\t\t`clonedFrom must be an object with non-empty id/digest strings and an integer at, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn null;\n\t}\n\treturn { id: record.id, digest: record.digest, at: record.at };\n}\n"]}
@@ -133,9 +133,9 @@ export const ORIENTATION_PROMPTS = {
133
133
  - No over-engineering: add no abstraction, options, or defensive handling for imagined future needs; generalise only when a second concrete case demands it.
134
134
  - Tests first: pin expected behavior with a failing or updated test before or alongside the fix, then run the smallest sufficient relevant checks; the work is not done until they pass.
135
135
  - Reproducible: prefer deterministic tests and mocks over ad-hoc verification, and report the exact commands and results so others can re-run them.
136
- - Docs as code: repository documentation is part of the change — keep design docs, READMEs, and changelogs consistent with the behavior they describe.
136
+ - Docs as code: follow the repository's documentation conventions; where the project treats design docs, READMEs, and changelogs as part of the change, keep them consistent with the behavior they describe.
137
137
  - Self-review before finishing: re-check your changes for correctness, edge cases, regressions, and missing tests; prefer a second review pass over shipping the first draft.
138
- - Cautious: weigh side effects, compatibility, and failure modes; when in doubt, take the safer path.`,
138
+ - Cautious: weigh side effects, compatibility, and failure modes; when in doubt, gather evidence and verify before changing — doubt is never resolved by making the fix smaller.`,
139
139
  };
140
140
  const EMPTY_ASSOCIATIONS = { skills: [], mcp: [], plugins: [], roles: [] };
141
141
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-suites.js","sourceRoot":"","sources":["../../src/suites/builtin-suites.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builtin suite (方案) declarations and suite.json (schemaVersion 1)\n * serialization, parsing, and validation — 方案系统设计.md v2 §5/§6/§9, M1a.\n *\n * Suites are pure data plus default policy: both builtin suites share the same\n * unrestricted tool surface and differ only in orientation and memory strategy\n * (the orientation persona text is injected into the system prompt, M2).\n * Nothing here touches the packages/agent kernel; association resolution is\n * declaration-only until M1b.\n */\n\nexport const SUITE_SCHEMA_VERSION = 1;\n\n/**\n * Factory contents revision (M4): the revision of the factory builtin\n * declarations, independent of SUITE_SCHEMA_VERSION. Bump it (and update both\n * builtin declarations' `factoryRevision`) whenever the factory contents\n * change; the registry upgrade proposal then offers `--suite-reset` for\n * workspaces still on an older revision. Suite schema evolution keeps using\n * SUITE_SCHEMA_VERSION.\n *\n * Revision 2 (统一修复轮集成收口, 2026-09-08): assistant and coding now share\n * the same active 8-tool surface in full-control — the sdk `suiteToolOverride`\n * DEFAULT_SUITE_ID exemption was removed (方案设计 §5 + user decision). Existing\n * workspaces provisioned at revision 1 receive the upgrade-proposal diagnostic\n * and adopt via `--suite-reset`.\n *\n * Revision 3 (2026-09-18): `builtin.session-share` joins both builtin suites\n * (开发计划 §216: session-share productized from the example plugin into a\n * first-party default-distributed capability) once the agent-dir config\n * channel for embedded capabilities landed\n * (`<agentDir>/capabilities/<short-id>.json`, see capabilities/builtin.ts).\n * Existing workspaces provisioned at revision 2 receive the upgrade-proposal\n * diagnostic and adopt via `--suite-reset`.\n *\n * Revision 4 (2026-09-18): `builtin.subagent-delegate` joins both builtin\n * suites — the first-party subagent delegation tool (`subagent_run`) now ships\n * by default in shared mode (zero extra processes; pooled runner processes stay\n * opt-in through the capability config channel). Existing workspaces\n * provisioned at revision 3 receive the upgrade-proposal diagnostic and adopt\n * via `--suite-reset`.\n *\n * Revision 5 (2026-09-20): subagent role profiles land on disk only\n * (`<agentDir>/roles/<id>.json` — the factory seeds explore/reviewer and never\n * overwrites user edits) and both builtin suites associate them by default via\n * the new `suite.associations.roles` field, with skill/MCP-isomorphic\n * visibility: unassociated roles stay invisible, associated-but-missing files\n * surface as dangling diagnostics. Existing workspaces provisioned at\n * revision 4 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n *\n * Revision 6 (D-077, 2026-10-02): `builtin.workflow` joins both builtin suites\n * — the workflow orchestration plugin enters the factory bootstrap manifest\n * (ninth package) and the suite capability declaration at goal/plan/todo-set\n * parity, keeping its plugin form. Existing workspaces provisioned at revision\n * 5 receive the upgrade-proposal diagnostic and adopt via `--suite-reset`.\n *\n * Revision 7 (视觉保底, 2026-10-04): the two visual baseline roles\n * `design-proposer` / `visual-reviewer` join the factory seeds and the default\n * `associations.roles` (user ruling \"术有专攻、角色隔离\"; role files are\n * disk-only and the seeds never overwrite user edits — see\n * `docs/plans/视觉保底角色设计注记.md`). Existing workspaces provisioned at\n * revision 6 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n */\nexport const FACTORY_CONTENTS_VERSION = 7;\n\n/**\n * Factory default suite used when no suite is configured anywhere (设计 §9).\n * 2026-10-02 user ruling: the product is a coding agent, so the factory\n * default flipped from \"assistant\" to \"coding\"; assistant stays as the\n * explicit-switch fallback suite.\n */\nexport const DEFAULT_SUITE_ID = \"coding\";\n\n/** Suite ids become directory names: lowercase letters, digits, hyphens (设计 §9). */\nexport const SUITE_ID_MAX_LENGTH = 64;\n\n/** The single unrestricted tool surface shared by both builtin suites (设计 §5/§6). */\nexport const BUILTIN_SUITE_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"write\",\n\t\"edit\",\n\t\"bash\",\n\t\"ls\",\n\t\"find\",\n\t\"grep\",\n\t\"powershell\",\n];\n\n/**\n * Builtin capability plugins associated with both suites. Declaration-only\n * data in M1a; the actual plugin wiring is delivered in M3. `builtin.memory`\n * joins in the 统一修复轮 A 路 (方案系统设计 §6.1: both suites share the same\n * memory tool surface; the strategy difference lives in the suiteId domain\n * isolation and the assistant preference card). `builtin.session-share` joins\n * in the session-share productization slice (开发计划 §216); its\n * target/gateway/viewerUrl are configured through the agent-dir config\n * channel (`<agentDir>/capabilities/builtin.session-share.json`), and the\n * unconfigured default answers `/share` with the explicit configuration\n * prompt — never an implicit Radius/Gist fallback. `builtin.workflow` joins\n * at goal/plan/todo-set parity (D-077, 2026-10-02: factory default install\n * plus this suite declaration, plugin form unchanged). `builtin.coding-tools`\n * joins with the D-082 batch-1 tool split (2026-10-03): the default coding\n * tools assemble from the `plugins/coding-tools` package through the bundled\n * distribution channel (插件独立分发与启动装配设计 §4.9), not the install\n * store.\n */\nexport const BUILTIN_SUITE_CAPABILITIES: readonly string[] = [\n\t\"builtin.goal\",\n\t\"builtin.plan\",\n\t\"builtin.todo-set\",\n\t\"builtin.workflow\",\n\t\"builtin.memory\",\n\t\"builtin.session-share\",\n\t\"builtin.subagent-delegate\",\n\t\"builtin.coding-tools\",\n];\n\nexport type SuiteMemoryStrategy = \"assistant\" | \"code\";\nexport type SuiteOrientation = \"assistant\" | \"coding\" | \"custom\";\n\n/**\n * Orientation persona texts injected into the system prompt (设计 §6.2, M2).\n * The strings are verbatim from the design spec: the assistant persona is the\n * companion style, the coding persona is the rigor-first style. Both are\n * session-nature declarations, so they ride every system prompt branch\n * (default and customPrompt). The custom orientation is not in this table: its\n * persona text comes from the suite workspace persona.md (设计 §6.3, resolved\n * by suite-loader).\n */\nexport const ORIENTATION_PROMPTS: Record<\"assistant\" | \"coding\", string> = {\n\tassistant: `You are the user's thoughtful companion — warm, patient, and helpful.\n- Understand the intent behind the question, including the unspoken parts; when something that matters is ambiguous, ask one short clarifying question instead of assuming.\n- Pay attention to detail: notice what the user might have missed and gently point it out.\n- Be proactive and divergent: after answering, offer next steps, related ideas, or creative alternatives — without being pushy.\n- Adapt tone to the user; stay natural and flexible, never robotic or formulaic.\n- When you can help by doing, act through tools autonomously (minimal interruption).\n- Structure longer answers clearly: short paragraphs, lists where they help, and a concrete \"what you can do next\" at the end.`,\n\tcoding: `You are an autonomous software engineering agent with a rigor-first mindset.\n- Never guess. Ground every claim in code you have read, commands you have run, or documented evidence; cite file paths and line numbers. If the evidence is insufficient, investigate, and report what is unverified — or \"unknown\" — instead of a plausible invention.\n- First principles: trace problems to the earliest reasonable root cause and fix that; do not patch symptoms.\n- No over-engineering: add no abstraction, options, or defensive handling for imagined future needs; generalise only when a second concrete case demands it.\n- Tests first: pin expected behavior with a failing or updated test before or alongside the fix, then run the smallest sufficient relevant checks; the work is not done until they pass.\n- Reproducible: prefer deterministic tests and mocks over ad-hoc verification, and report the exact commands and results so others can re-run them.\n- Docs as code: repository documentation is part of the change — keep design docs, READMEs, and changelogs consistent with the behavior they describe.\n- Self-review before finishing: re-check your changes for correctness, edge cases, regressions, and missing tests; prefer a second review pass over shipping the first draft.\n- Cautious: weigh side effects, compatibility, and failure modes; when in doubt, take the safer path.`,\n};\n\nexport interface SuiteAssociations {\n\treadonly skills: readonly string[];\n\treadonly mcp: readonly string[];\n\treadonly plugins: readonly string[];\n\t/**\n\t * 子代理角色关联(D-044 角色机制):关联的是 `<agentDir>/roles/<id>.json` 里的角色 id。\n\t * 角色定义只在磁盘上(工厂仅做种子落盘),方案只决定哪些角色对主代理可见——与\n\t * skill/MCP/插件同构,第一方与第三方角色没有区别。\n\t */\n\treadonly roles: readonly string[];\n}\n\nexport interface SuiteClonedFrom {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly at: number;\n}\n\n/** The serializable suite definition persisted as suite.json (设计 §5). */\nexport interface SuiteDefinition {\n\treadonly schemaVersion: number;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly builtin: boolean;\n\treadonly tools: readonly string[];\n\treadonly capabilities: readonly string[];\n\treadonly associations: SuiteAssociations;\n\treadonly inheritSystemAgentsMd: boolean;\n\treadonly memory: SuiteMemoryStrategy;\n\treadonly orientation: SuiteOrientation;\n\treadonly model: string | null;\n\treadonly thinking: string | null;\n\treadonly clonedFrom: SuiteClonedFrom | null;\n\t/**\n\t * Factory contents revision this declaration was written at (M4). Builtin\n\t * declarations carry it; on-disk builtin suite.json may omit it (pre-M4\n\t * files parse as FACTORY_CONTENTS_VERSION). User suites are outside factory\n\t * upgrade governance: the key stays optional and may be absent.\n\t */\n\treadonly factoryRevision?: number;\n}\n\nconst EMPTY_ASSOCIATIONS: SuiteAssociations = { skills: [], mcp: [], plugins: [], roles: [] };\n\n/**\n * 默认方案关联的子代理角色(开箱即用):这四个 id 对应工厂种子落盘的四个普通角色文件\n * (`<agentDir>/roles/{explore,reviewer,design-proposer,visual-reviewer}.json`,用户可改可删)。\n * design-proposer / visual-reviewer 是视觉保底角色(2026-10-04 用户裁决\"术有专攻、角色隔离\"),\n * 档案 readonly + 只读工具收窄,与编码角色结构性隔离——见 docs/plans/视觉保底角色设计注记.md。\n * 工厂不在运行期回退到任何编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\n\t\"explore\",\n\t\"reviewer\",\n\t\"design-proposer\",\n\t\"visual-reviewer\",\n];\n\nconst assistantSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"assistant\",\n\tname: \"Assistant\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"assistant\",\n\torientation: \"assistant\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\nconst codingSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"coding\",\n\tname: \"Coding\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"code\",\n\torientation: \"coding\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\n/** The factory builtin pair: coding (factory default 尖刀) and assistant (fallback). */\nexport const BUILTIN_SUITES: readonly SuiteDefinition[] = [assistantSuite, codingSuite];\n\nexport function getBuiltinSuite(id: string): SuiteDefinition | undefined {\n\treturn BUILTIN_SUITES.find((suite) => suite.id === id);\n}\n\nexport function isBuiltinSuiteId(id: string): boolean {\n\treturn BUILTIN_SUITES.some((suite) => suite.id === id);\n}\n\nconst WINDOWS_RESERVED_IDS = new Set([\n\t\"con\",\n\t\"prn\",\n\t\"aux\",\n\t\"nul\",\n\t\"com1\",\n\t\"com2\",\n\t\"com3\",\n\t\"com4\",\n\t\"com5\",\n\t\"com6\",\n\t\"com7\",\n\t\"com8\",\n\t\"com9\",\n\t\"lpt1\",\n\t\"lpt2\",\n\t\"lpt3\",\n\t\"lpt4\",\n\t\"lpt5\",\n\t\"lpt6\",\n\t\"lpt7\",\n\t\"lpt8\",\n\t\"lpt9\",\n\t\"conin$\",\n\t\"conout$\",\n]);\n\n/** Suite id rule (设计 §9): `a-z0-9-`, no leading/trailing hyphen, no Windows reserved names. */\nexport function isValidSuiteId(id: string): boolean {\n\tif (id.length === 0 || id.length > SUITE_ID_MAX_LENGTH) return false;\n\tif (!/^[a-z0-9-]+$/.test(id)) return false;\n\tif (id.startsWith(\"-\") || id.endsWith(\"-\")) return false;\n\tif (WINDOWS_RESERVED_IDS.has(id)) return false;\n\treturn true;\n}\n\n/** Serializes a suite to the canonical suite.json text (stable field order, trailing newline). */\nexport function serializeSuiteJson(suite: SuiteDefinition): string {\n\tconst ordered = {\n\t\tschemaVersion: suite.schemaVersion,\n\t\tid: suite.id,\n\t\tname: suite.name,\n\t\tbuiltin: suite.builtin,\n\t\ttools: [...suite.tools],\n\t\tcapabilities: [...suite.capabilities],\n\t\tassociations: {\n\t\t\tskills: [...suite.associations.skills],\n\t\t\tmcp: [...suite.associations.mcp],\n\t\t\tplugins: [...suite.associations.plugins],\n\t\t\troles: [...suite.associations.roles],\n\t\t},\n\t\tinheritSystemAgentsMd: suite.inheritSystemAgentsMd,\n\t\tmemory: suite.memory,\n\t\torientation: suite.orientation,\n\t\tmodel: suite.model,\n\t\tthinking: suite.thinking,\n\t\tclonedFrom: suite.clonedFrom\n\t\t\t? { id: suite.clonedFrom.id, digest: suite.clonedFrom.digest, at: suite.clonedFrom.at }\n\t\t\t: null,\n\t\tfactoryRevision: suite.factoryRevision,\n\t};\n\treturn `${JSON.stringify(ordered, null, 2)}\\n`;\n}\n\nexport interface SuiteJsonParseResult {\n\treadonly valid: boolean;\n\treadonly suite?: SuiteDefinition;\n\treadonly errors: readonly string[];\n}\n\n/**\n * Parses suite.json text. Never throws: an invalid result carries every\n * validation error so callers can apply the corruption policy (设计 §9) —\n * builtin suites fall back to factory content, user suites fail fast.\n */\nexport function parseSuiteJson(\n\traw: string,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string },\n): SuiteJsonParseResult {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(raw);\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors: [`invalid JSON: ${error instanceof Error ? error.message : String(error)}`],\n\t\t};\n\t}\n\treturn validateSuiteJson(value, options);\n}\n\nexport function validateSuiteJson(\n\tvalue: unknown,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string } = {},\n): SuiteJsonParseResult {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn { valid: false, errors: [\"suite.json must be a JSON object\"] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst errors: string[] = [];\n\n\tif (record.schemaVersion !== SUITE_SCHEMA_VERSION) {\n\t\terrors.push(`schemaVersion must be ${SUITE_SCHEMA_VERSION}, found ${JSON.stringify(record.schemaVersion)}`);\n\t}\n\n\t// Each field keeps a typed local: valid values land here, invalid ones only\n\t// contribute errors. The suite below is constructed exclusively when\n\t// `errors` is empty, so the fallbacks/coercions at that point are dead.\n\tconst idValue = record.id;\n\tconst id = typeof idValue === \"string\" && isValidSuiteId(idValue) ? idValue : undefined;\n\tif (id === undefined) {\n\t\terrors.push(\n\t\t\t`id must be a suite id (^[a-z0-9-]+$, no leading/trailing hyphen, Windows reserved names rejected), found ${JSON.stringify(idValue)}`,\n\t\t);\n\t} else if (options.expectedId !== undefined && id !== options.expectedId) {\n\t\terrors.push(`id \"${id}\" does not match the suite workspace directory id \"${options.expectedId}\"`);\n\t}\n\n\tconst nameValue = record.name;\n\tconst name = typeof nameValue === \"string\" && nameValue.trim().length > 0 ? nameValue : undefined;\n\tif (name === undefined) {\n\t\terrors.push(`name must be a non-empty string, found ${JSON.stringify(nameValue)}`);\n\t}\n\n\tconst builtinValue = record.builtin;\n\tconst builtin = typeof builtinValue === \"boolean\" ? builtinValue : undefined;\n\tif (builtin === undefined) {\n\t\terrors.push(`builtin must be a boolean, found ${JSON.stringify(builtinValue)}`);\n\t} else if (options.expectedBuiltin === true && builtin !== true) {\n\t\terrors.push(`builtin must be true for a builtin suite workspace, found ${builtin}`);\n\t}\n\n\tconst tools = readStringArray(record, \"tools\", errors);\n\tconst capabilities = readStringArray(record, \"capabilities\", errors);\n\tconst associations = readAssociations(record.associations, errors);\n\n\tconst inheritValue = record.inheritSystemAgentsMd;\n\tconst inheritSystemAgentsMd = typeof inheritValue === \"boolean\" ? inheritValue : undefined;\n\tif (inheritSystemAgentsMd === undefined) {\n\t\terrors.push(`inheritSystemAgentsMd must be a boolean, found ${JSON.stringify(inheritValue)}`);\n\t}\n\n\tconst memoryValue = record.memory;\n\tconst memory = memoryValue === \"assistant\" || memoryValue === \"code\" ? memoryValue : undefined;\n\tif (memory === undefined) {\n\t\terrors.push(`memory must be \"assistant\" or \"code\", found ${JSON.stringify(memoryValue)}`);\n\t}\n\n\tconst orientationValue = record.orientation;\n\tconst orientation =\n\t\torientationValue === \"assistant\" || orientationValue === \"coding\" || orientationValue === \"custom\"\n\t\t\t? orientationValue\n\t\t\t: undefined;\n\tif (orientationValue !== undefined && orientation === undefined) {\n\t\terrors.push(`orientation must be \"assistant\", \"coding\", or \"custom\", found ${JSON.stringify(orientationValue)}`);\n\t}\n\n\tconst model = readOptionalString(record, \"model\", errors);\n\tconst thinking = readOptionalString(record, \"thinking\", errors);\n\tconst clonedFrom = readClonedFrom(record.clonedFrom, errors);\n\tconst factoryRevision = readFactoryRevision(record.factoryRevision, options.expectedBuiltin === true, errors);\n\n\tif (errors.length > 0) return { valid: false, errors };\n\n\treturn {\n\t\tvalid: true,\n\t\terrors: [],\n\t\tsuite: {\n\t\t\tschemaVersion: SUITE_SCHEMA_VERSION,\n\t\t\tid: id!,\n\t\t\tname: name!,\n\t\t\tbuiltin: builtin!,\n\t\t\ttools,\n\t\t\tcapabilities,\n\t\t\tassociations,\n\t\t\tinheritSystemAgentsMd: inheritSystemAgentsMd!,\n\t\t\tmemory: memory!,\n\t\t\torientation: orientation ?? \"assistant\",\n\t\t\tmodel,\n\t\t\tthinking,\n\t\t\tclonedFrom,\n\t\t\t...(factoryRevision === undefined ? {} : { factoryRevision }),\n\t\t},\n\t};\n}\n\nfunction readStringArray(record: Record<string, unknown>, key: string, errors: string[]): readonly string[] {\n\tconst value = record[key];\n\tif (!Array.isArray(value)) {\n\t\terrors.push(`${key} must be an array of strings, found ${JSON.stringify(value)}`);\n\t\treturn [];\n\t}\n\tconst entries: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\" || item.trim().length === 0) {\n\t\t\terrors.push(`${key} entries must be non-empty strings, found ${JSON.stringify(item)}`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\terrors.push(`${key} contains duplicate entry \"${item}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tentries.push(item);\n\t}\n\treturn entries;\n}\n\nfunction readAssociations(value: unknown, errors: string[]): SuiteAssociations {\n\tif (value === undefined) return { skills: [], mcp: [], plugins: [], roles: [] };\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(\n\t\t\t`associations must be an object with skills/mcp/plugins/roles arrays, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn { skills: [], mcp: [], plugins: [], roles: [] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\t// A key left out entirely means an empty list, consistent with a fully\n\t// absent `associations` object; a key that is present but malformed still\n\t// reports its errors. The removed legacy `extensions` kind is ignored on\n\t// read (it lost its loader with the old ExtensionAPI surface).\n\treturn {\n\t\tskills: record.skills === undefined ? [] : readStringArray(record, \"skills\", errors),\n\t\tmcp: record.mcp === undefined ? [] : readStringArray(record, \"mcp\", errors),\n\t\tplugins: record.plugins === undefined ? [] : readStringArray(record, \"plugins\", errors),\n\t\troles: record.roles === undefined ? [] : readStringArray(record, \"roles\", errors),\n\t};\n}\n\nfunction readOptionalString(record: Record<string, unknown>, key: string, errors: string[]): string | null {\n\tconst value = record[key];\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\terrors.push(`${key} must be a non-empty string or null, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\treturn value;\n}\n\n/**\n * Reads the optional `factoryRevision` key (M4). A missing key means\n * FACTORY_CONTENTS_VERSION for builtin workspaces (pre-M4 on-disk files stay\n * compatible) and stays absent for user suites (outside factory upgrade\n * governance). A present key must be a positive integer.\n */\nfunction readFactoryRevision(value: unknown, expectedBuiltin: boolean, errors: string[]): number | undefined {\n\tif (value === undefined) return expectedBuiltin ? FACTORY_CONTENTS_VERSION : undefined;\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\terrors.push(`factoryRevision must be a positive integer, found ${JSON.stringify(value)}`);\n\t\treturn undefined;\n\t}\n\treturn value;\n}\n\nfunction readClonedFrom(value: unknown, errors: string[]): SuiteClonedFrom | null {\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(`clonedFrom must be an object with id/digest/at, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\ttypeof record.id !== \"string\" ||\n\t\trecord.id.trim().length === 0 ||\n\t\ttypeof record.digest !== \"string\" ||\n\t\trecord.digest.trim().length === 0 ||\n\t\ttypeof record.at !== \"number\" ||\n\t\t!Number.isSafeInteger(record.at)\n\t) {\n\t\terrors.push(\n\t\t\t`clonedFrom must be an object with non-empty id/digest strings and an integer at, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn null;\n\t}\n\treturn { id: record.id, digest: record.digest, at: record.at };\n}\n"]}
1
+ {"version":3,"file":"builtin-suites.js","sourceRoot":"","sources":["../../src/suites/builtin-suites.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builtin suite (方案) declarations and suite.json (schemaVersion 1)\n * serialization, parsing, and validation — 方案系统设计.md v2 §5/§6/§9, M1a.\n *\n * Suites are pure data plus default policy: both builtin suites share the same\n * unrestricted tool surface and differ only in orientation and memory strategy\n * (the orientation persona text is injected into the system prompt, M2).\n * Nothing here touches the packages/agent kernel; association resolution is\n * declaration-only until M1b.\n */\n\nexport const SUITE_SCHEMA_VERSION = 1;\n\n/**\n * Factory contents revision (M4): the revision of the factory builtin\n * declarations, independent of SUITE_SCHEMA_VERSION. Bump it (and update both\n * builtin declarations' `factoryRevision`) whenever the factory contents\n * change; the registry upgrade proposal then offers `--suite-reset` for\n * workspaces still on an older revision. Suite schema evolution keeps using\n * SUITE_SCHEMA_VERSION.\n *\n * Revision 2 (统一修复轮集成收口, 2026-09-08): assistant and coding now share\n * the same active 8-tool surface in full-control — the sdk `suiteToolOverride`\n * DEFAULT_SUITE_ID exemption was removed (方案设计 §5 + user decision). Existing\n * workspaces provisioned at revision 1 receive the upgrade-proposal diagnostic\n * and adopt via `--suite-reset`.\n *\n * Revision 3 (2026-09-18): `builtin.session-share` joins both builtin suites\n * (开发计划 §216: session-share productized from the example plugin into a\n * first-party default-distributed capability) once the agent-dir config\n * channel for embedded capabilities landed\n * (`<agentDir>/capabilities/<short-id>.json`, see capabilities/builtin.ts).\n * Existing workspaces provisioned at revision 2 receive the upgrade-proposal\n * diagnostic and adopt via `--suite-reset`.\n *\n * Revision 4 (2026-09-18): `builtin.subagent-delegate` joins both builtin\n * suites — the first-party subagent delegation tool (`subagent_run`) now ships\n * by default in shared mode (zero extra processes; pooled runner processes stay\n * opt-in through the capability config channel). Existing workspaces\n * provisioned at revision 3 receive the upgrade-proposal diagnostic and adopt\n * via `--suite-reset`.\n *\n * Revision 5 (2026-09-20): subagent role profiles land on disk only\n * (`<agentDir>/roles/<id>.json` — the factory seeds explore/reviewer and never\n * overwrites user edits) and both builtin suites associate them by default via\n * the new `suite.associations.roles` field, with skill/MCP-isomorphic\n * visibility: unassociated roles stay invisible, associated-but-missing files\n * surface as dangling diagnostics. Existing workspaces provisioned at\n * revision 4 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n *\n * Revision 6 (D-077, 2026-10-02): `builtin.workflow` joins both builtin suites\n * — the workflow orchestration plugin enters the factory bootstrap manifest\n * (ninth package) and the suite capability declaration at goal/plan/todo-set\n * parity, keeping its plugin form. Existing workspaces provisioned at revision\n * 5 receive the upgrade-proposal diagnostic and adopt via `--suite-reset`.\n *\n * Revision 7 (视觉保底, 2026-10-04): the two visual baseline roles\n * `design-proposer` / `visual-reviewer` join the factory seeds and the default\n * `associations.roles` (user ruling \"术有专攻、角色隔离\"; role files are\n * disk-only and the seeds never overwrite user edits — see\n * `docs/plans/视觉保底角色设计注记.md`). Existing workspaces provisioned at\n * revision 6 receive the upgrade-proposal diagnostic and adopt via\n * `--suite-reset`.\n */\nexport const FACTORY_CONTENTS_VERSION = 7;\n\n/**\n * Factory default suite used when no suite is configured anywhere (设计 §9).\n * 2026-10-02 user ruling: the product is a coding agent, so the factory\n * default flipped from \"assistant\" to \"coding\"; assistant stays as the\n * explicit-switch fallback suite.\n */\nexport const DEFAULT_SUITE_ID = \"coding\";\n\n/** Suite ids become directory names: lowercase letters, digits, hyphens (设计 §9). */\nexport const SUITE_ID_MAX_LENGTH = 64;\n\n/** The single unrestricted tool surface shared by both builtin suites (设计 §5/§6). */\nexport const BUILTIN_SUITE_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"write\",\n\t\"edit\",\n\t\"bash\",\n\t\"ls\",\n\t\"find\",\n\t\"grep\",\n\t\"powershell\",\n];\n\n/**\n * Builtin capability plugins associated with both suites. Declaration-only\n * data in M1a; the actual plugin wiring is delivered in M3. `builtin.memory`\n * joins in the 统一修复轮 A 路 (方案系统设计 §6.1: both suites share the same\n * memory tool surface; the strategy difference lives in the suiteId domain\n * isolation and the assistant preference card). `builtin.session-share` joins\n * in the session-share productization slice (开发计划 §216); its\n * target/gateway/viewerUrl are configured through the agent-dir config\n * channel (`<agentDir>/capabilities/builtin.session-share.json`), and the\n * unconfigured default answers `/share` with the explicit configuration\n * prompt — never an implicit Radius/Gist fallback. `builtin.workflow` joins\n * at goal/plan/todo-set parity (D-077, 2026-10-02: factory default install\n * plus this suite declaration, plugin form unchanged). `builtin.coding-tools`\n * joins with the D-082 batch-1 tool split (2026-10-03): the default coding\n * tools assemble from the `plugins/coding-tools` package through the bundled\n * distribution channel (插件独立分发与启动装配设计 §4.9), not the install\n * store.\n */\nexport const BUILTIN_SUITE_CAPABILITIES: readonly string[] = [\n\t\"builtin.goal\",\n\t\"builtin.plan\",\n\t\"builtin.todo-set\",\n\t\"builtin.workflow\",\n\t\"builtin.memory\",\n\t\"builtin.session-share\",\n\t\"builtin.subagent-delegate\",\n\t\"builtin.coding-tools\",\n];\n\nexport type SuiteMemoryStrategy = \"assistant\" | \"code\";\nexport type SuiteOrientation = \"assistant\" | \"coding\" | \"custom\";\n\n/**\n * Orientation persona texts injected into the system prompt (设计 §6.2, M2).\n * The strings are verbatim from the design spec: the assistant persona is the\n * companion style, the coding persona is the rigor-first style. Both are\n * session-nature declarations, so they ride every system prompt branch\n * (default and customPrompt). The custom orientation is not in this table: its\n * persona text comes from the suite workspace persona.md (设计 §6.3, resolved\n * by suite-loader).\n */\nexport const ORIENTATION_PROMPTS: Record<\"assistant\" | \"coding\", string> = {\n\tassistant: `You are the user's thoughtful companion — warm, patient, and helpful.\n- Understand the intent behind the question, including the unspoken parts; when something that matters is ambiguous, ask one short clarifying question instead of assuming.\n- Pay attention to detail: notice what the user might have missed and gently point it out.\n- Be proactive and divergent: after answering, offer next steps, related ideas, or creative alternatives — without being pushy.\n- Adapt tone to the user; stay natural and flexible, never robotic or formulaic.\n- When you can help by doing, act through tools autonomously (minimal interruption).\n- Structure longer answers clearly: short paragraphs, lists where they help, and a concrete \"what you can do next\" at the end.`,\n\tcoding: `You are an autonomous software engineering agent with a rigor-first mindset.\n- Never guess. Ground every claim in code you have read, commands you have run, or documented evidence; cite file paths and line numbers. If the evidence is insufficient, investigate, and report what is unverified — or \"unknown\" — instead of a plausible invention.\n- First principles: trace problems to the earliest reasonable root cause and fix that; do not patch symptoms.\n- No over-engineering: add no abstraction, options, or defensive handling for imagined future needs; generalise only when a second concrete case demands it.\n- Tests first: pin expected behavior with a failing or updated test before or alongside the fix, then run the smallest sufficient relevant checks; the work is not done until they pass.\n- Reproducible: prefer deterministic tests and mocks over ad-hoc verification, and report the exact commands and results so others can re-run them.\n- Docs as code: follow the repository's documentation conventions; where the project treats design docs, READMEs, and changelogs as part of the change, keep them consistent with the behavior they describe.\n- Self-review before finishing: re-check your changes for correctness, edge cases, regressions, and missing tests; prefer a second review pass over shipping the first draft.\n- Cautious: weigh side effects, compatibility, and failure modes; when in doubt, gather evidence and verify before changing — doubt is never resolved by making the fix smaller.`,\n};\n\nexport interface SuiteAssociations {\n\treadonly skills: readonly string[];\n\treadonly mcp: readonly string[];\n\treadonly plugins: readonly string[];\n\t/**\n\t * 子代理角色关联(D-044 角色机制):关联的是 `<agentDir>/roles/<id>.json` 里的角色 id。\n\t * 角色定义只在磁盘上(工厂仅做种子落盘),方案只决定哪些角色对主代理可见——与\n\t * skill/MCP/插件同构,第一方与第三方角色没有区别。\n\t */\n\treadonly roles: readonly string[];\n}\n\nexport interface SuiteClonedFrom {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly at: number;\n}\n\n/** The serializable suite definition persisted as suite.json (设计 §5). */\nexport interface SuiteDefinition {\n\treadonly schemaVersion: number;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly builtin: boolean;\n\treadonly tools: readonly string[];\n\treadonly capabilities: readonly string[];\n\treadonly associations: SuiteAssociations;\n\treadonly inheritSystemAgentsMd: boolean;\n\treadonly memory: SuiteMemoryStrategy;\n\treadonly orientation: SuiteOrientation;\n\treadonly model: string | null;\n\treadonly thinking: string | null;\n\treadonly clonedFrom: SuiteClonedFrom | null;\n\t/**\n\t * Factory contents revision this declaration was written at (M4). Builtin\n\t * declarations carry it; on-disk builtin suite.json may omit it (pre-M4\n\t * files parse as FACTORY_CONTENTS_VERSION). User suites are outside factory\n\t * upgrade governance: the key stays optional and may be absent.\n\t */\n\treadonly factoryRevision?: number;\n}\n\nconst EMPTY_ASSOCIATIONS: SuiteAssociations = { skills: [], mcp: [], plugins: [], roles: [] };\n\n/**\n * 默认方案关联的子代理角色(开箱即用):这四个 id 对应工厂种子落盘的四个普通角色文件\n * (`<agentDir>/roles/{explore,reviewer,design-proposer,visual-reviewer}.json`,用户可改可删)。\n * design-proposer / visual-reviewer 是视觉保底角色(2026-10-04 用户裁决\"术有专攻、角色隔离\"),\n * 档案 readonly + 只读工具收窄,与编码角色结构性隔离——见 docs/plans/视觉保底角色设计注记.md。\n * 工厂不在运行期回退到任何编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\n\t\"explore\",\n\t\"reviewer\",\n\t\"design-proposer\",\n\t\"visual-reviewer\",\n];\n\nconst assistantSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"assistant\",\n\tname: \"Assistant\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"assistant\",\n\torientation: \"assistant\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\nconst codingSuite: SuiteDefinition = {\n\tschemaVersion: SUITE_SCHEMA_VERSION,\n\tid: \"coding\",\n\tname: \"Coding\",\n\tbuiltin: true,\n\ttools: BUILTIN_SUITE_TOOLS,\n\tcapabilities: BUILTIN_SUITE_CAPABILITIES,\n\tassociations: { ...EMPTY_ASSOCIATIONS, roles: DEFAULT_ROLE_ASSOCIATIONS },\n\tinheritSystemAgentsMd: false,\n\tmemory: \"code\",\n\torientation: \"coding\",\n\tmodel: null,\n\tthinking: null,\n\tclonedFrom: null,\n\tfactoryRevision: FACTORY_CONTENTS_VERSION,\n};\n\n/** The factory builtin pair: coding (factory default 尖刀) and assistant (fallback). */\nexport const BUILTIN_SUITES: readonly SuiteDefinition[] = [assistantSuite, codingSuite];\n\nexport function getBuiltinSuite(id: string): SuiteDefinition | undefined {\n\treturn BUILTIN_SUITES.find((suite) => suite.id === id);\n}\n\nexport function isBuiltinSuiteId(id: string): boolean {\n\treturn BUILTIN_SUITES.some((suite) => suite.id === id);\n}\n\nconst WINDOWS_RESERVED_IDS = new Set([\n\t\"con\",\n\t\"prn\",\n\t\"aux\",\n\t\"nul\",\n\t\"com1\",\n\t\"com2\",\n\t\"com3\",\n\t\"com4\",\n\t\"com5\",\n\t\"com6\",\n\t\"com7\",\n\t\"com8\",\n\t\"com9\",\n\t\"lpt1\",\n\t\"lpt2\",\n\t\"lpt3\",\n\t\"lpt4\",\n\t\"lpt5\",\n\t\"lpt6\",\n\t\"lpt7\",\n\t\"lpt8\",\n\t\"lpt9\",\n\t\"conin$\",\n\t\"conout$\",\n]);\n\n/** Suite id rule (设计 §9): `a-z0-9-`, no leading/trailing hyphen, no Windows reserved names. */\nexport function isValidSuiteId(id: string): boolean {\n\tif (id.length === 0 || id.length > SUITE_ID_MAX_LENGTH) return false;\n\tif (!/^[a-z0-9-]+$/.test(id)) return false;\n\tif (id.startsWith(\"-\") || id.endsWith(\"-\")) return false;\n\tif (WINDOWS_RESERVED_IDS.has(id)) return false;\n\treturn true;\n}\n\n/** Serializes a suite to the canonical suite.json text (stable field order, trailing newline). */\nexport function serializeSuiteJson(suite: SuiteDefinition): string {\n\tconst ordered = {\n\t\tschemaVersion: suite.schemaVersion,\n\t\tid: suite.id,\n\t\tname: suite.name,\n\t\tbuiltin: suite.builtin,\n\t\ttools: [...suite.tools],\n\t\tcapabilities: [...suite.capabilities],\n\t\tassociations: {\n\t\t\tskills: [...suite.associations.skills],\n\t\t\tmcp: [...suite.associations.mcp],\n\t\t\tplugins: [...suite.associations.plugins],\n\t\t\troles: [...suite.associations.roles],\n\t\t},\n\t\tinheritSystemAgentsMd: suite.inheritSystemAgentsMd,\n\t\tmemory: suite.memory,\n\t\torientation: suite.orientation,\n\t\tmodel: suite.model,\n\t\tthinking: suite.thinking,\n\t\tclonedFrom: suite.clonedFrom\n\t\t\t? { id: suite.clonedFrom.id, digest: suite.clonedFrom.digest, at: suite.clonedFrom.at }\n\t\t\t: null,\n\t\tfactoryRevision: suite.factoryRevision,\n\t};\n\treturn `${JSON.stringify(ordered, null, 2)}\\n`;\n}\n\nexport interface SuiteJsonParseResult {\n\treadonly valid: boolean;\n\treadonly suite?: SuiteDefinition;\n\treadonly errors: readonly string[];\n}\n\n/**\n * Parses suite.json text. Never throws: an invalid result carries every\n * validation error so callers can apply the corruption policy (设计 §9) —\n * builtin suites fall back to factory content, user suites fail fast.\n */\nexport function parseSuiteJson(\n\traw: string,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string },\n): SuiteJsonParseResult {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(raw);\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors: [`invalid JSON: ${error instanceof Error ? error.message : String(error)}`],\n\t\t};\n\t}\n\treturn validateSuiteJson(value, options);\n}\n\nexport function validateSuiteJson(\n\tvalue: unknown,\n\toptions: { expectedBuiltin?: boolean; expectedId?: string } = {},\n): SuiteJsonParseResult {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn { valid: false, errors: [\"suite.json must be a JSON object\"] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst errors: string[] = [];\n\n\tif (record.schemaVersion !== SUITE_SCHEMA_VERSION) {\n\t\terrors.push(`schemaVersion must be ${SUITE_SCHEMA_VERSION}, found ${JSON.stringify(record.schemaVersion)}`);\n\t}\n\n\t// Each field keeps a typed local: valid values land here, invalid ones only\n\t// contribute errors. The suite below is constructed exclusively when\n\t// `errors` is empty, so the fallbacks/coercions at that point are dead.\n\tconst idValue = record.id;\n\tconst id = typeof idValue === \"string\" && isValidSuiteId(idValue) ? idValue : undefined;\n\tif (id === undefined) {\n\t\terrors.push(\n\t\t\t`id must be a suite id (^[a-z0-9-]+$, no leading/trailing hyphen, Windows reserved names rejected), found ${JSON.stringify(idValue)}`,\n\t\t);\n\t} else if (options.expectedId !== undefined && id !== options.expectedId) {\n\t\terrors.push(`id \"${id}\" does not match the suite workspace directory id \"${options.expectedId}\"`);\n\t}\n\n\tconst nameValue = record.name;\n\tconst name = typeof nameValue === \"string\" && nameValue.trim().length > 0 ? nameValue : undefined;\n\tif (name === undefined) {\n\t\terrors.push(`name must be a non-empty string, found ${JSON.stringify(nameValue)}`);\n\t}\n\n\tconst builtinValue = record.builtin;\n\tconst builtin = typeof builtinValue === \"boolean\" ? builtinValue : undefined;\n\tif (builtin === undefined) {\n\t\terrors.push(`builtin must be a boolean, found ${JSON.stringify(builtinValue)}`);\n\t} else if (options.expectedBuiltin === true && builtin !== true) {\n\t\terrors.push(`builtin must be true for a builtin suite workspace, found ${builtin}`);\n\t}\n\n\tconst tools = readStringArray(record, \"tools\", errors);\n\tconst capabilities = readStringArray(record, \"capabilities\", errors);\n\tconst associations = readAssociations(record.associations, errors);\n\n\tconst inheritValue = record.inheritSystemAgentsMd;\n\tconst inheritSystemAgentsMd = typeof inheritValue === \"boolean\" ? inheritValue : undefined;\n\tif (inheritSystemAgentsMd === undefined) {\n\t\terrors.push(`inheritSystemAgentsMd must be a boolean, found ${JSON.stringify(inheritValue)}`);\n\t}\n\n\tconst memoryValue = record.memory;\n\tconst memory = memoryValue === \"assistant\" || memoryValue === \"code\" ? memoryValue : undefined;\n\tif (memory === undefined) {\n\t\terrors.push(`memory must be \"assistant\" or \"code\", found ${JSON.stringify(memoryValue)}`);\n\t}\n\n\tconst orientationValue = record.orientation;\n\tconst orientation =\n\t\torientationValue === \"assistant\" || orientationValue === \"coding\" || orientationValue === \"custom\"\n\t\t\t? orientationValue\n\t\t\t: undefined;\n\tif (orientationValue !== undefined && orientation === undefined) {\n\t\terrors.push(`orientation must be \"assistant\", \"coding\", or \"custom\", found ${JSON.stringify(orientationValue)}`);\n\t}\n\n\tconst model = readOptionalString(record, \"model\", errors);\n\tconst thinking = readOptionalString(record, \"thinking\", errors);\n\tconst clonedFrom = readClonedFrom(record.clonedFrom, errors);\n\tconst factoryRevision = readFactoryRevision(record.factoryRevision, options.expectedBuiltin === true, errors);\n\n\tif (errors.length > 0) return { valid: false, errors };\n\n\treturn {\n\t\tvalid: true,\n\t\terrors: [],\n\t\tsuite: {\n\t\t\tschemaVersion: SUITE_SCHEMA_VERSION,\n\t\t\tid: id!,\n\t\t\tname: name!,\n\t\t\tbuiltin: builtin!,\n\t\t\ttools,\n\t\t\tcapabilities,\n\t\t\tassociations,\n\t\t\tinheritSystemAgentsMd: inheritSystemAgentsMd!,\n\t\t\tmemory: memory!,\n\t\t\torientation: orientation ?? \"assistant\",\n\t\t\tmodel,\n\t\t\tthinking,\n\t\t\tclonedFrom,\n\t\t\t...(factoryRevision === undefined ? {} : { factoryRevision }),\n\t\t},\n\t};\n}\n\nfunction readStringArray(record: Record<string, unknown>, key: string, errors: string[]): readonly string[] {\n\tconst value = record[key];\n\tif (!Array.isArray(value)) {\n\t\terrors.push(`${key} must be an array of strings, found ${JSON.stringify(value)}`);\n\t\treturn [];\n\t}\n\tconst entries: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\" || item.trim().length === 0) {\n\t\t\terrors.push(`${key} entries must be non-empty strings, found ${JSON.stringify(item)}`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\terrors.push(`${key} contains duplicate entry \"${item}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tentries.push(item);\n\t}\n\treturn entries;\n}\n\nfunction readAssociations(value: unknown, errors: string[]): SuiteAssociations {\n\tif (value === undefined) return { skills: [], mcp: [], plugins: [], roles: [] };\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(\n\t\t\t`associations must be an object with skills/mcp/plugins/roles arrays, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn { skills: [], mcp: [], plugins: [], roles: [] };\n\t}\n\tconst record = value as Record<string, unknown>;\n\t// A key left out entirely means an empty list, consistent with a fully\n\t// absent `associations` object; a key that is present but malformed still\n\t// reports its errors. The removed legacy `extensions` kind is ignored on\n\t// read (it lost its loader with the old ExtensionAPI surface).\n\treturn {\n\t\tskills: record.skills === undefined ? [] : readStringArray(record, \"skills\", errors),\n\t\tmcp: record.mcp === undefined ? [] : readStringArray(record, \"mcp\", errors),\n\t\tplugins: record.plugins === undefined ? [] : readStringArray(record, \"plugins\", errors),\n\t\troles: record.roles === undefined ? [] : readStringArray(record, \"roles\", errors),\n\t};\n}\n\nfunction readOptionalString(record: Record<string, unknown>, key: string, errors: string[]): string | null {\n\tconst value = record[key];\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\terrors.push(`${key} must be a non-empty string or null, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\treturn value;\n}\n\n/**\n * Reads the optional `factoryRevision` key (M4). A missing key means\n * FACTORY_CONTENTS_VERSION for builtin workspaces (pre-M4 on-disk files stay\n * compatible) and stays absent for user suites (outside factory upgrade\n * governance). A present key must be a positive integer.\n */\nfunction readFactoryRevision(value: unknown, expectedBuiltin: boolean, errors: string[]): number | undefined {\n\tif (value === undefined) return expectedBuiltin ? FACTORY_CONTENTS_VERSION : undefined;\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\terrors.push(`factoryRevision must be a positive integer, found ${JSON.stringify(value)}`);\n\t\treturn undefined;\n\t}\n\treturn value;\n}\n\nfunction readClonedFrom(value: unknown, errors: string[]): SuiteClonedFrom | null {\n\tif (value === undefined || value === null) return null;\n\tif (typeof value !== \"object\" || Array.isArray(value)) {\n\t\terrors.push(`clonedFrom must be an object with id/digest/at, found ${JSON.stringify(value)}`);\n\t\treturn null;\n\t}\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\ttypeof record.id !== \"string\" ||\n\t\trecord.id.trim().length === 0 ||\n\t\ttypeof record.digest !== \"string\" ||\n\t\trecord.digest.trim().length === 0 ||\n\t\ttypeof record.at !== \"number\" ||\n\t\t!Number.isSafeInteger(record.at)\n\t) {\n\t\terrors.push(\n\t\t\t`clonedFrom must be an object with non-empty id/digest strings and an integer at, found ${JSON.stringify(value)}`,\n\t\t);\n\t\treturn null;\n\t}\n\treturn { id: record.id, digest: record.digest, at: record.at };\n}\n"]}