@ai-agent-forge/agent-forge 0.86.6 → 0.87.0

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 (665) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +8 -9
  3. package/dist/artifacts/artifact-store.d.ts.map +1 -1
  4. package/dist/artifacts/artifact-store.js +9 -5
  5. package/dist/artifacts/artifact-store.js.map +1 -1
  6. package/dist/bundle/.build-manifest.json +410 -371
  7. package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
  8. package/dist/bundle/chunks/chunk-BFC2BDVJ.js +13 -0
  9. package/dist/bundle/chunks/chunk-MOHOLL3F.js +1456 -0
  10. package/dist/bundle/chunks/image-resize-worker.js +12 -1
  11. package/dist/bundle/chunks/{virtual-modules-3IZ4MYSQ.js → virtual-modules-KZ5DRH7Q.js} +1 -1
  12. package/dist/bundle/cli.js +1 -1
  13. package/dist/bundle/client.js +1 -1
  14. package/dist/bundle/index.js +2 -2
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/cli/args.d.ts.map +1 -1
  17. package/dist/cli/args.js +231 -185
  18. package/dist/cli/args.js.map +1 -1
  19. package/dist/cli/auth-check.d.ts.map +1 -1
  20. package/dist/cli/auth-check.js +3 -2
  21. package/dist/cli/auth-check.js.map +1 -1
  22. package/dist/cli/auth-command.d.ts.map +1 -1
  23. package/dist/cli/auth-command.js +15 -9
  24. package/dist/cli/auth-command.js.map +1 -1
  25. package/dist/cli/credential-print.d.ts.map +1 -1
  26. package/dist/cli/credential-print.js +14 -7
  27. package/dist/cli/credential-print.js.map +1 -1
  28. package/dist/cli/experimental/command.d.ts.map +1 -1
  29. package/dist/cli/experimental/command.js +6 -5
  30. package/dist/cli/experimental/command.js.map +1 -1
  31. package/dist/cli/list-models.d.ts.map +1 -1
  32. package/dist/cli/list-models.js +9 -8
  33. package/dist/cli/list-models.js.map +1 -1
  34. package/dist/cli/plugin-manager-controller.d.ts.map +1 -1
  35. package/dist/cli/plugin-manager-controller.js +2 -1
  36. package/dist/cli/plugin-manager-controller.js.map +1 -1
  37. package/dist/cli/serve.d.ts.map +1 -1
  38. package/dist/cli/serve.js +8 -5
  39. package/dist/cli/serve.js.map +1 -1
  40. package/dist/client/remote-session.d.ts.map +1 -1
  41. package/dist/client/remote-session.js +16 -9
  42. package/dist/client/remote-session.js.map +1 -1
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +2 -1
  45. package/dist/config.js.map +1 -1
  46. package/dist/core/agent-capability-contract.d.ts +0 -7
  47. package/dist/core/agent-capability-contract.d.ts.map +1 -1
  48. package/dist/core/agent-capability-contract.js +72 -68
  49. package/dist/core/agent-capability-contract.js.map +1 -1
  50. package/dist/core/agent-session-bash.d.ts.map +1 -1
  51. package/dist/core/agent-session-bash.js +5 -4
  52. package/dist/core/agent-session-bash.js.map +1 -1
  53. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  54. package/dist/core/agent-session-compaction.js +28 -22
  55. package/dist/core/agent-session-compaction.js.map +1 -1
  56. package/dist/core/agent-session-context.d.ts.map +1 -1
  57. package/dist/core/agent-session-context.js +18 -13
  58. package/dist/core/agent-session-context.js.map +1 -1
  59. package/dist/core/agent-session-model.d.ts.map +1 -1
  60. package/dist/core/agent-session-model.js +2 -1
  61. package/dist/core/agent-session-model.js.map +1 -1
  62. package/dist/core/agent-session-retry.d.ts.map +1 -1
  63. package/dist/core/agent-session-retry.js +3 -2
  64. package/dist/core/agent-session-retry.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  66. package/dist/core/agent-session-runtime.js +7 -6
  67. package/dist/core/agent-session-runtime.js.map +1 -1
  68. package/dist/core/agent-session-services.d.ts +1 -1
  69. package/dist/core/agent-session-services.d.ts.map +1 -1
  70. package/dist/core/agent-session-services.js.map +1 -1
  71. package/dist/core/agent-session-tools.d.ts.map +1 -1
  72. package/dist/core/agent-session-tools.js +3 -2
  73. package/dist/core/agent-session-tools.js.map +1 -1
  74. package/dist/core/agent-session.d.ts +40 -2
  75. package/dist/core/agent-session.d.ts.map +1 -1
  76. package/dist/core/agent-session.js +142 -34
  77. package/dist/core/agent-session.js.map +1 -1
  78. package/dist/core/auth-guidance.d.ts.map +1 -1
  79. package/dist/core/auth-guidance.js +11 -5
  80. package/dist/core/auth-guidance.js.map +1 -1
  81. package/dist/core/auth-storage.d.ts.map +1 -1
  82. package/dist/core/auth-storage.js +9 -6
  83. package/dist/core/auth-storage.js.map +1 -1
  84. package/dist/core/compaction/compaction.d.ts.map +1 -1
  85. package/dist/core/compaction/compaction.js +2 -1
  86. package/dist/core/compaction/compaction.js.map +1 -1
  87. package/dist/core/embedded-sdk.d.ts.map +1 -1
  88. package/dist/core/embedded-sdk.js +10 -6
  89. package/dist/core/embedded-sdk.js.map +1 -1
  90. package/dist/core/export-html/index.d.ts.map +1 -1
  91. package/dist/core/export-html/index.js +9 -4
  92. package/dist/core/export-html/index.js.map +1 -1
  93. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  94. package/dist/core/extensions/agent-composition.js +26 -19
  95. package/dist/core/extensions/agent-composition.js.map +1 -1
  96. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  97. package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
  98. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  99. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  100. package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
  101. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  102. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
  103. package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
  104. package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
  105. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
  106. package/dist/core/extensions/bootstrap-retry-policy.js +2 -1
  107. package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
  108. package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
  109. package/dist/core/extensions/bootstrap-skills.js +7 -6
  110. package/dist/core/extensions/bootstrap-skills.js.map +1 -1
  111. package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
  112. package/dist/core/extensions/bootstrap-tools.js +2 -1
  113. package/dist/core/extensions/bootstrap-tools.js.map +1 -1
  114. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  115. package/dist/core/extensions/capability-plugin.js +37 -13
  116. package/dist/core/extensions/capability-plugin.js.map +1 -1
  117. package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
  118. package/dist/core/extensions/capability-runtime-events.js +17 -13
  119. package/dist/core/extensions/capability-runtime-events.js.map +1 -1
  120. package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
  121. package/dist/core/extensions/capability-runtime-guards.js +16 -15
  122. package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
  123. package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
  124. package/dist/core/extensions/capability-runtime-manifest.js +52 -30
  125. package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
  126. package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
  127. package/dist/core/extensions/capability-runtime-validation.js +66 -65
  128. package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
  129. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  130. package/dist/core/extensions/capability-runtime.js +147 -127
  131. package/dist/core/extensions/capability-runtime.js.map +1 -1
  132. package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
  133. package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
  134. package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
  135. package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
  136. package/dist/core/extensions/context-strategy-binding.js +7 -4
  137. package/dist/core/extensions/context-strategy-binding.js.map +1 -1
  138. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  139. package/dist/core/extensions/lifecycle-catalog.js +290 -279
  140. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  141. package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
  142. package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
  143. package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
  144. package/dist/core/facade/coding-agent-facade.d.ts +6 -0
  145. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  146. package/dist/core/facade/coding-agent-facade.js +2 -0
  147. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  148. package/dist/core/http-dispatcher.d.ts.map +1 -1
  149. package/dist/core/http-dispatcher.js +2 -1
  150. package/dist/core/http-dispatcher.js.map +1 -1
  151. package/dist/core/i18n/index.d.ts +14 -0
  152. package/dist/core/i18n/index.d.ts.map +1 -0
  153. package/dist/core/i18n/index.js +67 -0
  154. package/dist/core/i18n/index.js.map +1 -0
  155. package/dist/core/i18n/locales/en/example.d.ts +7 -0
  156. package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
  157. package/dist/core/i18n/locales/en/example.js +7 -0
  158. package/dist/core/i18n/locales/en/example.js.map +1 -0
  159. package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
  160. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
  161. package/dist/core/i18n/locales/zh-cn/cli.js +227 -0
  162. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
  163. package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
  164. package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
  165. package/dist/core/i18n/locales/zh-cn/common.js +6 -0
  166. package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
  167. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
  168. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
  169. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
  170. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
  171. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
  172. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
  173. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
  174. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
  175. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
  176. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
  177. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
  178. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
  179. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
  180. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
  181. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
  182. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
  183. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
  184. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
  185. package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
  186. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
  187. package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
  188. package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
  189. package/dist/core/i18n/locales/zh-cn/example.js +10 -0
  190. package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
  191. package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
  192. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
  193. package/dist/core/i18n/locales/zh-cn/index.js +41 -0
  194. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
  195. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
  196. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
  197. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +265 -0
  198. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
  199. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
  200. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
  201. package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
  202. package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
  203. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
  204. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
  205. package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
  206. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
  207. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
  208. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
  209. package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
  210. package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
  211. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
  212. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
  213. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
  214. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
  215. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
  216. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
  217. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +288 -0
  218. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
  219. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
  220. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
  221. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
  222. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
  223. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
  224. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
  225. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
  226. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
  227. package/dist/core/keybindings.d.ts +15 -0
  228. package/dist/core/keybindings.d.ts.map +1 -1
  229. package/dist/core/keybindings.js +18 -0
  230. package/dist/core/keybindings.js.map +1 -1
  231. package/dist/core/logger.d.ts.map +1 -1
  232. package/dist/core/logger.js +5 -1
  233. package/dist/core/logger.js.map +1 -1
  234. package/dist/core/model-registry.d.ts.map +1 -1
  235. package/dist/core/model-registry.js +2 -1
  236. package/dist/core/model-registry.js.map +1 -1
  237. package/dist/core/model-runtime.d.ts.map +1 -1
  238. package/dist/core/model-runtime.js +8 -4
  239. package/dist/core/model-runtime.js.map +1 -1
  240. package/dist/core/package-install-host.d.ts.map +1 -1
  241. package/dist/core/package-install-host.js +4 -3
  242. package/dist/core/package-install-host.js.map +1 -1
  243. package/dist/core/package-manager.d.ts.map +1 -1
  244. package/dist/core/package-manager.js +15 -10
  245. package/dist/core/package-manager.js.map +1 -1
  246. package/dist/core/package-resource-collection.d.ts.map +1 -1
  247. package/dist/core/package-resource-collection.js +2 -1
  248. package/dist/core/package-resource-collection.js.map +1 -1
  249. package/dist/core/package-source.d.ts.map +1 -1
  250. package/dist/core/package-source.js +3 -2
  251. package/dist/core/package-source.js.map +1 -1
  252. package/dist/core/provider-composer.d.ts.map +1 -1
  253. package/dist/core/provider-composer.js +22 -13
  254. package/dist/core/provider-composer.js.map +1 -1
  255. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  256. package/dist/core/remote-catalog-provider.js +6 -2
  257. package/dist/core/remote-catalog-provider.js.map +1 -1
  258. package/dist/core/resolve-config-value.d.ts.map +1 -1
  259. package/dist/core/resolve-config-value.js +15 -5
  260. package/dist/core/resolve-config-value.js.map +1 -1
  261. package/dist/core/sdk.d.ts +19 -5
  262. package/dist/core/sdk.d.ts.map +1 -1
  263. package/dist/core/sdk.js +74 -54
  264. package/dist/core/sdk.js.map +1 -1
  265. package/dist/core/session-cwd.d.ts.map +1 -1
  266. package/dist/core/session-cwd.js +5 -2
  267. package/dist/core/session-cwd.js.map +1 -1
  268. package/dist/core/session-export.d.ts.map +1 -1
  269. package/dist/core/session-export.js +2 -1
  270. package/dist/core/session-export.js.map +1 -1
  271. package/dist/core/session-manager.d.ts.map +1 -1
  272. package/dist/core/session-manager.js +39 -29
  273. package/dist/core/session-manager.js.map +1 -1
  274. package/dist/core/session-storage.d.ts.map +1 -1
  275. package/dist/core/session-storage.js +3 -3
  276. package/dist/core/session-storage.js.map +1 -1
  277. package/dist/core/settings-manager.d.ts +11 -0
  278. package/dist/core/settings-manager.d.ts.map +1 -1
  279. package/dist/core/settings-manager.js +27 -5
  280. package/dist/core/settings-manager.js.map +1 -1
  281. package/dist/core/slash-commands.d.ts.map +1 -1
  282. package/dist/core/slash-commands.js +53 -32
  283. package/dist/core/slash-commands.js.map +1 -1
  284. package/dist/core/system-prompt.d.ts.map +1 -1
  285. package/dist/core/system-prompt.js +25 -2
  286. package/dist/core/system-prompt.js.map +1 -1
  287. package/dist/core/tools/bash.d.ts.map +1 -1
  288. package/dist/core/tools/bash.js +11 -7
  289. package/dist/core/tools/bash.js.map +1 -1
  290. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  291. package/dist/core/tools/edit-diff.js +9 -4
  292. package/dist/core/tools/edit-diff.js.map +1 -1
  293. package/dist/core/tools/edit.d.ts.map +1 -1
  294. package/dist/core/tools/edit.js +4 -3
  295. package/dist/core/tools/edit.js.map +1 -1
  296. package/dist/core/tools/index.d.ts.map +1 -1
  297. package/dist/core/tools/index.js +3 -2
  298. package/dist/core/tools/index.js.map +1 -1
  299. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  300. package/dist/core/tools/output-accumulator.js +2 -1
  301. package/dist/core/tools/output-accumulator.js.map +1 -1
  302. package/dist/core/tools/read.d.ts.map +1 -1
  303. package/dist/core/tools/read.js +6 -2
  304. package/dist/core/tools/read.js.map +1 -1
  305. package/dist/core/tools/write.d.ts.map +1 -1
  306. package/dist/core/tools/write.js +2 -1
  307. package/dist/core/tools/write.js.map +1 -1
  308. package/dist/durable/durable-service.d.ts.map +1 -1
  309. package/dist/durable/durable-service.js +25 -18
  310. package/dist/durable/durable-service.js.map +1 -1
  311. package/dist/host/checkpoint-commit.d.ts.map +1 -1
  312. package/dist/host/checkpoint-commit.js +2 -1
  313. package/dist/host/checkpoint-commit.js.map +1 -1
  314. package/dist/host/manual-compaction.d.ts.map +1 -1
  315. package/dist/host/manual-compaction.js +2 -1
  316. package/dist/host/manual-compaction.js.map +1 -1
  317. package/dist/host/output-projection.d.ts +0 -13
  318. package/dist/host/output-projection.d.ts.map +1 -1
  319. package/dist/host/output-projection.js +16 -2
  320. package/dist/host/output-projection.js.map +1 -1
  321. package/dist/host/summary-retry.d.ts.map +1 -1
  322. package/dist/host/summary-retry.js +3 -2
  323. package/dist/host/summary-retry.js.map +1 -1
  324. package/dist/main.d.ts.map +1 -1
  325. package/dist/main.js +94 -58
  326. package/dist/main.js.map +1 -1
  327. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/agents-view.js +18 -15
  329. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  330. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/assistant-message.js +6 -5
  332. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  333. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/bash-execution.js +12 -7
  335. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  336. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/bordered-loader.js +2 -1
  338. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  339. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/branch-summary-message.js +6 -5
  341. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  342. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  343. package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
  344. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  345. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/config-selector.js +18 -15
  347. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  349. package/dist/modes/interactive/components/custom-entry.js +2 -1
  350. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  351. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/dialog-editor.js +5 -4
  353. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  354. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/dialog-input.js +2 -1
  356. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  357. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  358. package/dist/modes/interactive/components/dialog-selector.js +4 -3
  359. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/first-time-setup.js +11 -10
  362. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  363. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/footer.js +7 -4
  365. package/dist/modes/interactive/components/footer.js.map +1 -1
  366. package/dist/modes/interactive/components/index.d.ts +1 -0
  367. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/index.js +1 -0
  369. package/dist/modes/interactive/components/index.js.map +1 -1
  370. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/keybinding-hints.js +3 -2
  372. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  373. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/login-dialog.js +12 -11
  375. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  376. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/mermaid.js +6 -2
  378. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  379. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/model-selector.js +28 -16
  381. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/oauth-selector.js +10 -9
  384. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
  387. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  388. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
  390. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  391. package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
  392. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
  393. package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
  394. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
  395. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  396. package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
  397. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  398. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/session-selector.js +43 -31
  400. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  401. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  402. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/settings-selector.js +113 -96
  404. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  405. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/settings-submenu.js +5 -4
  407. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  408. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/show-images-selector.js +3 -2
  410. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  411. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
  413. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  414. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/status-indicator.js +14 -5
  416. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  417. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/theme-selector.js +2 -1
  419. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  420. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/thinking-selector.js +11 -4
  422. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  423. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/tool-execution.js +8 -3
  425. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  426. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/tree-list.js +7 -6
  428. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  429. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/tree-render.js +28 -23
  431. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  432. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/tree-selector.js +9 -7
  434. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  435. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  436. package/dist/modes/interactive/components/user-message-selector.js +5 -4
  437. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  438. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  439. package/dist/modes/interactive/components/workflow-view.js +36 -21
  440. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  441. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  442. package/dist/modes/interactive/external-editor.js +2 -1
  443. package/dist/modes/interactive/external-editor.js.map +1 -1
  444. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  445. package/dist/modes/interactive/interactive-auth.js +71 -40
  446. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  447. package/dist/modes/interactive/interactive-commands.d.ts +1 -0
  448. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  449. package/dist/modes/interactive/interactive-commands.js +3 -0
  450. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  451. package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
  452. package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
  453. package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
  454. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  455. package/dist/modes/interactive/interactive-format.js +34 -18
  456. package/dist/modes/interactive/interactive-format.js.map +1 -1
  457. package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
  458. package/dist/modes/interactive/interactive-helpers.js +7 -2
  459. package/dist/modes/interactive/interactive-helpers.js.map +1 -1
  460. package/dist/modes/interactive/interactive-mode.d.ts +4 -1
  461. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-mode.js +327 -243
  463. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  464. package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
  465. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-selectors.js +79 -25
  467. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  468. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  469. package/dist/modes/interactive/theme/theme-controller.js +5 -1
  470. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  471. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  472. package/dist/modes/interactive/theme/theme.js +26 -23
  473. package/dist/modes/interactive/theme/theme.js.map +1 -1
  474. package/dist/modes/json-event.d.ts.map +1 -1
  475. package/dist/modes/json-event.js +3 -2
  476. package/dist/modes/json-event.js.map +1 -1
  477. package/dist/modes/print-mode.d.ts.map +1 -1
  478. package/dist/modes/print-mode.js +3 -2
  479. package/dist/modes/print-mode.js.map +1 -1
  480. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  481. package/dist/modes/rpc/rpc-client.js +3 -2
  482. package/dist/modes/rpc/rpc-client.js.map +1 -1
  483. package/dist/package-manager-cli.d.ts.map +1 -1
  484. package/dist/package-manager-cli.js +28 -13
  485. package/dist/package-manager-cli.js.map +1 -1
  486. package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
  487. package/dist/plugins/ecosystem/catalog.js +3 -2
  488. package/dist/plugins/ecosystem/catalog.js.map +1 -1
  489. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  490. package/dist/plugins/ecosystem/cli.js +2 -1
  491. package/dist/plugins/ecosystem/cli.js.map +1 -1
  492. package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
  493. package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
  494. package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
  495. package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
  496. package/dist/plugins/ecosystem/distribution.js +2 -1
  497. package/dist/plugins/ecosystem/distribution.js.map +1 -1
  498. package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
  499. package/dist/plugins/ecosystem/installer.js +3 -2
  500. package/dist/plugins/ecosystem/installer.js.map +1 -1
  501. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  502. package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
  503. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  504. package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
  505. package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
  506. package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
  507. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  508. package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
  509. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  510. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  511. package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
  512. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  513. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  514. package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
  515. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  516. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  517. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +21 -5
  518. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  519. package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
  520. package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
  521. package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
  522. package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
  523. package/dist/plugins/ecosystem/node-registry-source.js +31 -30
  524. package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
  525. package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
  526. package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
  527. package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
  528. package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
  529. package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
  530. package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
  531. package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
  532. package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
  533. package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
  534. package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
  535. package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
  536. package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
  537. package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
  538. package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
  539. package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
  540. package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
  541. package/dist/plugins/ecosystem/registry.js +35 -32
  542. package/dist/plugins/ecosystem/registry.js.map +1 -1
  543. package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
  544. package/dist/plugins/ecosystem/resolver.js +3 -2
  545. package/dist/plugins/ecosystem/resolver.js.map +1 -1
  546. package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
  547. package/dist/plugins/ecosystem/selection-store.js +11 -10
  548. package/dist/plugins/ecosystem/selection-store.js.map +1 -1
  549. package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
  550. package/dist/plugins/ecosystem/selection.js +8 -7
  551. package/dist/plugins/ecosystem/selection.js.map +1 -1
  552. package/dist/plugins/ecosystem/state.d.ts.map +1 -1
  553. package/dist/plugins/ecosystem/state.js +24 -23
  554. package/dist/plugins/ecosystem/state.js.map +1 -1
  555. package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
  556. package/dist/plugins/ecosystem/updates.js +5 -4
  557. package/dist/plugins/ecosystem/updates.js.map +1 -1
  558. package/dist/plugins/mcp-http.d.ts +0 -17
  559. package/dist/plugins/mcp-http.d.ts.map +1 -1
  560. package/dist/plugins/mcp-http.js +30 -7
  561. package/dist/plugins/mcp-http.js.map +1 -1
  562. package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
  563. package/dist/plugins/plugin-supervisor.js +19 -1
  564. package/dist/plugins/plugin-supervisor.js.map +1 -1
  565. package/dist/profile/first-roles.d.ts.map +1 -1
  566. package/dist/profile/first-roles.js +10 -1
  567. package/dist/profile/first-roles.js.map +1 -1
  568. package/dist/profile/goal-plugin.d.ts.map +1 -1
  569. package/dist/profile/goal-plugin.js +24 -5
  570. package/dist/profile/goal-plugin.js.map +1 -1
  571. package/dist/profile/identity.d.ts.map +1 -1
  572. package/dist/profile/identity.js +7 -6
  573. package/dist/profile/identity.js.map +1 -1
  574. package/dist/profile/lock.d.ts.map +1 -1
  575. package/dist/profile/lock.js +15 -1
  576. package/dist/profile/lock.js.map +1 -1
  577. package/dist/profile/plan-plugin.d.ts.map +1 -1
  578. package/dist/profile/plan-plugin.js +26 -13
  579. package/dist/profile/plan-plugin.js.map +1 -1
  580. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  581. package/dist/profile/plugin-profiles.js +2 -1
  582. package/dist/profile/plugin-profiles.js.map +1 -1
  583. package/dist/profile/policy-manifest.d.ts.map +1 -1
  584. package/dist/profile/policy-manifest.js +5 -4
  585. package/dist/profile/policy-manifest.js.map +1 -1
  586. package/dist/profile/profile-registry.d.ts +0 -12
  587. package/dist/profile/profile-registry.d.ts.map +1 -1
  588. package/dist/profile/profile-registry.js +14 -1
  589. package/dist/profile/profile-registry.js.map +1 -1
  590. package/dist/profile/role-catalog.d.ts +0 -1
  591. package/dist/profile/role-catalog.d.ts.map +1 -1
  592. package/dist/profile/role-catalog.js +17 -15
  593. package/dist/profile/role-catalog.js.map +1 -1
  594. package/dist/profile/role-orchestrator.d.ts.map +1 -1
  595. package/dist/profile/role-orchestrator.js +8 -7
  596. package/dist/profile/role-orchestrator.js.map +1 -1
  597. package/dist/profile/role-runner.d.ts.map +1 -1
  598. package/dist/profile/role-runner.js +3 -2
  599. package/dist/profile/role-runner.js.map +1 -1
  600. package/dist/profile/root-facade.d.ts.map +1 -1
  601. package/dist/profile/root-facade.js +2 -1
  602. package/dist/profile/root-facade.js.map +1 -1
  603. package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
  604. package/dist/profile/skill-discovery-wiring.js +7 -2
  605. package/dist/profile/skill-discovery-wiring.js.map +1 -1
  606. package/dist/profile/state-store.d.ts.map +1 -1
  607. package/dist/profile/state-store.js +13 -9
  608. package/dist/profile/state-store.js.map +1 -1
  609. package/dist/profile/todo-plugin.d.ts.map +1 -1
  610. package/dist/profile/todo-plugin.js +9 -4
  611. package/dist/profile/todo-plugin.js.map +1 -1
  612. package/dist/profiles/builtin-suites.d.ts +13 -6
  613. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  614. package/dist/profiles/builtin-suites.js +15 -6
  615. package/dist/profiles/builtin-suites.js.map +1 -1
  616. package/dist/profiles/suite-loader.d.ts +25 -1
  617. package/dist/profiles/suite-loader.d.ts.map +1 -1
  618. package/dist/profiles/suite-loader.js +34 -9
  619. package/dist/profiles/suite-loader.js.map +1 -1
  620. package/dist/remote/server-entry.d.ts.map +1 -1
  621. package/dist/remote/server-entry.js +3 -2
  622. package/dist/remote/server-entry.js.map +1 -1
  623. package/dist/remote/session-source.d.ts.map +1 -1
  624. package/dist/remote/session-source.js +8 -4
  625. package/dist/remote/session-source.js.map +1 -1
  626. package/dist/share/session-share.d.ts.map +1 -1
  627. package/dist/share/session-share.js +14 -2
  628. package/dist/share/session-share.js.map +1 -1
  629. package/dist/testing/plugin-testkit.d.ts.map +1 -1
  630. package/dist/testing/plugin-testkit.js +4 -3
  631. package/dist/testing/plugin-testkit.js.map +1 -1
  632. package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
  633. package/dist/testing/runtime-delivery-queue.js +2 -1
  634. package/dist/testing/runtime-delivery-queue.js.map +1 -1
  635. package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
  636. package/dist/testing/session-plugin-testkit.js +10 -7
  637. package/dist/testing/session-plugin-testkit.js.map +1 -1
  638. package/dist/utils/ansi.d.ts.map +1 -1
  639. package/dist/utils/ansi.js +2 -1
  640. package/dist/utils/ansi.js.map +1 -1
  641. package/dist/utils/clipboard.d.ts.map +1 -1
  642. package/dist/utils/clipboard.js +7 -6
  643. package/dist/utils/clipboard.js.map +1 -1
  644. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  645. package/dist/utils/image-resize-worker.js +3 -2
  646. package/dist/utils/image-resize-worker.js.map +1 -1
  647. package/dist/utils/shell.d.ts.map +1 -1
  648. package/dist/utils/shell.js +9 -8
  649. package/dist/utils/shell.js.map +1 -1
  650. package/dist/utils/tools-manager.d.ts.map +1 -1
  651. package/dist/utils/tools-manager.js +23 -13
  652. package/dist/utils/tools-manager.js.map +1 -1
  653. package/dist/utils/version-check.d.ts.map +1 -1
  654. package/dist/utils/version-check.js +5 -1
  655. package/dist/utils/version-check.js.map +1 -1
  656. package/docs/keybindings.md +3 -0
  657. package/docs/quickstart.md +1 -1
  658. package/docs/settings.md +1 -0
  659. package/docs/terminal-setup.md +2 -3
  660. package/docs/usage.md +6 -5
  661. package/examples/extensions/with-deps/package-lock.json +2 -2
  662. package/examples/extensions/with-deps/package.json +1 -1
  663. package/examples/extensions/with-deps/plugin.json +1 -1
  664. package/package.json +1 -1
  665. package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
@@ -1 +1 @@
1
- {"version":3,"file":"skill-discovery-wiring.js","sourceRoot":"","sources":["../../src/profile/skill-discovery-wiring.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill/MCP discovery wiring (4.4) — turns discovered Skill and MCP tool\n * capabilities into profile-assembly inputs, with all four failure modes\n * explicit BEFORE a session exists: missing dependencies, version conflicts\n * between sources, disabled items, and replacements.\n *\n * Each registered item (a Skill or an MCP server) contributes capability\n * declarations; MCP tools derive capability ids `mcp:<serverId>:<toolName>`.\n * Two enabled items declaring the SAME capability id with DIFFERENT\n * versions is a structured version conflict; identical versions dedupe.\n * Disabled items contribute nothing (replacement = disable + register).\n * Resolution reuses the 2.5a exact-version wiring — no kernel special\n * cases. Implementation lives entirely in profile/assembly land.\n */\n\nimport type { ProfileDependencyWiringV1 } from \"./dependency-wiring.ts\";\nimport { wireProfileDependencies } from \"./dependency-wiring.ts\";\nimport type { ResolvedPluginManifestV1 } from \"./identity.ts\";\n\nexport type DiscoverySourceKindV1 = \"skill\" | \"mcp\";\n\nexport interface DiscoveredItemV1 {\n\treadonly sourceKind: DiscoverySourceKindV1;\n\treadonly itemId: string;\n\treadonly version: string;\n\treadonly capabilities: readonly { readonly id: string; readonly version: number }[];\n\treadonly enabled: boolean;\n}\n\nexport interface DiscoveryVersionConflictV1 {\n\treadonly capabilityId: string;\n\treadonly declarations: readonly {\n\t\treadonly sourceKind: DiscoverySourceKindV1;\n\t\treadonly itemId: string;\n\t\treadonly version: number;\n\t}[];\n}\n\nexport interface DiscoveryWiringV1 {\n\tregister(item: DiscoveredItemV1): void;\n\tderiveMcpItem(input: {\n\t\treadonly serverId: string;\n\t\treadonly version: string;\n\t\treadonly tools: readonly { readonly name: string; readonly description?: string }[];\n\t\treadonly enabled?: boolean;\n\t}): DiscoveredItemV1;\n\twireDiscoveredDependencies(input: {\n\t\treadonly availableCapabilities: readonly { readonly id: string; readonly version: number }[];\n\t\treadonly disabledItemIds?: readonly string[];\n\t}): { readonly conflicts: readonly DiscoveryVersionConflictV1[]; readonly wiring: ProfileDependencyWiringV1 };\n}\n\nexport function createSkillDiscoveryWiring(): DiscoveryWiringV1 {\n\tconst items = new Map<string, DiscoveredItemV1>();\n\tconst keyOf = (item: DiscoveredItemV1): string => `${item.sourceKind}:${item.itemId}`;\n\n\treturn {\n\t\tregister(item) {\n\t\t\tif (item.itemId.trim().length === 0) throw new Error(\"Discovered item id must be a non-empty string\");\n\t\t\tconst existing = items.get(keyOf(item));\n\t\t\tif (existing && existing.version !== item.version) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Item ${keyOf(item)} re-registered with a different version (${existing.version} -> ${item.version})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\titems.set(keyOf(item), { ...item, capabilities: [...item.capabilities] });\n\t\t},\n\t\tderiveMcpItem({ serverId, version, tools, enabled = true }) {\n\t\t\treturn {\n\t\t\t\tsourceKind: \"mcp\",\n\t\t\t\titemId: serverId,\n\t\t\t\tversion,\n\t\t\t\tcapabilities: tools.map((tool) => ({ id: `mcp:${serverId}:${tool.name}`, version: 1 })),\n\t\t\t\tenabled,\n\t\t\t};\n\t\t},\n\t\twireDiscoveredDependencies({ availableCapabilities, disabledItemIds }) {\n\t\t\tconst disabled = new Set(disabledItemIds ?? []);\n\t\t\tconst enabledItems = [...items.values()].filter((item) => item.enabled && !disabled.has(keyOf(item)));\n\n\t\t\t// Version conflicts: same capability id, different declared versions,\n\t\t\t// across different enabled items.\n\t\t\tconst byCapability = new Map<\n\t\t\t\tstring,\n\t\t\t\tArray<{ sourceKind: DiscoverySourceKindV1; itemId: string; version: number }>\n\t\t\t>();\n\t\t\tfor (const item of enabledItems) {\n\t\t\t\tfor (const capability of item.capabilities) {\n\t\t\t\t\tconst list = byCapability.get(capability.id) ?? [];\n\t\t\t\t\tif (!list.some((entry) => entry.itemId === item.itemId)) {\n\t\t\t\t\t\tlist.push({ sourceKind: item.sourceKind, itemId: item.itemId, version: capability.version });\n\t\t\t\t\t}\n\t\t\t\t\tbyCapability.set(capability.id, list);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst conflicts: DiscoveryVersionConflictV1[] = [];\n\t\t\tfor (const [capabilityId, declarations] of byCapability) {\n\t\t\t\tconst versions = new Set(declarations.map((entry) => entry.version));\n\t\t\t\tif (versions.size > 1) conflicts.push({ capabilityId, declarations });\n\t\t\t}\n\n\t\t\t// Disabled items stay in the manifests so the wiring result shows an\n\t\t\t// explicit skipped_disabled entry (visible audit, not silent removal).\n\t\t\tconst manifests: ResolvedPluginManifestV1[] = [...items.values()].map((item) => ({\n\t\t\t\tpluginId: keyOf(item),\n\t\t\t\tpluginVersion: item.version,\n\t\t\t\tcapabilityRefs: [...item.capabilities],\n\t\t\t}));\n\t\t\tconst wiring = wireProfileDependencies({\n\t\t\t\tresolvedPlugins: manifests,\n\t\t\t\tavailableCapabilities,\n\t\t\t\tdisabledPluginIds: disabledItemIds,\n\t\t\t});\n\t\t\treturn { conflicts: Object.freeze(conflicts), wiring };\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"skill-discovery-wiring.js","sourceRoot":"","sources":["../../src/profile/skill-discovery-wiring.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill/MCP discovery wiring (4.4) — turns discovered Skill and MCP tool\n * capabilities into profile-assembly inputs, with all four failure modes\n * explicit BEFORE a session exists: missing dependencies, version conflicts\n * between sources, disabled items, and replacements.\n *\n * Each registered item (a Skill or an MCP server) contributes capability\n * declarations; MCP tools derive capability ids `mcp:<serverId>:<toolName>`.\n * Two enabled items declaring the SAME capability id with DIFFERENT\n * versions is a structured version conflict; identical versions dedupe.\n * Disabled items contribute nothing (replacement = disable + register).\n * Resolution reuses the 2.5a exact-version wiring — no kernel special\n * cases. Implementation lives entirely in profile/assembly land.\n */\n\nimport { t } from \"../core/i18n/index.ts\";\nimport type { ProfileDependencyWiringV1 } from \"./dependency-wiring.ts\";\nimport { wireProfileDependencies } from \"./dependency-wiring.ts\";\nimport type { ResolvedPluginManifestV1 } from \"./identity.ts\";\n\nexport type DiscoverySourceKindV1 = \"skill\" | \"mcp\";\n\nexport interface DiscoveredItemV1 {\n\treadonly sourceKind: DiscoverySourceKindV1;\n\treadonly itemId: string;\n\treadonly version: string;\n\treadonly capabilities: readonly { readonly id: string; readonly version: number }[];\n\treadonly enabled: boolean;\n}\n\nexport interface DiscoveryVersionConflictV1 {\n\treadonly capabilityId: string;\n\treadonly declarations: readonly {\n\t\treadonly sourceKind: DiscoverySourceKindV1;\n\t\treadonly itemId: string;\n\t\treadonly version: number;\n\t}[];\n}\n\nexport interface DiscoveryWiringV1 {\n\tregister(item: DiscoveredItemV1): void;\n\tderiveMcpItem(input: {\n\t\treadonly serverId: string;\n\t\treadonly version: string;\n\t\treadonly tools: readonly { readonly name: string; readonly description?: string }[];\n\t\treadonly enabled?: boolean;\n\t}): DiscoveredItemV1;\n\twireDiscoveredDependencies(input: {\n\t\treadonly availableCapabilities: readonly { readonly id: string; readonly version: number }[];\n\t\treadonly disabledItemIds?: readonly string[];\n\t}): { readonly conflicts: readonly DiscoveryVersionConflictV1[]; readonly wiring: ProfileDependencyWiringV1 };\n}\n\nexport function createSkillDiscoveryWiring(): DiscoveryWiringV1 {\n\tconst items = new Map<string, DiscoveredItemV1>();\n\tconst keyOf = (item: DiscoveredItemV1): string => `${item.sourceKind}:${item.itemId}`;\n\n\treturn {\n\t\tregister(item) {\n\t\t\tif (item.itemId.trim().length === 0) throw new Error(t(\"Discovered item id must be a non-empty string\"));\n\t\t\tconst existing = items.get(keyOf(item));\n\t\t\tif (existing && existing.version !== item.version) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt(\"Item {key} re-registered with a different version ({from} -> {to})\", {\n\t\t\t\t\t\tkey: keyOf(item),\n\t\t\t\t\t\tfrom: existing.version,\n\t\t\t\t\t\tto: item.version,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\titems.set(keyOf(item), { ...item, capabilities: [...item.capabilities] });\n\t\t},\n\t\tderiveMcpItem({ serverId, version, tools, enabled = true }) {\n\t\t\treturn {\n\t\t\t\tsourceKind: \"mcp\",\n\t\t\t\titemId: serverId,\n\t\t\t\tversion,\n\t\t\t\tcapabilities: tools.map((tool) => ({ id: `mcp:${serverId}:${tool.name}`, version: 1 })),\n\t\t\t\tenabled,\n\t\t\t};\n\t\t},\n\t\twireDiscoveredDependencies({ availableCapabilities, disabledItemIds }) {\n\t\t\tconst disabled = new Set(disabledItemIds ?? []);\n\t\t\tconst enabledItems = [...items.values()].filter((item) => item.enabled && !disabled.has(keyOf(item)));\n\n\t\t\t// Version conflicts: same capability id, different declared versions,\n\t\t\t// across different enabled items.\n\t\t\tconst byCapability = new Map<\n\t\t\t\tstring,\n\t\t\t\tArray<{ sourceKind: DiscoverySourceKindV1; itemId: string; version: number }>\n\t\t\t>();\n\t\t\tfor (const item of enabledItems) {\n\t\t\t\tfor (const capability of item.capabilities) {\n\t\t\t\t\tconst list = byCapability.get(capability.id) ?? [];\n\t\t\t\t\tif (!list.some((entry) => entry.itemId === item.itemId)) {\n\t\t\t\t\t\tlist.push({ sourceKind: item.sourceKind, itemId: item.itemId, version: capability.version });\n\t\t\t\t\t}\n\t\t\t\t\tbyCapability.set(capability.id, list);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst conflicts: DiscoveryVersionConflictV1[] = [];\n\t\t\tfor (const [capabilityId, declarations] of byCapability) {\n\t\t\t\tconst versions = new Set(declarations.map((entry) => entry.version));\n\t\t\t\tif (versions.size > 1) conflicts.push({ capabilityId, declarations });\n\t\t\t}\n\n\t\t\t// Disabled items stay in the manifests so the wiring result shows an\n\t\t\t// explicit skipped_disabled entry (visible audit, not silent removal).\n\t\t\tconst manifests: ResolvedPluginManifestV1[] = [...items.values()].map((item) => ({\n\t\t\t\tpluginId: keyOf(item),\n\t\t\t\tpluginVersion: item.version,\n\t\t\t\tcapabilityRefs: [...item.capabilities],\n\t\t\t}));\n\t\t\tconst wiring = wireProfileDependencies({\n\t\t\t\tresolvedPlugins: manifests,\n\t\t\t\tavailableCapabilities,\n\t\t\t\tdisabledPluginIds: disabledItemIds,\n\t\t\t});\n\t\t\treturn { conflicts: Object.freeze(conflicts), wiring };\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/profile/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAyDD,MAAM,WAAW,iBAAiB;IACjC,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAAC;IACzD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAAC;IACzD,iFAAiF;IACjF,MAAM,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,CAAC;IACrD,QAAQ,IAAI,SAAS,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAAG,iBAAiB,CAiFtG","sourcesContent":["/**\n * Generic transition/evidence/revision store (2.3a) — the domain-agnostic\n * contract base for Goal/Plan/Todo plugins.\n *\n * The store knows NOTHING about goal/plan/todo semantics. It only enforces:\n * - causality: a transition's `fromStatus` must equal the entity's current\n * status (null = initial transition), otherwise an explicit conflict;\n * - idempotency: replaying the same (domain, entityId, operationId, toStatus)\n * returns the existing record and never advances the revision;\n * - evidence: every transition carries structured evidence references;\n * - payload: transitions may carry an optional domain payload (e.g. a goal\n * title) that is validated JSON and part of the replayable record;\n * - replay: the full history rebuilds the identical current state.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\n\nexport interface TransitionEvidenceRefV1 {\n\treadonly kind: string;\n\treadonly ref: string;\n\treadonly digest?: string;\n}\n\nexport interface TransitionRecordV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly revision: number;\n\treadonly at: number;\n}\n\nexport interface TransitionInputV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly at?: number;\n}\n\nexport interface TransitionResultV1 {\n\treadonly record: TransitionRecordV1;\n\treadonly deduped: boolean;\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\nfunction validateEvidence(value: unknown, label: string): TransitionEvidenceRefV1[] {\n\tif (value === undefined) return [];\n\tif (!Array.isArray(value)) throw new Error(`${label} must be an array`);\n\treturn value.map((item, index) => {\n\t\tconst depLabel = `${label}[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(`${depLabel} must be a plain object`);\n\t\t}\n\t\tconst record = item as Record<string, unknown>;\n\t\tassertNonEmptyString(record.kind, `${depLabel}.kind`);\n\t\tassertNonEmptyString(record.ref, `${depLabel}.ref`);\n\t\tif (record.digest !== undefined) assertNonEmptyString(record.digest, `${depLabel}.digest`);\n\t\treturn Object.freeze({\n\t\t\tkind: record.kind,\n\t\t\tref: record.ref,\n\t\t\t...(record.digest === undefined ? {} : { digest: record.digest }),\n\t\t});\n\t});\n}\n\nfunction validatePayload(value: unknown, label: string): JsonValue | undefined {\n\tif (value === undefined) return undefined;\n\tconst seen = new Set<object>();\n\tconst check = (node: unknown): void => {\n\t\tif (node === null || typeof node === \"string\" || typeof node === \"boolean\") return;\n\t\tif (typeof node === \"number\") {\n\t\t\tif (!Number.isFinite(node)) throw new Error(`${label} must be JSON-safe: ${node} is not a finite number`);\n\t\t\treturn;\n\t\t}\n\t\tif (typeof node === \"object\") {\n\t\t\tif (seen.has(node)) throw new Error(`${label} must be JSON-safe: circular reference`);\n\t\t\tseen.add(node);\n\t\t\tif (Array.isArray(node)) {\n\t\t\t\tfor (const item of node) check(item);\n\t\t\t} else {\n\t\t\t\tconst proto = Object.getPrototypeOf(node) as unknown;\n\t\t\t\tif (proto !== Object.prototype && proto !== null) throw new Error(`${label} must be a plain object`);\n\t\t\t\tfor (const entry of Object.entries(node)) {\n\t\t\t\t\tif (entry[1] === undefined) throw new Error(`${label} must be JSON-safe: ${entry[0]} is undefined`);\n\t\t\t\t\tcheck(entry[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tseen.delete(node);\n\t\t\treturn;\n\t\t}\n\t\tthrow new Error(`${label} must be JSON-safe: unsupported value of type ${typeof node}`);\n\t};\n\tcheck(value);\n\treturn JSON.parse(JSON.stringify(value)) as JsonValue;\n}\n\nexport interface TransitionStoreV1 {\n\ttransition(input: TransitionInputV1): TransitionResultV1;\n\tcurrentStatus(domain: string, entityId: string): { readonly status: string; readonly revision: number } | undefined;\n\thistory(entityId: string): readonly TransitionRecordV1[];\n\t/** Replays a history into a fresh store; the rebuilt state must be identical. */\n\treplay(history: readonly TransitionRecordV1[]): void;\n\tentities(): readonly string[];\n}\n\nexport function createTransitionStore(options: { readonly now?: () => number } = {}): TransitionStoreV1 {\n\tconst now = options.now ?? (() => Date.now());\n\tconst recordsByEntity = new Map<string, TransitionRecordV1[]>();\n\tconst idempotency = new Map<string, TransitionRecordV1>();\n\tconst currentStatus = new Map<string, { status: string; revision: number }>();\n\tconst revisions = new Map<string, number>();\n\n\tconst entityKey = (domain: string, entityId: string): string => `${domain}\\u0000${entityId}`;\n\n\treturn {\n\t\ttransition(input) {\n\t\t\tassertNonEmptyString(input.domain, \"Transition domain\");\n\t\t\tassertNonEmptyString(input.entityId, \"Transition entityId\");\n\t\t\tassertNonEmptyString(input.owner, \"Transition owner\");\n\t\t\tassertNonEmptyString(input.operationId, \"Transition operationId\");\n\t\t\tassertNonEmptyString(input.toStatus, \"Transition toStatus\");\n\t\t\tconst evidence = validateEvidence(input.evidence, \"Transition evidence\");\n\t\t\tconst payload = validatePayload(input.payload, \"Transition payload\");\n\t\t\tconst key = `${entityKey(input.domain, input.entityId)}\\u0000${input.operationId}\\u0000${input.toStatus}`;\n\n\t\t\tconst existing = idempotency.get(key);\n\t\t\tif (existing) return { record: existing, deduped: true };\n\n\t\t\tconst entityKeyId = entityKey(input.domain, input.entityId);\n\t\t\tconst current = currentStatus.get(entityKeyId);\n\t\t\tconst fromStatus = input.fromStatus;\n\t\t\tif ((current?.status ?? null) !== fromStatus) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Transition conflict: expected fromStatus ${JSON.stringify(current?.status ?? null)}, got ${JSON.stringify(fromStatus)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst revision = (revisions.get(entityKeyId) ?? 0) + 1;\n\t\t\trevisions.set(entityKeyId, revision);\n\t\t\tconst record: TransitionRecordV1 = Object.freeze({\n\t\t\t\tdomain: input.domain,\n\t\t\t\tentityId: input.entityId,\n\t\t\t\towner: input.owner,\n\t\t\t\tfromStatus,\n\t\t\t\ttoStatus: input.toStatus,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tevidence: Object.freeze(evidence),\n\t\t\t\t...(payload === undefined ? {} : { payload }),\n\t\t\t\trevision,\n\t\t\t\tat: input.at ?? now(),\n\t\t\t});\n\t\t\tconst log = recordsByEntity.get(entityKeyId) ?? [];\n\t\t\tlog.push(record);\n\t\t\trecordsByEntity.set(entityKeyId, log);\n\t\t\tcurrentStatus.set(entityKeyId, { status: input.toStatus, revision });\n\t\t\tidempotency.set(key, record);\n\t\t\treturn { record, deduped: false };\n\t\t},\n\t\tcurrentStatus(domain: string, entityId: string) {\n\t\t\treturn currentStatus.get(entityKey(domain, entityId));\n\t\t},\n\t\thistory(entityId: string) {\n\t\t\treturn Object.freeze(\n\t\t\t\t[...recordsByEntity.entries()]\n\t\t\t\t\t.filter(([entityKeyId]) => entityKeyId.endsWith(`\\u0000${entityId}`))\n\t\t\t\t\t.flatMap(([, log]) => log),\n\t\t\t);\n\t\t},\n\t\treplay(history) {\n\t\t\tfor (const record of history) {\n\t\t\t\tthis.transition({\n\t\t\t\t\tdomain: record.domain,\n\t\t\t\t\tentityId: record.entityId,\n\t\t\t\t\towner: record.owner,\n\t\t\t\t\tfromStatus: record.fromStatus,\n\t\t\t\t\ttoStatus: record.toStatus,\n\t\t\t\t\toperationId: record.operationId,\n\t\t\t\t\tevidence: record.evidence,\n\t\t\t\t\tpayload: record.payload,\n\t\t\t\t\tat: record.at,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tentities() {\n\t\t\treturn Object.freeze([...new Set([...currentStatus.keys()].map((key) => key.split(\"\\u0000\")[1]!))]);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/profile/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AA+DD,MAAM,WAAW,iBAAiB;IACjC,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAAC;IACzD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAAC;IACzD,iFAAiF;IACjF,MAAM,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,CAAC;IACrD,QAAQ,IAAI,SAAS,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAAG,iBAAiB,CAoFtG","sourcesContent":["/**\n * Generic transition/evidence/revision store (2.3a) — the domain-agnostic\n * contract base for Goal/Plan/Todo plugins.\n *\n * The store knows NOTHING about goal/plan/todo semantics. It only enforces:\n * - causality: a transition's `fromStatus` must equal the entity's current\n * status (null = initial transition), otherwise an explicit conflict;\n * - idempotency: replaying the same (domain, entityId, operationId, toStatus)\n * returns the existing record and never advances the revision;\n * - evidence: every transition carries structured evidence references;\n * - payload: transitions may carry an optional domain payload (e.g. a goal\n * title) that is validated JSON and part of the replayable record;\n * - replay: the full history rebuilds the identical current state.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport { t } from \"../core/i18n/index.ts\";\n\nexport interface TransitionEvidenceRefV1 {\n\treadonly kind: string;\n\treadonly ref: string;\n\treadonly digest?: string;\n}\n\nexport interface TransitionRecordV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly revision: number;\n\treadonly at: number;\n}\n\nexport interface TransitionInputV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly at?: number;\n}\n\nexport interface TransitionResultV1 {\n\treadonly record: TransitionRecordV1;\n\treadonly deduped: boolean;\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0)\n\t\tthrow new Error(t(\"{label} must be a non-empty string\", { label }));\n}\n\nfunction validateEvidence(value: unknown, label: string): TransitionEvidenceRefV1[] {\n\tif (value === undefined) return [];\n\tif (!Array.isArray(value)) throw new Error(t(\"{label} must be an array\", { label }));\n\treturn value.map((item, index) => {\n\t\tconst depLabel = `${label}[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(t(\"{label} must be a plain object\", { label: depLabel }));\n\t\t}\n\t\tconst record = item as Record<string, unknown>;\n\t\tassertNonEmptyString(record.kind, `${depLabel}.kind`);\n\t\tassertNonEmptyString(record.ref, `${depLabel}.ref`);\n\t\tif (record.digest !== undefined) assertNonEmptyString(record.digest, `${depLabel}.digest`);\n\t\treturn Object.freeze({\n\t\t\tkind: record.kind,\n\t\t\tref: record.ref,\n\t\t\t...(record.digest === undefined ? {} : { digest: record.digest }),\n\t\t});\n\t});\n}\n\nfunction validatePayload(value: unknown, label: string): JsonValue | undefined {\n\tif (value === undefined) return undefined;\n\tconst seen = new Set<object>();\n\tconst check = (node: unknown): void => {\n\t\tif (node === null || typeof node === \"string\" || typeof node === \"boolean\") return;\n\t\tif (typeof node === \"number\") {\n\t\t\tif (!Number.isFinite(node))\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt(\"{label} must be JSON-safe: {node} is not a finite number\", { label, node: String(node) }),\n\t\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (typeof node === \"object\") {\n\t\t\tif (seen.has(node)) throw new Error(t(\"{label} must be JSON-safe: circular reference\", { label }));\n\t\t\tseen.add(node);\n\t\t\tif (Array.isArray(node)) {\n\t\t\t\tfor (const item of node) check(item);\n\t\t\t} else {\n\t\t\t\tconst proto = Object.getPrototypeOf(node) as unknown;\n\t\t\t\tif (proto !== Object.prototype && proto !== null)\n\t\t\t\t\tthrow new Error(t(\"{label} must be a plain object\", { label }));\n\t\t\t\tfor (const entry of Object.entries(node)) {\n\t\t\t\t\tif (entry[1] === undefined)\n\t\t\t\t\t\tthrow new Error(t(\"{label} must be JSON-safe: {key} is undefined\", { label, key: entry[0] }));\n\t\t\t\t\tcheck(entry[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tseen.delete(node);\n\t\t\treturn;\n\t\t}\n\t\tthrow new Error(t(\"{label} must be JSON-safe: unsupported value of type {type}\", { label, type: typeof node }));\n\t};\n\tcheck(value);\n\treturn JSON.parse(JSON.stringify(value)) as JsonValue;\n}\n\nexport interface TransitionStoreV1 {\n\ttransition(input: TransitionInputV1): TransitionResultV1;\n\tcurrentStatus(domain: string, entityId: string): { readonly status: string; readonly revision: number } | undefined;\n\thistory(entityId: string): readonly TransitionRecordV1[];\n\t/** Replays a history into a fresh store; the rebuilt state must be identical. */\n\treplay(history: readonly TransitionRecordV1[]): void;\n\tentities(): readonly string[];\n}\n\nexport function createTransitionStore(options: { readonly now?: () => number } = {}): TransitionStoreV1 {\n\tconst now = options.now ?? (() => Date.now());\n\tconst recordsByEntity = new Map<string, TransitionRecordV1[]>();\n\tconst idempotency = new Map<string, TransitionRecordV1>();\n\tconst currentStatus = new Map<string, { status: string; revision: number }>();\n\tconst revisions = new Map<string, number>();\n\n\tconst entityKey = (domain: string, entityId: string): string => `${domain}\\u0000${entityId}`;\n\n\treturn {\n\t\ttransition(input) {\n\t\t\tassertNonEmptyString(input.domain, \"Transition domain\");\n\t\t\tassertNonEmptyString(input.entityId, \"Transition entityId\");\n\t\t\tassertNonEmptyString(input.owner, \"Transition owner\");\n\t\t\tassertNonEmptyString(input.operationId, \"Transition operationId\");\n\t\t\tassertNonEmptyString(input.toStatus, \"Transition toStatus\");\n\t\t\tconst evidence = validateEvidence(input.evidence, \"Transition evidence\");\n\t\t\tconst payload = validatePayload(input.payload, \"Transition payload\");\n\t\t\tconst key = `${entityKey(input.domain, input.entityId)}\\u0000${input.operationId}\\u0000${input.toStatus}`;\n\n\t\t\tconst existing = idempotency.get(key);\n\t\t\tif (existing) return { record: existing, deduped: true };\n\n\t\t\tconst entityKeyId = entityKey(input.domain, input.entityId);\n\t\t\tconst current = currentStatus.get(entityKeyId);\n\t\t\tconst fromStatus = input.fromStatus;\n\t\t\tif ((current?.status ?? null) !== fromStatus) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt(\"Transition conflict: expected fromStatus {from}, got {to}\", {\n\t\t\t\t\t\tfrom: JSON.stringify(current?.status ?? null),\n\t\t\t\t\t\tto: JSON.stringify(fromStatus),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst revision = (revisions.get(entityKeyId) ?? 0) + 1;\n\t\t\trevisions.set(entityKeyId, revision);\n\t\t\tconst record: TransitionRecordV1 = Object.freeze({\n\t\t\t\tdomain: input.domain,\n\t\t\t\tentityId: input.entityId,\n\t\t\t\towner: input.owner,\n\t\t\t\tfromStatus,\n\t\t\t\ttoStatus: input.toStatus,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tevidence: Object.freeze(evidence),\n\t\t\t\t...(payload === undefined ? {} : { payload }),\n\t\t\t\trevision,\n\t\t\t\tat: input.at ?? now(),\n\t\t\t});\n\t\t\tconst log = recordsByEntity.get(entityKeyId) ?? [];\n\t\t\tlog.push(record);\n\t\t\trecordsByEntity.set(entityKeyId, log);\n\t\t\tcurrentStatus.set(entityKeyId, { status: input.toStatus, revision });\n\t\t\tidempotency.set(key, record);\n\t\t\treturn { record, deduped: false };\n\t\t},\n\t\tcurrentStatus(domain: string, entityId: string) {\n\t\t\treturn currentStatus.get(entityKey(domain, entityId));\n\t\t},\n\t\thistory(entityId: string) {\n\t\t\treturn Object.freeze(\n\t\t\t\t[...recordsByEntity.entries()]\n\t\t\t\t\t.filter(([entityKeyId]) => entityKeyId.endsWith(`\\u0000${entityId}`))\n\t\t\t\t\t.flatMap(([, log]) => log),\n\t\t\t);\n\t\t},\n\t\treplay(history) {\n\t\t\tfor (const record of history) {\n\t\t\t\tthis.transition({\n\t\t\t\t\tdomain: record.domain,\n\t\t\t\t\tentityId: record.entityId,\n\t\t\t\t\towner: record.owner,\n\t\t\t\t\tfromStatus: record.fromStatus,\n\t\t\t\t\ttoStatus: record.toStatus,\n\t\t\t\t\toperationId: record.operationId,\n\t\t\t\t\tevidence: record.evidence,\n\t\t\t\t\tpayload: record.payload,\n\t\t\t\t\tat: record.at,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tentities() {\n\t\t\treturn Object.freeze([...new Set([...currentStatus.keys()].map((key) => key.split(\"\\u0000\")[1]!))]);\n\t\t},\n\t};\n}\n"]}
@@ -1,16 +1,17 @@
1
+ import { t } from "../core/i18n/index.js";
1
2
  function assertNonEmptyString(value, label) {
2
3
  if (typeof value !== "string" || value.trim().length === 0)
3
- throw new Error(`${label} must be a non-empty string`);
4
+ throw new Error(t("{label} must be a non-empty string", { label }));
4
5
  }
5
6
  function validateEvidence(value, label) {
6
7
  if (value === undefined)
7
8
  return [];
8
9
  if (!Array.isArray(value))
9
- throw new Error(`${label} must be an array`);
10
+ throw new Error(t("{label} must be an array", { label }));
10
11
  return value.map((item, index) => {
11
12
  const depLabel = `${label}[${index}]`;
12
13
  if (item === null || typeof item !== "object" || Array.isArray(item)) {
13
- throw new Error(`${depLabel} must be a plain object`);
14
+ throw new Error(t("{label} must be a plain object", { label: depLabel }));
14
15
  }
15
16
  const record = item;
16
17
  assertNonEmptyString(record.kind, `${depLabel}.kind`);
@@ -33,12 +34,12 @@ function validatePayload(value, label) {
33
34
  return;
34
35
  if (typeof node === "number") {
35
36
  if (!Number.isFinite(node))
36
- throw new Error(`${label} must be JSON-safe: ${node} is not a finite number`);
37
+ throw new Error(t("{label} must be JSON-safe: {node} is not a finite number", { label, node: String(node) }));
37
38
  return;
38
39
  }
39
40
  if (typeof node === "object") {
40
41
  if (seen.has(node))
41
- throw new Error(`${label} must be JSON-safe: circular reference`);
42
+ throw new Error(t("{label} must be JSON-safe: circular reference", { label }));
42
43
  seen.add(node);
43
44
  if (Array.isArray(node)) {
44
45
  for (const item of node)
@@ -47,17 +48,17 @@ function validatePayload(value, label) {
47
48
  else {
48
49
  const proto = Object.getPrototypeOf(node);
49
50
  if (proto !== Object.prototype && proto !== null)
50
- throw new Error(`${label} must be a plain object`);
51
+ throw new Error(t("{label} must be a plain object", { label }));
51
52
  for (const entry of Object.entries(node)) {
52
53
  if (entry[1] === undefined)
53
- throw new Error(`${label} must be JSON-safe: ${entry[0]} is undefined`);
54
+ throw new Error(t("{label} must be JSON-safe: {key} is undefined", { label, key: entry[0] }));
54
55
  check(entry[1]);
55
56
  }
56
57
  }
57
58
  seen.delete(node);
58
59
  return;
59
60
  }
60
- throw new Error(`${label} must be JSON-safe: unsupported value of type ${typeof node}`);
61
+ throw new Error(t("{label} must be JSON-safe: unsupported value of type {type}", { label, type: typeof node }));
61
62
  };
62
63
  check(value);
63
64
  return JSON.parse(JSON.stringify(value));
@@ -86,7 +87,10 @@ export function createTransitionStore(options = {}) {
86
87
  const current = currentStatus.get(entityKeyId);
87
88
  const fromStatus = input.fromStatus;
88
89
  if ((current?.status ?? null) !== fromStatus) {
89
- throw new Error(`Transition conflict: expected fromStatus ${JSON.stringify(current?.status ?? null)}, got ${JSON.stringify(fromStatus)}`);
90
+ throw new Error(t("Transition conflict: expected fromStatus {from}, got {to}", {
91
+ from: JSON.stringify(current?.status ?? null),
92
+ to: JSON.stringify(fromStatus),
93
+ }));
90
94
  }
91
95
  const revision = (revisions.get(entityKeyId) ?? 0) + 1;
92
96
  revisions.set(entityKeyId, revision);
@@ -1 +1 @@
1
- {"version":3,"file":"state-store.js","sourceRoot":"","sources":["../../src/profile/state-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generic transition/evidence/revision store (2.3a) — the domain-agnostic\n * contract base for Goal/Plan/Todo plugins.\n *\n * The store knows NOTHING about goal/plan/todo semantics. It only enforces:\n * - causality: a transition's `fromStatus` must equal the entity's current\n * status (null = initial transition), otherwise an explicit conflict;\n * - idempotency: replaying the same (domain, entityId, operationId, toStatus)\n * returns the existing record and never advances the revision;\n * - evidence: every transition carries structured evidence references;\n * - payload: transitions may carry an optional domain payload (e.g. a goal\n * title) that is validated JSON and part of the replayable record;\n * - replay: the full history rebuilds the identical current state.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\n\nexport interface TransitionEvidenceRefV1 {\n\treadonly kind: string;\n\treadonly ref: string;\n\treadonly digest?: string;\n}\n\nexport interface TransitionRecordV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly revision: number;\n\treadonly at: number;\n}\n\nexport interface TransitionInputV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly at?: number;\n}\n\nexport interface TransitionResultV1 {\n\treadonly record: TransitionRecordV1;\n\treadonly deduped: boolean;\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\nfunction validateEvidence(value: unknown, label: string): TransitionEvidenceRefV1[] {\n\tif (value === undefined) return [];\n\tif (!Array.isArray(value)) throw new Error(`${label} must be an array`);\n\treturn value.map((item, index) => {\n\t\tconst depLabel = `${label}[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(`${depLabel} must be a plain object`);\n\t\t}\n\t\tconst record = item as Record<string, unknown>;\n\t\tassertNonEmptyString(record.kind, `${depLabel}.kind`);\n\t\tassertNonEmptyString(record.ref, `${depLabel}.ref`);\n\t\tif (record.digest !== undefined) assertNonEmptyString(record.digest, `${depLabel}.digest`);\n\t\treturn Object.freeze({\n\t\t\tkind: record.kind,\n\t\t\tref: record.ref,\n\t\t\t...(record.digest === undefined ? {} : { digest: record.digest }),\n\t\t});\n\t});\n}\n\nfunction validatePayload(value: unknown, label: string): JsonValue | undefined {\n\tif (value === undefined) return undefined;\n\tconst seen = new Set<object>();\n\tconst check = (node: unknown): void => {\n\t\tif (node === null || typeof node === \"string\" || typeof node === \"boolean\") return;\n\t\tif (typeof node === \"number\") {\n\t\t\tif (!Number.isFinite(node)) throw new Error(`${label} must be JSON-safe: ${node} is not a finite number`);\n\t\t\treturn;\n\t\t}\n\t\tif (typeof node === \"object\") {\n\t\t\tif (seen.has(node)) throw new Error(`${label} must be JSON-safe: circular reference`);\n\t\t\tseen.add(node);\n\t\t\tif (Array.isArray(node)) {\n\t\t\t\tfor (const item of node) check(item);\n\t\t\t} else {\n\t\t\t\tconst proto = Object.getPrototypeOf(node) as unknown;\n\t\t\t\tif (proto !== Object.prototype && proto !== null) throw new Error(`${label} must be a plain object`);\n\t\t\t\tfor (const entry of Object.entries(node)) {\n\t\t\t\t\tif (entry[1] === undefined) throw new Error(`${label} must be JSON-safe: ${entry[0]} is undefined`);\n\t\t\t\t\tcheck(entry[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tseen.delete(node);\n\t\t\treturn;\n\t\t}\n\t\tthrow new Error(`${label} must be JSON-safe: unsupported value of type ${typeof node}`);\n\t};\n\tcheck(value);\n\treturn JSON.parse(JSON.stringify(value)) as JsonValue;\n}\n\nexport interface TransitionStoreV1 {\n\ttransition(input: TransitionInputV1): TransitionResultV1;\n\tcurrentStatus(domain: string, entityId: string): { readonly status: string; readonly revision: number } | undefined;\n\thistory(entityId: string): readonly TransitionRecordV1[];\n\t/** Replays a history into a fresh store; the rebuilt state must be identical. */\n\treplay(history: readonly TransitionRecordV1[]): void;\n\tentities(): readonly string[];\n}\n\nexport function createTransitionStore(options: { readonly now?: () => number } = {}): TransitionStoreV1 {\n\tconst now = options.now ?? (() => Date.now());\n\tconst recordsByEntity = new Map<string, TransitionRecordV1[]>();\n\tconst idempotency = new Map<string, TransitionRecordV1>();\n\tconst currentStatus = new Map<string, { status: string; revision: number }>();\n\tconst revisions = new Map<string, number>();\n\n\tconst entityKey = (domain: string, entityId: string): string => `${domain}\\u0000${entityId}`;\n\n\treturn {\n\t\ttransition(input) {\n\t\t\tassertNonEmptyString(input.domain, \"Transition domain\");\n\t\t\tassertNonEmptyString(input.entityId, \"Transition entityId\");\n\t\t\tassertNonEmptyString(input.owner, \"Transition owner\");\n\t\t\tassertNonEmptyString(input.operationId, \"Transition operationId\");\n\t\t\tassertNonEmptyString(input.toStatus, \"Transition toStatus\");\n\t\t\tconst evidence = validateEvidence(input.evidence, \"Transition evidence\");\n\t\t\tconst payload = validatePayload(input.payload, \"Transition payload\");\n\t\t\tconst key = `${entityKey(input.domain, input.entityId)}\\u0000${input.operationId}\\u0000${input.toStatus}`;\n\n\t\t\tconst existing = idempotency.get(key);\n\t\t\tif (existing) return { record: existing, deduped: true };\n\n\t\t\tconst entityKeyId = entityKey(input.domain, input.entityId);\n\t\t\tconst current = currentStatus.get(entityKeyId);\n\t\t\tconst fromStatus = input.fromStatus;\n\t\t\tif ((current?.status ?? null) !== fromStatus) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Transition conflict: expected fromStatus ${JSON.stringify(current?.status ?? null)}, got ${JSON.stringify(fromStatus)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst revision = (revisions.get(entityKeyId) ?? 0) + 1;\n\t\t\trevisions.set(entityKeyId, revision);\n\t\t\tconst record: TransitionRecordV1 = Object.freeze({\n\t\t\t\tdomain: input.domain,\n\t\t\t\tentityId: input.entityId,\n\t\t\t\towner: input.owner,\n\t\t\t\tfromStatus,\n\t\t\t\ttoStatus: input.toStatus,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tevidence: Object.freeze(evidence),\n\t\t\t\t...(payload === undefined ? {} : { payload }),\n\t\t\t\trevision,\n\t\t\t\tat: input.at ?? now(),\n\t\t\t});\n\t\t\tconst log = recordsByEntity.get(entityKeyId) ?? [];\n\t\t\tlog.push(record);\n\t\t\trecordsByEntity.set(entityKeyId, log);\n\t\t\tcurrentStatus.set(entityKeyId, { status: input.toStatus, revision });\n\t\t\tidempotency.set(key, record);\n\t\t\treturn { record, deduped: false };\n\t\t},\n\t\tcurrentStatus(domain: string, entityId: string) {\n\t\t\treturn currentStatus.get(entityKey(domain, entityId));\n\t\t},\n\t\thistory(entityId: string) {\n\t\t\treturn Object.freeze(\n\t\t\t\t[...recordsByEntity.entries()]\n\t\t\t\t\t.filter(([entityKeyId]) => entityKeyId.endsWith(`\\u0000${entityId}`))\n\t\t\t\t\t.flatMap(([, log]) => log),\n\t\t\t);\n\t\t},\n\t\treplay(history) {\n\t\t\tfor (const record of history) {\n\t\t\t\tthis.transition({\n\t\t\t\t\tdomain: record.domain,\n\t\t\t\t\tentityId: record.entityId,\n\t\t\t\t\towner: record.owner,\n\t\t\t\t\tfromStatus: record.fromStatus,\n\t\t\t\t\ttoStatus: record.toStatus,\n\t\t\t\t\toperationId: record.operationId,\n\t\t\t\t\tevidence: record.evidence,\n\t\t\t\t\tpayload: record.payload,\n\t\t\t\t\tat: record.at,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tentities() {\n\t\t\treturn Object.freeze([...new Set([...currentStatus.keys()].map((key) => key.split(\"\\u0000\")[1]!))]);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"state-store.js","sourceRoot":"","sources":["../../src/profile/state-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generic transition/evidence/revision store (2.3a) — the domain-agnostic\n * contract base for Goal/Plan/Todo plugins.\n *\n * The store knows NOTHING about goal/plan/todo semantics. It only enforces:\n * - causality: a transition's `fromStatus` must equal the entity's current\n * status (null = initial transition), otherwise an explicit conflict;\n * - idempotency: replaying the same (domain, entityId, operationId, toStatus)\n * returns the existing record and never advances the revision;\n * - evidence: every transition carries structured evidence references;\n * - payload: transitions may carry an optional domain payload (e.g. a goal\n * title) that is validated JSON and part of the replayable record;\n * - replay: the full history rebuilds the identical current state.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport { t } from \"../core/i18n/index.ts\";\n\nexport interface TransitionEvidenceRefV1 {\n\treadonly kind: string;\n\treadonly ref: string;\n\treadonly digest?: string;\n}\n\nexport interface TransitionRecordV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly revision: number;\n\treadonly at: number;\n}\n\nexport interface TransitionInputV1 {\n\treadonly domain: string;\n\treadonly entityId: string;\n\treadonly owner: string;\n\treadonly fromStatus: string | null;\n\treadonly toStatus: string;\n\treadonly operationId: string;\n\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\treadonly payload?: JsonValue;\n\treadonly at?: number;\n}\n\nexport interface TransitionResultV1 {\n\treadonly record: TransitionRecordV1;\n\treadonly deduped: boolean;\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0)\n\t\tthrow new Error(t(\"{label} must be a non-empty string\", { label }));\n}\n\nfunction validateEvidence(value: unknown, label: string): TransitionEvidenceRefV1[] {\n\tif (value === undefined) return [];\n\tif (!Array.isArray(value)) throw new Error(t(\"{label} must be an array\", { label }));\n\treturn value.map((item, index) => {\n\t\tconst depLabel = `${label}[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(t(\"{label} must be a plain object\", { label: depLabel }));\n\t\t}\n\t\tconst record = item as Record<string, unknown>;\n\t\tassertNonEmptyString(record.kind, `${depLabel}.kind`);\n\t\tassertNonEmptyString(record.ref, `${depLabel}.ref`);\n\t\tif (record.digest !== undefined) assertNonEmptyString(record.digest, `${depLabel}.digest`);\n\t\treturn Object.freeze({\n\t\t\tkind: record.kind,\n\t\t\tref: record.ref,\n\t\t\t...(record.digest === undefined ? {} : { digest: record.digest }),\n\t\t});\n\t});\n}\n\nfunction validatePayload(value: unknown, label: string): JsonValue | undefined {\n\tif (value === undefined) return undefined;\n\tconst seen = new Set<object>();\n\tconst check = (node: unknown): void => {\n\t\tif (node === null || typeof node === \"string\" || typeof node === \"boolean\") return;\n\t\tif (typeof node === \"number\") {\n\t\t\tif (!Number.isFinite(node))\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt(\"{label} must be JSON-safe: {node} is not a finite number\", { label, node: String(node) }),\n\t\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (typeof node === \"object\") {\n\t\t\tif (seen.has(node)) throw new Error(t(\"{label} must be JSON-safe: circular reference\", { label }));\n\t\t\tseen.add(node);\n\t\t\tif (Array.isArray(node)) {\n\t\t\t\tfor (const item of node) check(item);\n\t\t\t} else {\n\t\t\t\tconst proto = Object.getPrototypeOf(node) as unknown;\n\t\t\t\tif (proto !== Object.prototype && proto !== null)\n\t\t\t\t\tthrow new Error(t(\"{label} must be a plain object\", { label }));\n\t\t\t\tfor (const entry of Object.entries(node)) {\n\t\t\t\t\tif (entry[1] === undefined)\n\t\t\t\t\t\tthrow new Error(t(\"{label} must be JSON-safe: {key} is undefined\", { label, key: entry[0] }));\n\t\t\t\t\tcheck(entry[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tseen.delete(node);\n\t\t\treturn;\n\t\t}\n\t\tthrow new Error(t(\"{label} must be JSON-safe: unsupported value of type {type}\", { label, type: typeof node }));\n\t};\n\tcheck(value);\n\treturn JSON.parse(JSON.stringify(value)) as JsonValue;\n}\n\nexport interface TransitionStoreV1 {\n\ttransition(input: TransitionInputV1): TransitionResultV1;\n\tcurrentStatus(domain: string, entityId: string): { readonly status: string; readonly revision: number } | undefined;\n\thistory(entityId: string): readonly TransitionRecordV1[];\n\t/** Replays a history into a fresh store; the rebuilt state must be identical. */\n\treplay(history: readonly TransitionRecordV1[]): void;\n\tentities(): readonly string[];\n}\n\nexport function createTransitionStore(options: { readonly now?: () => number } = {}): TransitionStoreV1 {\n\tconst now = options.now ?? (() => Date.now());\n\tconst recordsByEntity = new Map<string, TransitionRecordV1[]>();\n\tconst idempotency = new Map<string, TransitionRecordV1>();\n\tconst currentStatus = new Map<string, { status: string; revision: number }>();\n\tconst revisions = new Map<string, number>();\n\n\tconst entityKey = (domain: string, entityId: string): string => `${domain}\\u0000${entityId}`;\n\n\treturn {\n\t\ttransition(input) {\n\t\t\tassertNonEmptyString(input.domain, \"Transition domain\");\n\t\t\tassertNonEmptyString(input.entityId, \"Transition entityId\");\n\t\t\tassertNonEmptyString(input.owner, \"Transition owner\");\n\t\t\tassertNonEmptyString(input.operationId, \"Transition operationId\");\n\t\t\tassertNonEmptyString(input.toStatus, \"Transition toStatus\");\n\t\t\tconst evidence = validateEvidence(input.evidence, \"Transition evidence\");\n\t\t\tconst payload = validatePayload(input.payload, \"Transition payload\");\n\t\t\tconst key = `${entityKey(input.domain, input.entityId)}\\u0000${input.operationId}\\u0000${input.toStatus}`;\n\n\t\t\tconst existing = idempotency.get(key);\n\t\t\tif (existing) return { record: existing, deduped: true };\n\n\t\t\tconst entityKeyId = entityKey(input.domain, input.entityId);\n\t\t\tconst current = currentStatus.get(entityKeyId);\n\t\t\tconst fromStatus = input.fromStatus;\n\t\t\tif ((current?.status ?? null) !== fromStatus) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt(\"Transition conflict: expected fromStatus {from}, got {to}\", {\n\t\t\t\t\t\tfrom: JSON.stringify(current?.status ?? null),\n\t\t\t\t\t\tto: JSON.stringify(fromStatus),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst revision = (revisions.get(entityKeyId) ?? 0) + 1;\n\t\t\trevisions.set(entityKeyId, revision);\n\t\t\tconst record: TransitionRecordV1 = Object.freeze({\n\t\t\t\tdomain: input.domain,\n\t\t\t\tentityId: input.entityId,\n\t\t\t\towner: input.owner,\n\t\t\t\tfromStatus,\n\t\t\t\ttoStatus: input.toStatus,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tevidence: Object.freeze(evidence),\n\t\t\t\t...(payload === undefined ? {} : { payload }),\n\t\t\t\trevision,\n\t\t\t\tat: input.at ?? now(),\n\t\t\t});\n\t\t\tconst log = recordsByEntity.get(entityKeyId) ?? [];\n\t\t\tlog.push(record);\n\t\t\trecordsByEntity.set(entityKeyId, log);\n\t\t\tcurrentStatus.set(entityKeyId, { status: input.toStatus, revision });\n\t\t\tidempotency.set(key, record);\n\t\t\treturn { record, deduped: false };\n\t\t},\n\t\tcurrentStatus(domain: string, entityId: string) {\n\t\t\treturn currentStatus.get(entityKey(domain, entityId));\n\t\t},\n\t\thistory(entityId: string) {\n\t\t\treturn Object.freeze(\n\t\t\t\t[...recordsByEntity.entries()]\n\t\t\t\t\t.filter(([entityKeyId]) => entityKeyId.endsWith(`\\u0000${entityId}`))\n\t\t\t\t\t.flatMap(([, log]) => log),\n\t\t\t);\n\t\t},\n\t\treplay(history) {\n\t\t\tfor (const record of history) {\n\t\t\t\tthis.transition({\n\t\t\t\t\tdomain: record.domain,\n\t\t\t\t\tentityId: record.entityId,\n\t\t\t\t\towner: record.owner,\n\t\t\t\t\tfromStatus: record.fromStatus,\n\t\t\t\t\ttoStatus: record.toStatus,\n\t\t\t\t\toperationId: record.operationId,\n\t\t\t\t\tevidence: record.evidence,\n\t\t\t\t\tpayload: record.payload,\n\t\t\t\t\tat: record.at,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tentities() {\n\t\t\treturn Object.freeze([...new Set([...currentStatus.keys()].map((key) => key.split(\"\\u0000\")[1]!))]);\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"todo-plugin.d.ts","sourceRoot":"","sources":["../../src/profile/todo-plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEnF,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;AAE9E,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,UAAU,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IACzG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC1F,8FAA8F;IAC9F,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC5G,QAAQ,CACP,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,EAC7C,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,MAAM,CAAC;IACV,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/D,gDAAgD;IAChD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC3F,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAyBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAA;CAAE,GAAG,YAAY,CAuInG","sourcesContent":["/**\n * Todo plugin (2.3d) — Todo content lifecycle with cancellation and restart\n * over the 2.3a transition store.\n *\n * Status graph: null → open → in_progress → completed; open/in_progress →\n * cancelled; cancelled → open (restart). Content updates rewrite the payload\n * in place while the todo is open/in_progress, and every terminal transition\n * stays replayable from the ledger. The plugin holds NO shadow state —\n * content and status are always derived from the transition history.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport type { TransitionEvidenceRefV1, TransitionStoreV1 } from \"./state-store.ts\";\n\nexport type TodoStatusV1 = \"open\" | \"in_progress\" | \"completed\" | \"cancelled\";\n\nexport interface TodoV1 {\n\treadonly todoId: string;\n\treadonly owner: string;\n\treadonly content: string;\n\treadonly status: TodoStatusV1;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly revision: number;\n}\n\nexport interface TodoPluginV1 {\n\tcreateTodo(input: { readonly todoId: string; readonly owner: string; readonly content: string }): TodoV1;\n\tstart(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\t/** Rewrites the content while open/in_progress; the ledger keeps every version replayable. */\n\tupdate(todoId: string, owner: string, content: string, options?: { readonly operationId?: string }): TodoV1;\n\tcomplete(\n\t\ttodoId: string,\n\t\towner: string,\n\t\tevidence?: readonly TransitionEvidenceRefV1[],\n\t\toptions?: { readonly operationId?: string },\n\t): TodoV1;\n\tcancel(todoId: string, owner: string, reason?: string): TodoV1;\n\t/** Restarts a cancelled todo back into open. */\n\treopen(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\tget(todoId: string, owner: string): TodoV1 | undefined;\n}\n\ninterface TodoPayloadV1 {\n\treadonly content: string;\n\treadonly cancelReason?: string;\n}\n\n/** FNV-1a 32-bit — a short deterministic operationId suffix for content updates. */\nfunction contentHash(content: string): string {\n\tlet hash = 0x811c9dc5;\n\tfor (let index = 0; index < content.length; index += 1) {\n\t\thash ^= content.charCodeAt(index);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn (hash >>> 0).toString(36);\n}\n\nfunction todoPayloadOf(record: { readonly payload?: unknown }): Partial<TodoPayloadV1> | undefined {\n\tconst payload = record.payload;\n\tif (payload !== null && typeof payload === \"object\" && !Array.isArray(payload)) {\n\t\treturn payload as Partial<TodoPayloadV1>;\n\t}\n\treturn undefined;\n}\n\nexport function createTodoPlugin(options: { readonly transitions: TransitionStoreV1 }): TodoPluginV1 {\n\tconst transitions = options.transitions;\n\n\tconst todoHistory = (todoId: string, owner: string) =>\n\t\ttransitions.history(todoId).filter((record) => record.domain === \"todo\" && record.owner === owner);\n\n\tconst current = (todoId: string, owner: string): { status: TodoStatusV1; revision: number } | undefined => {\n\t\tconst state = transitions.currentStatus(\"todo\", todoId);\n\t\tif (state === undefined || todoHistory(todoId, owner).length === 0) return undefined;\n\t\treturn { status: state.status as TodoStatusV1, revision: state.revision };\n\t};\n\n\tconst todoGet = (todoId: string, owner: string): TodoV1 | undefined => {\n\t\tconst state = current(todoId, owner);\n\t\tif (!state) return undefined;\n\t\tconst history = todoHistory(todoId, owner);\n\t\tconst content = [...history]\n\t\t\t.reverse()\n\t\t\t.map((record) => todoPayloadOf(record)?.content)\n\t\t\t.find((value): value is string => typeof value === \"string\");\n\t\tconst lastEvidence = [...history].reverse().find((record) => record.evidence.length > 0)?.evidence ?? [];\n\t\treturn {\n\t\t\ttodoId,\n\t\t\towner,\n\t\t\t// v8 ignore next -- createTodo 恒写入 content payload,标题扫描必命中\n\t\t\tcontent: content ?? \"\",\n\t\t\tstatus: state.status,\n\t\t\tevidence: lastEvidence,\n\t\t\trevision: state.revision,\n\t\t};\n\t};\n\n\t/** A retried transition with an already-applied operationId returns the existing state instead of conflicting. */\n\tconst replayedTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\ttoStatus: TodoStatusV1,\n\t\toperationId?: string,\n\t): TodoV1 | undefined => {\n\t\tif (!operationId) return undefined;\n\t\tconst applied = todoHistory(todoId, owner).some(\n\t\t\t(record) => record.toStatus === toStatus && record.operationId === operationId,\n\t\t);\n\t\treturn applied ? todoGet(todoId, owner) : undefined;\n\t};\n\n\tconst transitionTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\tfromStatus: TodoStatusV1 | null,\n\t\ttoStatus: TodoStatusV1,\n\t\ttodoOptions: {\n\t\t\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\t\t\treadonly payload?: TodoPayloadV1;\n\t\t\treadonly operationId?: string;\n\t\t},\n\t): TodoV1 => {\n\t\ttransitions.transition({\n\t\t\tdomain: \"todo\",\n\t\t\tentityId: todoId,\n\t\t\towner,\n\t\t\tfromStatus,\n\t\t\ttoStatus,\n\t\t\toperationId: todoOptions.operationId ?? `${toStatus}:${todoId}`,\n\t\t\tevidence: todoOptions.evidence,\n\t\t\tpayload: todoOptions.payload as JsonValue | undefined,\n\t\t});\n\t\treturn todoGet(todoId, owner)!;\n\t};\n\n\tconst requireStatus = (todoId: string, owner: string, allowed: readonly TodoStatusV1[]): TodoV1 => {\n\t\tconst todo = todoGet(todoId, owner);\n\t\tif (!todo || !allowed.includes(todo.status)) {\n\t\t\tthrow new Error(`Todo ${todoId} must be ${allowed.join(\"/\")} (current: ${todo?.status ?? \"missing\"})`);\n\t\t}\n\t\treturn todo;\n\t};\n\n\treturn {\n\t\tcreateTodo({ todoId, owner, content }) {\n\t\t\tif (content.trim().length === 0) throw new Error(\"Todo content must be a non-empty string\");\n\t\t\treturn transitionTodo(todoId, owner, null, \"open\", {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: `create:${todoId}`,\n\t\t\t});\n\t\t},\n\t\tstart(todoId, owner, startOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"in_progress\", startOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"open\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"open\", \"in_progress\", { operationId: startOptions?.operationId });\n\t\t},\n\t\tupdate(todoId, owner, content, updateOptions) {\n\t\t\tif (content.trim().length === 0) throw new Error(\"Todo content must be a non-empty string\");\n\t\t\tconst replayed = replayedTodo(\n\t\t\t\ttodoId,\n\t\t\t\towner,\n\t\t\t\ttodoGet(todoId, owner)?.status ?? \"open\",\n\t\t\t\tupdateOptions?.operationId,\n\t\t\t);\n\t\t\tif (replayed) return replayed;\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, todo.status, todo.status, {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: updateOptions?.operationId ?? `update:${todoId}:${contentHash(content)}`,\n\t\t\t});\n\t\t},\n\t\tcomplete(todoId, owner, evidence, completeOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"completed\", completeOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"in_progress\", \"completed\", {\n\t\t\t\tevidence: evidence ?? [],\n\t\t\t\toperationId: completeOptions?.operationId,\n\t\t\t});\n\t\t},\n\t\tcancel(todoId, owner, reason) {\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\tif (reason !== undefined && reason.trim().length === 0) {\n\t\t\t\tthrow new Error(\"Todo cancel reason must be a non-empty string when provided\");\n\t\t\t}\n\t\t\treturn transitionTodo(todoId, owner, todo.status, \"cancelled\", {\n\t\t\t\t...(reason === undefined ? {} : { payload: { content: todo.content, cancelReason: reason } }),\n\t\t\t});\n\t\t},\n\t\treopen(todoId, owner, reopenOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"open\", reopenOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"cancelled\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"cancelled\", \"open\", { operationId: reopenOptions?.operationId });\n\t\t},\n\t\tget(todoId, owner) {\n\t\t\treturn todoGet(todoId, owner);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"todo-plugin.d.ts","sourceRoot":"","sources":["../../src/profile/todo-plugin.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEnF,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;AAE9E,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,UAAU,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IACzG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC1F,8FAA8F;IAC9F,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC5G,QAAQ,CACP,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,EAC7C,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,MAAM,CAAC;IACV,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/D,gDAAgD;IAChD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAC3F,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAyBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAA;CAAE,GAAG,YAAY,CA6InG","sourcesContent":["/**\n * Todo plugin (2.3d) — Todo content lifecycle with cancellation and restart\n * over the 2.3a transition store.\n *\n * Status graph: null → open → in_progress → completed; open/in_progress →\n * cancelled; cancelled → open (restart). Content updates rewrite the payload\n * in place while the todo is open/in_progress, and every terminal transition\n * stays replayable from the ledger. The plugin holds NO shadow state —\n * content and status are always derived from the transition history.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { TransitionEvidenceRefV1, TransitionStoreV1 } from \"./state-store.ts\";\n\nexport type TodoStatusV1 = \"open\" | \"in_progress\" | \"completed\" | \"cancelled\";\n\nexport interface TodoV1 {\n\treadonly todoId: string;\n\treadonly owner: string;\n\treadonly content: string;\n\treadonly status: TodoStatusV1;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly revision: number;\n}\n\nexport interface TodoPluginV1 {\n\tcreateTodo(input: { readonly todoId: string; readonly owner: string; readonly content: string }): TodoV1;\n\tstart(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\t/** Rewrites the content while open/in_progress; the ledger keeps every version replayable. */\n\tupdate(todoId: string, owner: string, content: string, options?: { readonly operationId?: string }): TodoV1;\n\tcomplete(\n\t\ttodoId: string,\n\t\towner: string,\n\t\tevidence?: readonly TransitionEvidenceRefV1[],\n\t\toptions?: { readonly operationId?: string },\n\t): TodoV1;\n\tcancel(todoId: string, owner: string, reason?: string): TodoV1;\n\t/** Restarts a cancelled todo back into open. */\n\treopen(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\tget(todoId: string, owner: string): TodoV1 | undefined;\n}\n\ninterface TodoPayloadV1 {\n\treadonly content: string;\n\treadonly cancelReason?: string;\n}\n\n/** FNV-1a 32-bit — a short deterministic operationId suffix for content updates. */\nfunction contentHash(content: string): string {\n\tlet hash = 0x811c9dc5;\n\tfor (let index = 0; index < content.length; index += 1) {\n\t\thash ^= content.charCodeAt(index);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn (hash >>> 0).toString(36);\n}\n\nfunction todoPayloadOf(record: { readonly payload?: unknown }): Partial<TodoPayloadV1> | undefined {\n\tconst payload = record.payload;\n\tif (payload !== null && typeof payload === \"object\" && !Array.isArray(payload)) {\n\t\treturn payload as Partial<TodoPayloadV1>;\n\t}\n\treturn undefined;\n}\n\nexport function createTodoPlugin(options: { readonly transitions: TransitionStoreV1 }): TodoPluginV1 {\n\tconst transitions = options.transitions;\n\n\tconst todoHistory = (todoId: string, owner: string) =>\n\t\ttransitions.history(todoId).filter((record) => record.domain === \"todo\" && record.owner === owner);\n\n\tconst current = (todoId: string, owner: string): { status: TodoStatusV1; revision: number } | undefined => {\n\t\tconst state = transitions.currentStatus(\"todo\", todoId);\n\t\tif (state === undefined || todoHistory(todoId, owner).length === 0) return undefined;\n\t\treturn { status: state.status as TodoStatusV1, revision: state.revision };\n\t};\n\n\tconst todoGet = (todoId: string, owner: string): TodoV1 | undefined => {\n\t\tconst state = current(todoId, owner);\n\t\tif (!state) return undefined;\n\t\tconst history = todoHistory(todoId, owner);\n\t\tconst content = [...history]\n\t\t\t.reverse()\n\t\t\t.map((record) => todoPayloadOf(record)?.content)\n\t\t\t.find((value): value is string => typeof value === \"string\");\n\t\tconst lastEvidence = [...history].reverse().find((record) => record.evidence.length > 0)?.evidence ?? [];\n\t\treturn {\n\t\t\ttodoId,\n\t\t\towner,\n\t\t\t// v8 ignore next -- createTodo 恒写入 content payload,标题扫描必命中\n\t\t\tcontent: content ?? \"\",\n\t\t\tstatus: state.status,\n\t\t\tevidence: lastEvidence,\n\t\t\trevision: state.revision,\n\t\t};\n\t};\n\n\t/** A retried transition with an already-applied operationId returns the existing state instead of conflicting. */\n\tconst replayedTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\ttoStatus: TodoStatusV1,\n\t\toperationId?: string,\n\t): TodoV1 | undefined => {\n\t\tif (!operationId) return undefined;\n\t\tconst applied = todoHistory(todoId, owner).some(\n\t\t\t(record) => record.toStatus === toStatus && record.operationId === operationId,\n\t\t);\n\t\treturn applied ? todoGet(todoId, owner) : undefined;\n\t};\n\n\tconst transitionTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\tfromStatus: TodoStatusV1 | null,\n\t\ttoStatus: TodoStatusV1,\n\t\ttodoOptions: {\n\t\t\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\t\t\treadonly payload?: TodoPayloadV1;\n\t\t\treadonly operationId?: string;\n\t\t},\n\t): TodoV1 => {\n\t\ttransitions.transition({\n\t\t\tdomain: \"todo\",\n\t\t\tentityId: todoId,\n\t\t\towner,\n\t\t\tfromStatus,\n\t\t\ttoStatus,\n\t\t\toperationId: todoOptions.operationId ?? `${toStatus}:${todoId}`,\n\t\t\tevidence: todoOptions.evidence,\n\t\t\tpayload: todoOptions.payload as JsonValue | undefined,\n\t\t});\n\t\treturn todoGet(todoId, owner)!;\n\t};\n\n\tconst requireStatus = (todoId: string, owner: string, allowed: readonly TodoStatusV1[]): TodoV1 => {\n\t\tconst todo = todoGet(todoId, owner);\n\t\tif (!todo || !allowed.includes(todo.status)) {\n\t\t\tthrow new Error(\n\t\t\t\tt(\"Todo {todoId} must be {allowed} (current: {status})\", {\n\t\t\t\t\ttodoId,\n\t\t\t\t\tallowed: allowed.join(\"/\"),\n\t\t\t\t\tstatus: todo?.status ?? \"missing\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn todo;\n\t};\n\n\treturn {\n\t\tcreateTodo({ todoId, owner, content }) {\n\t\t\tif (content.trim().length === 0) throw new Error(t(\"Todo content must be a non-empty string\"));\n\t\t\treturn transitionTodo(todoId, owner, null, \"open\", {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: `create:${todoId}`,\n\t\t\t});\n\t\t},\n\t\tstart(todoId, owner, startOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"in_progress\", startOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"open\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"open\", \"in_progress\", { operationId: startOptions?.operationId });\n\t\t},\n\t\tupdate(todoId, owner, content, updateOptions) {\n\t\t\tif (content.trim().length === 0) throw new Error(t(\"Todo content must be a non-empty string\"));\n\t\t\tconst replayed = replayedTodo(\n\t\t\t\ttodoId,\n\t\t\t\towner,\n\t\t\t\ttodoGet(todoId, owner)?.status ?? \"open\",\n\t\t\t\tupdateOptions?.operationId,\n\t\t\t);\n\t\t\tif (replayed) return replayed;\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, todo.status, todo.status, {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: updateOptions?.operationId ?? `update:${todoId}:${contentHash(content)}`,\n\t\t\t});\n\t\t},\n\t\tcomplete(todoId, owner, evidence, completeOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"completed\", completeOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"in_progress\", \"completed\", {\n\t\t\t\tevidence: evidence ?? [],\n\t\t\t\toperationId: completeOptions?.operationId,\n\t\t\t});\n\t\t},\n\t\tcancel(todoId, owner, reason) {\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\tif (reason !== undefined && reason.trim().length === 0) {\n\t\t\t\tthrow new Error(t(\"Todo cancel reason must be a non-empty string when provided\"));\n\t\t\t}\n\t\t\treturn transitionTodo(todoId, owner, todo.status, \"cancelled\", {\n\t\t\t\t...(reason === undefined ? {} : { payload: { content: todo.content, cancelReason: reason } }),\n\t\t\t});\n\t\t},\n\t\treopen(todoId, owner, reopenOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"open\", reopenOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"cancelled\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"cancelled\", \"open\", { operationId: reopenOptions?.operationId });\n\t\t},\n\t\tget(todoId, owner) {\n\t\t\treturn todoGet(todoId, owner);\n\t\t},\n\t};\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { t } from "../core/i18n/index.js";
1
2
  /** FNV-1a 32-bit — a short deterministic operationId suffix for content updates. */
2
3
  function contentHash(content) {
3
4
  let hash = 0x811c9dc5;
@@ -66,14 +67,18 @@ export function createTodoPlugin(options) {
66
67
  const requireStatus = (todoId, owner, allowed) => {
67
68
  const todo = todoGet(todoId, owner);
68
69
  if (!todo || !allowed.includes(todo.status)) {
69
- throw new Error(`Todo ${todoId} must be ${allowed.join("/")} (current: ${todo?.status ?? "missing"})`);
70
+ throw new Error(t("Todo {todoId} must be {allowed} (current: {status})", {
71
+ todoId,
72
+ allowed: allowed.join("/"),
73
+ status: todo?.status ?? "missing",
74
+ }));
70
75
  }
71
76
  return todo;
72
77
  };
73
78
  return {
74
79
  createTodo({ todoId, owner, content }) {
75
80
  if (content.trim().length === 0)
76
- throw new Error("Todo content must be a non-empty string");
81
+ throw new Error(t("Todo content must be a non-empty string"));
77
82
  return transitionTodo(todoId, owner, null, "open", {
78
83
  payload: { content },
79
84
  operationId: `create:${todoId}`,
@@ -88,7 +93,7 @@ export function createTodoPlugin(options) {
88
93
  },
89
94
  update(todoId, owner, content, updateOptions) {
90
95
  if (content.trim().length === 0)
91
- throw new Error("Todo content must be a non-empty string");
96
+ throw new Error(t("Todo content must be a non-empty string"));
92
97
  const replayed = replayedTodo(todoId, owner, todoGet(todoId, owner)?.status ?? "open", updateOptions?.operationId);
93
98
  if (replayed)
94
99
  return replayed;
@@ -111,7 +116,7 @@ export function createTodoPlugin(options) {
111
116
  cancel(todoId, owner, reason) {
112
117
  const todo = requireStatus(todoId, owner, ["open", "in_progress"]);
113
118
  if (reason !== undefined && reason.trim().length === 0) {
114
- throw new Error("Todo cancel reason must be a non-empty string when provided");
119
+ throw new Error(t("Todo cancel reason must be a non-empty string when provided"));
115
120
  }
116
121
  return transitionTodo(todoId, owner, todo.status, "cancelled", {
117
122
  ...(reason === undefined ? {} : { payload: { content: todo.content, cancelReason: reason } }),
@@ -1 +1 @@
1
- {"version":3,"file":"todo-plugin.js","sourceRoot":"","sources":["../../src/profile/todo-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Todo plugin (2.3d) — Todo content lifecycle with cancellation and restart\n * over the 2.3a transition store.\n *\n * Status graph: null → open → in_progress → completed; open/in_progress →\n * cancelled; cancelled → open (restart). Content updates rewrite the payload\n * in place while the todo is open/in_progress, and every terminal transition\n * stays replayable from the ledger. The plugin holds NO shadow state —\n * content and status are always derived from the transition history.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport type { TransitionEvidenceRefV1, TransitionStoreV1 } from \"./state-store.ts\";\n\nexport type TodoStatusV1 = \"open\" | \"in_progress\" | \"completed\" | \"cancelled\";\n\nexport interface TodoV1 {\n\treadonly todoId: string;\n\treadonly owner: string;\n\treadonly content: string;\n\treadonly status: TodoStatusV1;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly revision: number;\n}\n\nexport interface TodoPluginV1 {\n\tcreateTodo(input: { readonly todoId: string; readonly owner: string; readonly content: string }): TodoV1;\n\tstart(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\t/** Rewrites the content while open/in_progress; the ledger keeps every version replayable. */\n\tupdate(todoId: string, owner: string, content: string, options?: { readonly operationId?: string }): TodoV1;\n\tcomplete(\n\t\ttodoId: string,\n\t\towner: string,\n\t\tevidence?: readonly TransitionEvidenceRefV1[],\n\t\toptions?: { readonly operationId?: string },\n\t): TodoV1;\n\tcancel(todoId: string, owner: string, reason?: string): TodoV1;\n\t/** Restarts a cancelled todo back into open. */\n\treopen(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\tget(todoId: string, owner: string): TodoV1 | undefined;\n}\n\ninterface TodoPayloadV1 {\n\treadonly content: string;\n\treadonly cancelReason?: string;\n}\n\n/** FNV-1a 32-bit — a short deterministic operationId suffix for content updates. */\nfunction contentHash(content: string): string {\n\tlet hash = 0x811c9dc5;\n\tfor (let index = 0; index < content.length; index += 1) {\n\t\thash ^= content.charCodeAt(index);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn (hash >>> 0).toString(36);\n}\n\nfunction todoPayloadOf(record: { readonly payload?: unknown }): Partial<TodoPayloadV1> | undefined {\n\tconst payload = record.payload;\n\tif (payload !== null && typeof payload === \"object\" && !Array.isArray(payload)) {\n\t\treturn payload as Partial<TodoPayloadV1>;\n\t}\n\treturn undefined;\n}\n\nexport function createTodoPlugin(options: { readonly transitions: TransitionStoreV1 }): TodoPluginV1 {\n\tconst transitions = options.transitions;\n\n\tconst todoHistory = (todoId: string, owner: string) =>\n\t\ttransitions.history(todoId).filter((record) => record.domain === \"todo\" && record.owner === owner);\n\n\tconst current = (todoId: string, owner: string): { status: TodoStatusV1; revision: number } | undefined => {\n\t\tconst state = transitions.currentStatus(\"todo\", todoId);\n\t\tif (state === undefined || todoHistory(todoId, owner).length === 0) return undefined;\n\t\treturn { status: state.status as TodoStatusV1, revision: state.revision };\n\t};\n\n\tconst todoGet = (todoId: string, owner: string): TodoV1 | undefined => {\n\t\tconst state = current(todoId, owner);\n\t\tif (!state) return undefined;\n\t\tconst history = todoHistory(todoId, owner);\n\t\tconst content = [...history]\n\t\t\t.reverse()\n\t\t\t.map((record) => todoPayloadOf(record)?.content)\n\t\t\t.find((value): value is string => typeof value === \"string\");\n\t\tconst lastEvidence = [...history].reverse().find((record) => record.evidence.length > 0)?.evidence ?? [];\n\t\treturn {\n\t\t\ttodoId,\n\t\t\towner,\n\t\t\t// v8 ignore next -- createTodo 恒写入 content payload,标题扫描必命中\n\t\t\tcontent: content ?? \"\",\n\t\t\tstatus: state.status,\n\t\t\tevidence: lastEvidence,\n\t\t\trevision: state.revision,\n\t\t};\n\t};\n\n\t/** A retried transition with an already-applied operationId returns the existing state instead of conflicting. */\n\tconst replayedTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\ttoStatus: TodoStatusV1,\n\t\toperationId?: string,\n\t): TodoV1 | undefined => {\n\t\tif (!operationId) return undefined;\n\t\tconst applied = todoHistory(todoId, owner).some(\n\t\t\t(record) => record.toStatus === toStatus && record.operationId === operationId,\n\t\t);\n\t\treturn applied ? todoGet(todoId, owner) : undefined;\n\t};\n\n\tconst transitionTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\tfromStatus: TodoStatusV1 | null,\n\t\ttoStatus: TodoStatusV1,\n\t\ttodoOptions: {\n\t\t\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\t\t\treadonly payload?: TodoPayloadV1;\n\t\t\treadonly operationId?: string;\n\t\t},\n\t): TodoV1 => {\n\t\ttransitions.transition({\n\t\t\tdomain: \"todo\",\n\t\t\tentityId: todoId,\n\t\t\towner,\n\t\t\tfromStatus,\n\t\t\ttoStatus,\n\t\t\toperationId: todoOptions.operationId ?? `${toStatus}:${todoId}`,\n\t\t\tevidence: todoOptions.evidence,\n\t\t\tpayload: todoOptions.payload as JsonValue | undefined,\n\t\t});\n\t\treturn todoGet(todoId, owner)!;\n\t};\n\n\tconst requireStatus = (todoId: string, owner: string, allowed: readonly TodoStatusV1[]): TodoV1 => {\n\t\tconst todo = todoGet(todoId, owner);\n\t\tif (!todo || !allowed.includes(todo.status)) {\n\t\t\tthrow new Error(`Todo ${todoId} must be ${allowed.join(\"/\")} (current: ${todo?.status ?? \"missing\"})`);\n\t\t}\n\t\treturn todo;\n\t};\n\n\treturn {\n\t\tcreateTodo({ todoId, owner, content }) {\n\t\t\tif (content.trim().length === 0) throw new Error(\"Todo content must be a non-empty string\");\n\t\t\treturn transitionTodo(todoId, owner, null, \"open\", {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: `create:${todoId}`,\n\t\t\t});\n\t\t},\n\t\tstart(todoId, owner, startOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"in_progress\", startOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"open\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"open\", \"in_progress\", { operationId: startOptions?.operationId });\n\t\t},\n\t\tupdate(todoId, owner, content, updateOptions) {\n\t\t\tif (content.trim().length === 0) throw new Error(\"Todo content must be a non-empty string\");\n\t\t\tconst replayed = replayedTodo(\n\t\t\t\ttodoId,\n\t\t\t\towner,\n\t\t\t\ttodoGet(todoId, owner)?.status ?? \"open\",\n\t\t\t\tupdateOptions?.operationId,\n\t\t\t);\n\t\t\tif (replayed) return replayed;\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, todo.status, todo.status, {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: updateOptions?.operationId ?? `update:${todoId}:${contentHash(content)}`,\n\t\t\t});\n\t\t},\n\t\tcomplete(todoId, owner, evidence, completeOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"completed\", completeOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"in_progress\", \"completed\", {\n\t\t\t\tevidence: evidence ?? [],\n\t\t\t\toperationId: completeOptions?.operationId,\n\t\t\t});\n\t\t},\n\t\tcancel(todoId, owner, reason) {\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\tif (reason !== undefined && reason.trim().length === 0) {\n\t\t\t\tthrow new Error(\"Todo cancel reason must be a non-empty string when provided\");\n\t\t\t}\n\t\t\treturn transitionTodo(todoId, owner, todo.status, \"cancelled\", {\n\t\t\t\t...(reason === undefined ? {} : { payload: { content: todo.content, cancelReason: reason } }),\n\t\t\t});\n\t\t},\n\t\treopen(todoId, owner, reopenOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"open\", reopenOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"cancelled\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"cancelled\", \"open\", { operationId: reopenOptions?.operationId });\n\t\t},\n\t\tget(todoId, owner) {\n\t\t\treturn todoGet(todoId, owner);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"todo-plugin.js","sourceRoot":"","sources":["../../src/profile/todo-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Todo plugin (2.3d) — Todo content lifecycle with cancellation and restart\n * over the 2.3a transition store.\n *\n * Status graph: null → open → in_progress → completed; open/in_progress →\n * cancelled; cancelled → open (restart). Content updates rewrite the payload\n * in place while the todo is open/in_progress, and every terminal transition\n * stays replayable from the ledger. The plugin holds NO shadow state —\n * content and status are always derived from the transition history.\n */\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { TransitionEvidenceRefV1, TransitionStoreV1 } from \"./state-store.ts\";\n\nexport type TodoStatusV1 = \"open\" | \"in_progress\" | \"completed\" | \"cancelled\";\n\nexport interface TodoV1 {\n\treadonly todoId: string;\n\treadonly owner: string;\n\treadonly content: string;\n\treadonly status: TodoStatusV1;\n\treadonly evidence: readonly TransitionEvidenceRefV1[];\n\treadonly revision: number;\n}\n\nexport interface TodoPluginV1 {\n\tcreateTodo(input: { readonly todoId: string; readonly owner: string; readonly content: string }): TodoV1;\n\tstart(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\t/** Rewrites the content while open/in_progress; the ledger keeps every version replayable. */\n\tupdate(todoId: string, owner: string, content: string, options?: { readonly operationId?: string }): TodoV1;\n\tcomplete(\n\t\ttodoId: string,\n\t\towner: string,\n\t\tevidence?: readonly TransitionEvidenceRefV1[],\n\t\toptions?: { readonly operationId?: string },\n\t): TodoV1;\n\tcancel(todoId: string, owner: string, reason?: string): TodoV1;\n\t/** Restarts a cancelled todo back into open. */\n\treopen(todoId: string, owner: string, options?: { readonly operationId?: string }): TodoV1;\n\tget(todoId: string, owner: string): TodoV1 | undefined;\n}\n\ninterface TodoPayloadV1 {\n\treadonly content: string;\n\treadonly cancelReason?: string;\n}\n\n/** FNV-1a 32-bit — a short deterministic operationId suffix for content updates. */\nfunction contentHash(content: string): string {\n\tlet hash = 0x811c9dc5;\n\tfor (let index = 0; index < content.length; index += 1) {\n\t\thash ^= content.charCodeAt(index);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn (hash >>> 0).toString(36);\n}\n\nfunction todoPayloadOf(record: { readonly payload?: unknown }): Partial<TodoPayloadV1> | undefined {\n\tconst payload = record.payload;\n\tif (payload !== null && typeof payload === \"object\" && !Array.isArray(payload)) {\n\t\treturn payload as Partial<TodoPayloadV1>;\n\t}\n\treturn undefined;\n}\n\nexport function createTodoPlugin(options: { readonly transitions: TransitionStoreV1 }): TodoPluginV1 {\n\tconst transitions = options.transitions;\n\n\tconst todoHistory = (todoId: string, owner: string) =>\n\t\ttransitions.history(todoId).filter((record) => record.domain === \"todo\" && record.owner === owner);\n\n\tconst current = (todoId: string, owner: string): { status: TodoStatusV1; revision: number } | undefined => {\n\t\tconst state = transitions.currentStatus(\"todo\", todoId);\n\t\tif (state === undefined || todoHistory(todoId, owner).length === 0) return undefined;\n\t\treturn { status: state.status as TodoStatusV1, revision: state.revision };\n\t};\n\n\tconst todoGet = (todoId: string, owner: string): TodoV1 | undefined => {\n\t\tconst state = current(todoId, owner);\n\t\tif (!state) return undefined;\n\t\tconst history = todoHistory(todoId, owner);\n\t\tconst content = [...history]\n\t\t\t.reverse()\n\t\t\t.map((record) => todoPayloadOf(record)?.content)\n\t\t\t.find((value): value is string => typeof value === \"string\");\n\t\tconst lastEvidence = [...history].reverse().find((record) => record.evidence.length > 0)?.evidence ?? [];\n\t\treturn {\n\t\t\ttodoId,\n\t\t\towner,\n\t\t\t// v8 ignore next -- createTodo 恒写入 content payload,标题扫描必命中\n\t\t\tcontent: content ?? \"\",\n\t\t\tstatus: state.status,\n\t\t\tevidence: lastEvidence,\n\t\t\trevision: state.revision,\n\t\t};\n\t};\n\n\t/** A retried transition with an already-applied operationId returns the existing state instead of conflicting. */\n\tconst replayedTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\ttoStatus: TodoStatusV1,\n\t\toperationId?: string,\n\t): TodoV1 | undefined => {\n\t\tif (!operationId) return undefined;\n\t\tconst applied = todoHistory(todoId, owner).some(\n\t\t\t(record) => record.toStatus === toStatus && record.operationId === operationId,\n\t\t);\n\t\treturn applied ? todoGet(todoId, owner) : undefined;\n\t};\n\n\tconst transitionTodo = (\n\t\ttodoId: string,\n\t\towner: string,\n\t\tfromStatus: TodoStatusV1 | null,\n\t\ttoStatus: TodoStatusV1,\n\t\ttodoOptions: {\n\t\t\treadonly evidence?: readonly TransitionEvidenceRefV1[];\n\t\t\treadonly payload?: TodoPayloadV1;\n\t\t\treadonly operationId?: string;\n\t\t},\n\t): TodoV1 => {\n\t\ttransitions.transition({\n\t\t\tdomain: \"todo\",\n\t\t\tentityId: todoId,\n\t\t\towner,\n\t\t\tfromStatus,\n\t\t\ttoStatus,\n\t\t\toperationId: todoOptions.operationId ?? `${toStatus}:${todoId}`,\n\t\t\tevidence: todoOptions.evidence,\n\t\t\tpayload: todoOptions.payload as JsonValue | undefined,\n\t\t});\n\t\treturn todoGet(todoId, owner)!;\n\t};\n\n\tconst requireStatus = (todoId: string, owner: string, allowed: readonly TodoStatusV1[]): TodoV1 => {\n\t\tconst todo = todoGet(todoId, owner);\n\t\tif (!todo || !allowed.includes(todo.status)) {\n\t\t\tthrow new Error(\n\t\t\t\tt(\"Todo {todoId} must be {allowed} (current: {status})\", {\n\t\t\t\t\ttodoId,\n\t\t\t\t\tallowed: allowed.join(\"/\"),\n\t\t\t\t\tstatus: todo?.status ?? \"missing\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn todo;\n\t};\n\n\treturn {\n\t\tcreateTodo({ todoId, owner, content }) {\n\t\t\tif (content.trim().length === 0) throw new Error(t(\"Todo content must be a non-empty string\"));\n\t\t\treturn transitionTodo(todoId, owner, null, \"open\", {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: `create:${todoId}`,\n\t\t\t});\n\t\t},\n\t\tstart(todoId, owner, startOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"in_progress\", startOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"open\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"open\", \"in_progress\", { operationId: startOptions?.operationId });\n\t\t},\n\t\tupdate(todoId, owner, content, updateOptions) {\n\t\t\tif (content.trim().length === 0) throw new Error(t(\"Todo content must be a non-empty string\"));\n\t\t\tconst replayed = replayedTodo(\n\t\t\t\ttodoId,\n\t\t\t\towner,\n\t\t\t\ttodoGet(todoId, owner)?.status ?? \"open\",\n\t\t\t\tupdateOptions?.operationId,\n\t\t\t);\n\t\t\tif (replayed) return replayed;\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, todo.status, todo.status, {\n\t\t\t\tpayload: { content },\n\t\t\t\toperationId: updateOptions?.operationId ?? `update:${todoId}:${contentHash(content)}`,\n\t\t\t});\n\t\t},\n\t\tcomplete(todoId, owner, evidence, completeOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"completed\", completeOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"in_progress\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"in_progress\", \"completed\", {\n\t\t\t\tevidence: evidence ?? [],\n\t\t\t\toperationId: completeOptions?.operationId,\n\t\t\t});\n\t\t},\n\t\tcancel(todoId, owner, reason) {\n\t\t\tconst todo = requireStatus(todoId, owner, [\"open\", \"in_progress\"]);\n\t\t\tif (reason !== undefined && reason.trim().length === 0) {\n\t\t\t\tthrow new Error(t(\"Todo cancel reason must be a non-empty string when provided\"));\n\t\t\t}\n\t\t\treturn transitionTodo(todoId, owner, todo.status, \"cancelled\", {\n\t\t\t\t...(reason === undefined ? {} : { payload: { content: todo.content, cancelReason: reason } }),\n\t\t\t});\n\t\t},\n\t\treopen(todoId, owner, reopenOptions) {\n\t\t\tconst replayed = replayedTodo(todoId, owner, \"open\", reopenOptions?.operationId);\n\t\t\tif (replayed) return replayed;\n\t\t\trequireStatus(todoId, owner, [\"cancelled\"]);\n\t\t\treturn transitionTodo(todoId, owner, \"cancelled\", \"open\", { operationId: reopenOptions?.operationId });\n\t\t},\n\t\tget(todoId, owner) {\n\t\t\treturn todoGet(todoId, owner);\n\t\t},\n\t};\n}\n"]}
@@ -54,8 +54,13 @@ export declare const SUITE_SCHEMA_VERSION = 1;
54
54
  * 5 receive the upgrade-proposal diagnostic and adopt via `--suite-reset`.
55
55
  */
56
56
  export declare const FACTORY_CONTENTS_VERSION = 6;
57
- /** Factory default suite used when no suite is configured anywhere (设计 §9). */
58
- export declare const DEFAULT_SUITE_ID = "assistant";
57
+ /**
58
+ * Factory default suite used when no suite is configured anywhere (设计 §9).
59
+ * 2026-10-02 user ruling: the product is a coding agent, so the factory
60
+ * default flipped from "assistant" to "coding"; assistant stays as the
61
+ * explicit-switch fallback suite.
62
+ */
63
+ export declare const DEFAULT_SUITE_ID = "coding";
59
64
  /** Suite ids become directory names: lowercase letters, digits, hyphens (设计 §9). */
60
65
  export declare const SUITE_ID_MAX_LENGTH = 64;
61
66
  /** The single unrestricted tool surface shared by both builtin suites (设计 §5/§6). */
@@ -76,15 +81,17 @@ export declare const BUILTIN_SUITE_TOOLS: readonly string[];
76
81
  */
77
82
  export declare const BUILTIN_SUITE_CAPABILITIES: readonly string[];
78
83
  export type SuiteMemoryStrategy = "assistant" | "code";
79
- export type SuiteOrientation = "assistant" | "coding";
84
+ export type SuiteOrientation = "assistant" | "coding" | "custom";
80
85
  /**
81
86
  * Orientation persona texts injected into the system prompt (设计 §6.2, M2).
82
87
  * The strings are verbatim from the design spec: the assistant persona is the
83
88
  * companion style, the coding persona is the rigor-first style. Both are
84
89
  * session-nature declarations, so they ride every system prompt branch
85
- * (default and customPrompt).
90
+ * (default and customPrompt). The custom orientation is not in this table: its
91
+ * persona text comes from the suite workspace persona.md (设计 §6.3, resolved
92
+ * by suite-loader).
86
93
  */
87
- export declare const ORIENTATION_PROMPTS: Record<SuiteOrientation, string>;
94
+ export declare const ORIENTATION_PROMPTS: Record<"assistant" | "coding", string>;
88
95
  export interface SuiteAssociations {
89
96
  readonly skills: readonly string[];
90
97
  readonly mcp: readonly string[];
@@ -130,7 +137,7 @@ export interface SuiteDefinition {
130
137
  * 编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。
131
138
  */
132
139
  export declare const DEFAULT_ROLE_ASSOCIATIONS: readonly string[];
133
- /** The factory builtin pair: assistant (fallback default) and coding (尖刀). */
140
+ /** The factory builtin pair: coding (factory default 尖刀) and assistant (fallback). */
134
141
  export declare const BUILTIN_SUITES: readonly SuiteDefinition[];
135
142
  export declare function getBuiltinSuite(id: string): SuiteDefinition | undefined;
136
143
  export declare function isBuiltinSuiteId(id: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-suites.d.ts","sourceRoot":"","sources":["../../src/profiles/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 */\nexport const FACTORY_CONTENTS_VERSION = 6;\n\n/** Factory default suite used when no suite is configured anywhere (设计 §9). */\nexport const DEFAULT_SUITE_ID = \"assistant\";\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).\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];\n\nexport type SuiteMemoryStrategy = \"assistant\" | \"code\";\nexport type SuiteOrientation = \"assistant\" | \"coding\";\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).\n */\nexport const ORIENTATION_PROMPTS: Record<SuiteOrientation, 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}.json`,用户可改可删)。工厂不在运行期回退到任何\n * 编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\"explore\", \"reviewer\"];\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: assistant (fallback default) and coding (尖刀). */\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 = orientationValue === \"assistant\" || orientationValue === \"coding\" ? orientationValue : undefined;\n\tif (orientationValue !== undefined && orientation === undefined) {\n\t\terrors.push(`orientation must be \"assistant\" or \"coding\", 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/profiles/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 */\nexport const FACTORY_CONTENTS_VERSION = 6;\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).\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];\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}.json`,用户可改可删)。工厂不在运行期回退到任何\n * 编译内的角色定义;删掉文件只会让该关联成为 dangling 诊断。\n */\nexport const DEFAULT_ROLE_ASSOCIATIONS: readonly string[] = [\"explore\", \"reviewer\"];\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"]}