@ai-agent-forge/agent-forge 0.86.7 → 0.88.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 (717) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +10 -11
  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 +430 -413
  7. package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
  8. package/dist/bundle/chunks/chunk-HLJEVRWP.js +13 -0
  9. package/dist/bundle/chunks/chunk-YGHQME4V.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 +17 -4
  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 +5 -3
  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 +6 -10
  54. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  55. package/dist/core/agent-session-compaction.js +35 -133
  56. package/dist/core/agent-session-compaction.js.map +1 -1
  57. package/dist/core/agent-session-context.d.ts.map +1 -1
  58. package/dist/core/agent-session-context.js +18 -13
  59. package/dist/core/agent-session-context.js.map +1 -1
  60. package/dist/core/agent-session-internal.d.ts +0 -6
  61. package/dist/core/agent-session-internal.d.ts.map +1 -1
  62. package/dist/core/agent-session-internal.js.map +1 -1
  63. package/dist/core/agent-session-model.d.ts.map +1 -1
  64. package/dist/core/agent-session-model.js +2 -1
  65. package/dist/core/agent-session-model.js.map +1 -1
  66. package/dist/core/agent-session-retry.d.ts.map +1 -1
  67. package/dist/core/agent-session-retry.js +3 -3
  68. package/dist/core/agent-session-retry.js.map +1 -1
  69. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  70. package/dist/core/agent-session-runtime.js +7 -6
  71. package/dist/core/agent-session-runtime.js.map +1 -1
  72. package/dist/core/agent-session-services.d.ts +1 -1
  73. package/dist/core/agent-session-services.d.ts.map +1 -1
  74. package/dist/core/agent-session-services.js.map +1 -1
  75. package/dist/core/agent-session-tools.d.ts.map +1 -1
  76. package/dist/core/agent-session-tools.js +3 -2
  77. package/dist/core/agent-session-tools.js.map +1 -1
  78. package/dist/core/agent-session.d.ts +40 -22
  79. package/dist/core/agent-session.d.ts.map +1 -1
  80. package/dist/core/agent-session.js +147 -67
  81. package/dist/core/agent-session.js.map +1 -1
  82. package/dist/core/auth-guidance.d.ts.map +1 -1
  83. package/dist/core/auth-guidance.js +11 -5
  84. package/dist/core/auth-guidance.js.map +1 -1
  85. package/dist/core/auth-storage.d.ts.map +1 -1
  86. package/dist/core/auth-storage.js +9 -6
  87. package/dist/core/auth-storage.js.map +1 -1
  88. package/dist/core/compaction/compaction.d.ts.map +1 -1
  89. package/dist/core/compaction/compaction.js +2 -1
  90. package/dist/core/compaction/compaction.js.map +1 -1
  91. package/dist/core/embedded-sdk.d.ts.map +1 -1
  92. package/dist/core/embedded-sdk.js +10 -6
  93. package/dist/core/embedded-sdk.js.map +1 -1
  94. package/dist/core/export-html/index.d.ts.map +1 -1
  95. package/dist/core/export-html/index.js +9 -4
  96. package/dist/core/export-html/index.js.map +1 -1
  97. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  98. package/dist/core/extensions/agent-composition.js +26 -19
  99. package/dist/core/extensions/agent-composition.js.map +1 -1
  100. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  101. package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
  102. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  103. package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +1 -1
  104. package/dist/core/extensions/bootstrap-compaction-policy.js +0 -34
  105. package/dist/core/extensions/bootstrap-compaction-policy.js.map +1 -1
  106. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  107. package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
  108. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  109. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
  110. package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
  111. package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
  112. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
  113. package/dist/core/extensions/bootstrap-retry-policy.js +4 -3
  114. package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
  115. package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
  116. package/dist/core/extensions/bootstrap-skills.js +7 -6
  117. package/dist/core/extensions/bootstrap-skills.js.map +1 -1
  118. package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
  119. package/dist/core/extensions/bootstrap-tools.js +2 -1
  120. package/dist/core/extensions/bootstrap-tools.js.map +1 -1
  121. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  122. package/dist/core/extensions/capability-plugin.js +37 -13
  123. package/dist/core/extensions/capability-plugin.js.map +1 -1
  124. package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
  125. package/dist/core/extensions/capability-runtime-events.js +17 -13
  126. package/dist/core/extensions/capability-runtime-events.js.map +1 -1
  127. package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
  128. package/dist/core/extensions/capability-runtime-guards.js +16 -15
  129. package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
  130. package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
  131. package/dist/core/extensions/capability-runtime-manifest.js +52 -30
  132. package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
  133. package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
  134. package/dist/core/extensions/capability-runtime-validation.js +66 -65
  135. package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
  136. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  137. package/dist/core/extensions/capability-runtime.js +147 -127
  138. package/dist/core/extensions/capability-runtime.js.map +1 -1
  139. package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
  140. package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
  141. package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
  142. package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
  143. package/dist/core/extensions/context-strategy-binding.js +7 -4
  144. package/dist/core/extensions/context-strategy-binding.js.map +1 -1
  145. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  146. package/dist/core/extensions/lifecycle-catalog.js +290 -279
  147. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  148. package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
  149. package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
  150. package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
  151. package/dist/core/extensions/provider-failover.d.ts +7 -3
  152. package/dist/core/extensions/provider-failover.d.ts.map +1 -1
  153. package/dist/core/extensions/provider-failover.js +9 -8
  154. package/dist/core/extensions/provider-failover.js.map +1 -1
  155. package/dist/core/facade/coding-agent-facade.d.ts +6 -6
  156. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  157. package/dist/core/facade/coding-agent-facade.js +2 -3
  158. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  159. package/dist/core/http-dispatcher.d.ts.map +1 -1
  160. package/dist/core/http-dispatcher.js +2 -1
  161. package/dist/core/http-dispatcher.js.map +1 -1
  162. package/dist/core/i18n/index.d.ts +14 -0
  163. package/dist/core/i18n/index.d.ts.map +1 -0
  164. package/dist/core/i18n/index.js +67 -0
  165. package/dist/core/i18n/index.js.map +1 -0
  166. package/dist/core/i18n/locales/en/example.d.ts +7 -0
  167. package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
  168. package/dist/core/i18n/locales/en/example.js +7 -0
  169. package/dist/core/i18n/locales/en/example.js.map +1 -0
  170. package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
  171. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
  172. package/dist/core/i18n/locales/zh-cn/cli.js +229 -0
  173. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
  174. package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
  175. package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
  176. package/dist/core/i18n/locales/zh-cn/common.js +6 -0
  177. package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
  178. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
  179. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
  180. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
  181. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
  182. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
  183. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
  184. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
  185. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
  186. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
  187. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
  188. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
  189. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
  190. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
  191. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
  192. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
  193. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
  194. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
  195. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
  196. package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
  197. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
  198. package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
  199. package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
  200. package/dist/core/i18n/locales/zh-cn/example.js +10 -0
  201. package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
  202. package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
  203. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
  204. package/dist/core/i18n/locales/zh-cn/index.js +41 -0
  205. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
  206. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
  207. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
  208. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +267 -0
  209. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
  210. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
  211. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
  212. package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
  213. package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
  214. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
  215. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
  216. package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
  217. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
  218. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
  219. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
  220. package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
  221. package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
  222. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
  223. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
  224. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
  225. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
  226. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
  227. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
  228. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +286 -0
  229. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
  230. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
  231. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
  232. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
  233. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
  234. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
  235. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
  236. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
  237. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
  238. package/dist/core/keybindings.d.ts +15 -0
  239. package/dist/core/keybindings.d.ts.map +1 -1
  240. package/dist/core/keybindings.js +18 -0
  241. package/dist/core/keybindings.js.map +1 -1
  242. package/dist/core/logger.d.ts.map +1 -1
  243. package/dist/core/logger.js +5 -1
  244. package/dist/core/logger.js.map +1 -1
  245. package/dist/core/model-config.d.ts +0 -1
  246. package/dist/core/model-config.d.ts.map +1 -1
  247. package/dist/core/model-config.js +9 -1
  248. package/dist/core/model-config.js.map +1 -1
  249. package/dist/core/model-registry.d.ts.map +1 -1
  250. package/dist/core/model-registry.js +2 -1
  251. package/dist/core/model-registry.js.map +1 -1
  252. package/dist/core/model-runtime.d.ts.map +1 -1
  253. package/dist/core/model-runtime.js +11 -7
  254. package/dist/core/model-runtime.js.map +1 -1
  255. package/dist/core/package-install-host.d.ts.map +1 -1
  256. package/dist/core/package-install-host.js +4 -3
  257. package/dist/core/package-install-host.js.map +1 -1
  258. package/dist/core/package-manager.d.ts.map +1 -1
  259. package/dist/core/package-manager.js +15 -10
  260. package/dist/core/package-manager.js.map +1 -1
  261. package/dist/core/package-resource-collection.d.ts.map +1 -1
  262. package/dist/core/package-resource-collection.js +2 -1
  263. package/dist/core/package-resource-collection.js.map +1 -1
  264. package/dist/core/package-source.d.ts.map +1 -1
  265. package/dist/core/package-source.js +3 -2
  266. package/dist/core/package-source.js.map +1 -1
  267. package/dist/core/provider-composer.d.ts +2 -2
  268. package/dist/core/provider-composer.d.ts.map +1 -1
  269. package/dist/core/provider-composer.js +29 -21
  270. package/dist/core/provider-composer.js.map +1 -1
  271. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  272. package/dist/core/remote-catalog-provider.js +6 -2
  273. package/dist/core/remote-catalog-provider.js.map +1 -1
  274. package/dist/core/resolve-config-value.d.ts.map +1 -1
  275. package/dist/core/resolve-config-value.js +15 -5
  276. package/dist/core/resolve-config-value.js.map +1 -1
  277. package/dist/core/sdk.d.ts +27 -5
  278. package/dist/core/sdk.d.ts.map +1 -1
  279. package/dist/core/sdk.js +80 -55
  280. package/dist/core/sdk.js.map +1 -1
  281. package/dist/core/session-cwd.d.ts.map +1 -1
  282. package/dist/core/session-cwd.js +5 -2
  283. package/dist/core/session-cwd.js.map +1 -1
  284. package/dist/core/session-export.d.ts.map +1 -1
  285. package/dist/core/session-export.js +2 -1
  286. package/dist/core/session-export.js.map +1 -1
  287. package/dist/core/session-manager.d.ts.map +1 -1
  288. package/dist/core/session-manager.js +39 -29
  289. package/dist/core/session-manager.js.map +1 -1
  290. package/dist/core/session-storage.d.ts.map +1 -1
  291. package/dist/core/session-storage.js +3 -3
  292. package/dist/core/session-storage.js.map +1 -1
  293. package/dist/core/settings-manager.d.ts +20 -20
  294. package/dist/core/settings-manager.d.ts.map +1 -1
  295. package/dist/core/settings-manager.js +47 -59
  296. package/dist/core/settings-manager.js.map +1 -1
  297. package/dist/core/slash-commands.d.ts.map +1 -1
  298. package/dist/core/slash-commands.js +53 -32
  299. package/dist/core/slash-commands.js.map +1 -1
  300. package/dist/core/system-prompt.d.ts.map +1 -1
  301. package/dist/core/system-prompt.js +25 -2
  302. package/dist/core/system-prompt.js.map +1 -1
  303. package/dist/core/tools/bash.d.ts.map +1 -1
  304. package/dist/core/tools/bash.js +11 -7
  305. package/dist/core/tools/bash.js.map +1 -1
  306. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  307. package/dist/core/tools/edit-diff.js +9 -4
  308. package/dist/core/tools/edit-diff.js.map +1 -1
  309. package/dist/core/tools/edit.d.ts.map +1 -1
  310. package/dist/core/tools/edit.js +4 -3
  311. package/dist/core/tools/edit.js.map +1 -1
  312. package/dist/core/tools/index.d.ts.map +1 -1
  313. package/dist/core/tools/index.js +3 -2
  314. package/dist/core/tools/index.js.map +1 -1
  315. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  316. package/dist/core/tools/output-accumulator.js +2 -1
  317. package/dist/core/tools/output-accumulator.js.map +1 -1
  318. package/dist/core/tools/read.d.ts.map +1 -1
  319. package/dist/core/tools/read.js +6 -2
  320. package/dist/core/tools/read.js.map +1 -1
  321. package/dist/core/tools/write.d.ts.map +1 -1
  322. package/dist/core/tools/write.js +2 -1
  323. package/dist/core/tools/write.js.map +1 -1
  324. package/dist/durable/durable-service.d.ts.map +1 -1
  325. package/dist/durable/durable-service.js +25 -18
  326. package/dist/durable/durable-service.js.map +1 -1
  327. package/dist/host/checkpoint-commit.d.ts.map +1 -1
  328. package/dist/host/checkpoint-commit.js +2 -1
  329. package/dist/host/checkpoint-commit.js.map +1 -1
  330. package/dist/host/manual-compaction.d.ts.map +1 -1
  331. package/dist/host/manual-compaction.js +2 -1
  332. package/dist/host/manual-compaction.js.map +1 -1
  333. package/dist/host/output-projection.d.ts +0 -13
  334. package/dist/host/output-projection.d.ts.map +1 -1
  335. package/dist/host/output-projection.js +16 -2
  336. package/dist/host/output-projection.js.map +1 -1
  337. package/dist/host/summary-retry.d.ts.map +1 -1
  338. package/dist/host/summary-retry.js +3 -2
  339. package/dist/host/summary-retry.js.map +1 -1
  340. package/dist/main.d.ts.map +1 -1
  341. package/dist/main.js +97 -60
  342. package/dist/main.js.map +1 -1
  343. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  344. package/dist/modes/interactive/components/agents-view.js +18 -15
  345. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  346. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  347. package/dist/modes/interactive/components/assistant-message.js +6 -5
  348. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  349. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/bash-execution.js +12 -7
  351. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  352. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/bordered-loader.js +2 -1
  354. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  355. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  356. package/dist/modes/interactive/components/branch-summary-message.js +6 -5
  357. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  358. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  359. package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
  360. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  361. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  362. package/dist/modes/interactive/components/config-selector.js +18 -15
  363. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  364. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  365. package/dist/modes/interactive/components/custom-entry.js +2 -1
  366. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  367. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/dialog-editor.js +5 -4
  369. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  370. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/dialog-input.js +2 -1
  372. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  373. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/dialog-selector.js +4 -3
  375. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  376. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/first-time-setup.js +11 -10
  378. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  379. package/dist/modes/interactive/components/footer.d.ts +0 -2
  380. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  381. package/dist/modes/interactive/components/footer.js +8 -10
  382. package/dist/modes/interactive/components/footer.js.map +1 -1
  383. package/dist/modes/interactive/components/index.d.ts +1 -0
  384. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/index.js +1 -0
  386. package/dist/modes/interactive/components/index.js.map +1 -1
  387. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  388. package/dist/modes/interactive/components/keybinding-hints.js +3 -2
  389. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  390. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/login-dialog.js +12 -11
  392. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  393. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  394. package/dist/modes/interactive/components/mermaid.js +6 -2
  395. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  396. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/model-selector.js +28 -16
  398. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  399. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/oauth-selector.js +10 -9
  401. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  402. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
  404. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  405. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
  407. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  408. package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
  409. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
  410. package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
  411. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
  412. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
  414. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  415. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/session-selector.js +43 -31
  417. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  418. package/dist/modes/interactive/components/settings-selector.d.ts +4 -6
  419. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/settings-selector.js +115 -120
  421. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  422. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  423. package/dist/modes/interactive/components/settings-submenu.js +5 -4
  424. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  425. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/show-images-selector.js +3 -2
  427. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  428. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
  430. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  431. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  432. package/dist/modes/interactive/components/status-indicator.js +14 -5
  433. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  434. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/theme-selector.js +2 -1
  436. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  437. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/thinking-selector.js +11 -4
  439. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  440. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  441. package/dist/modes/interactive/components/tool-execution.js +8 -3
  442. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  443. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  444. package/dist/modes/interactive/components/tree-list.js +7 -6
  445. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  446. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  447. package/dist/modes/interactive/components/tree-render.js +28 -23
  448. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  449. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/tree-selector.js +9 -7
  451. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  452. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  453. package/dist/modes/interactive/components/user-message-selector.js +5 -4
  454. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  455. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/workflow-view.js +36 -21
  457. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  458. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  459. package/dist/modes/interactive/external-editor.js +2 -1
  460. package/dist/modes/interactive/external-editor.js.map +1 -1
  461. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-auth.js +71 -40
  463. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  464. package/dist/modes/interactive/interactive-commands.d.ts +1 -0
  465. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-commands.js +3 -0
  467. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  468. package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
  469. package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
  470. package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
  471. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  472. package/dist/modes/interactive/interactive-format.js +34 -18
  473. package/dist/modes/interactive/interactive-format.js.map +1 -1
  474. package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
  475. package/dist/modes/interactive/interactive-helpers.js +7 -2
  476. package/dist/modes/interactive/interactive-helpers.js.map +1 -1
  477. package/dist/modes/interactive/interactive-mode.d.ts +4 -2
  478. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  479. package/dist/modes/interactive/interactive-mode.js +350 -279
  480. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  481. package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
  482. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  483. package/dist/modes/interactive/interactive-selectors.js +79 -25
  484. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  485. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  486. package/dist/modes/interactive/theme/theme-controller.js +5 -1
  487. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  488. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  489. package/dist/modes/interactive/theme/theme.js +26 -23
  490. package/dist/modes/interactive/theme/theme.js.map +1 -1
  491. package/dist/modes/json-event.d.ts.map +1 -1
  492. package/dist/modes/json-event.js +3 -2
  493. package/dist/modes/json-event.js.map +1 -1
  494. package/dist/modes/print-mode.d.ts.map +1 -1
  495. package/dist/modes/print-mode.js +3 -2
  496. package/dist/modes/print-mode.js.map +1 -1
  497. package/dist/modes/rpc/rpc-client.d.ts +0 -8
  498. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  499. package/dist/modes/rpc/rpc-client.js +3 -14
  500. package/dist/modes/rpc/rpc-client.js.map +1 -1
  501. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  502. package/dist/modes/rpc/rpc-mode.js +0 -9
  503. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  504. package/dist/modes/rpc/rpc-types.d.ts +0 -19
  505. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  506. package/dist/modes/rpc/rpc-types.js.map +1 -1
  507. package/dist/package-manager-cli.d.ts.map +1 -1
  508. package/dist/package-manager-cli.js +28 -13
  509. package/dist/package-manager-cli.js.map +1 -1
  510. package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
  511. package/dist/plugins/ecosystem/catalog.js +3 -2
  512. package/dist/plugins/ecosystem/catalog.js.map +1 -1
  513. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  514. package/dist/plugins/ecosystem/cli.js +2 -1
  515. package/dist/plugins/ecosystem/cli.js.map +1 -1
  516. package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
  517. package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
  518. package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
  519. package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
  520. package/dist/plugins/ecosystem/distribution.js +2 -1
  521. package/dist/plugins/ecosystem/distribution.js.map +1 -1
  522. package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
  523. package/dist/plugins/ecosystem/installer.js +3 -2
  524. package/dist/plugins/ecosystem/installer.js.map +1 -1
  525. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  526. package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
  527. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  528. package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
  529. package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
  530. package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
  531. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  532. package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
  533. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  534. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  535. package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
  536. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  537. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  538. package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
  539. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  540. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +9 -2
  541. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  542. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +44 -5
  543. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  544. package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
  545. package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
  546. package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
  547. package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
  548. package/dist/plugins/ecosystem/node-registry-source.js +31 -30
  549. package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
  550. package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
  551. package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
  552. package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
  553. package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
  554. package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
  555. package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
  556. package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
  557. package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
  558. package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
  559. package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
  560. package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
  561. package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
  562. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +9 -1
  563. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  564. package/dist/plugins/ecosystem/plugin-bootstrap.js +5 -0
  565. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  566. package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
  567. package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
  568. package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
  569. package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
  570. package/dist/plugins/ecosystem/registry.js +35 -32
  571. package/dist/plugins/ecosystem/registry.js.map +1 -1
  572. package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
  573. package/dist/plugins/ecosystem/resolver.js +3 -2
  574. package/dist/plugins/ecosystem/resolver.js.map +1 -1
  575. package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
  576. package/dist/plugins/ecosystem/selection-store.js +11 -10
  577. package/dist/plugins/ecosystem/selection-store.js.map +1 -1
  578. package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
  579. package/dist/plugins/ecosystem/selection.js +8 -7
  580. package/dist/plugins/ecosystem/selection.js.map +1 -1
  581. package/dist/plugins/ecosystem/state.d.ts.map +1 -1
  582. package/dist/plugins/ecosystem/state.js +24 -23
  583. package/dist/plugins/ecosystem/state.js.map +1 -1
  584. package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
  585. package/dist/plugins/ecosystem/updates.js +5 -4
  586. package/dist/plugins/ecosystem/updates.js.map +1 -1
  587. package/dist/plugins/mcp-http.d.ts +0 -17
  588. package/dist/plugins/mcp-http.d.ts.map +1 -1
  589. package/dist/plugins/mcp-http.js +30 -7
  590. package/dist/plugins/mcp-http.js.map +1 -1
  591. package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
  592. package/dist/plugins/plugin-supervisor.js +19 -1
  593. package/dist/plugins/plugin-supervisor.js.map +1 -1
  594. package/dist/profile/first-roles.d.ts.map +1 -1
  595. package/dist/profile/first-roles.js +10 -1
  596. package/dist/profile/first-roles.js.map +1 -1
  597. package/dist/profile/goal-plugin.d.ts.map +1 -1
  598. package/dist/profile/goal-plugin.js +24 -5
  599. package/dist/profile/goal-plugin.js.map +1 -1
  600. package/dist/profile/identity.d.ts.map +1 -1
  601. package/dist/profile/identity.js +7 -6
  602. package/dist/profile/identity.js.map +1 -1
  603. package/dist/profile/lock.d.ts.map +1 -1
  604. package/dist/profile/lock.js +15 -1
  605. package/dist/profile/lock.js.map +1 -1
  606. package/dist/profile/plan-plugin.d.ts.map +1 -1
  607. package/dist/profile/plan-plugin.js +26 -13
  608. package/dist/profile/plan-plugin.js.map +1 -1
  609. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  610. package/dist/profile/plugin-profiles.js +2 -1
  611. package/dist/profile/plugin-profiles.js.map +1 -1
  612. package/dist/profile/policy-manifest.d.ts.map +1 -1
  613. package/dist/profile/policy-manifest.js +5 -4
  614. package/dist/profile/policy-manifest.js.map +1 -1
  615. package/dist/profile/profile-registry.d.ts +0 -12
  616. package/dist/profile/profile-registry.d.ts.map +1 -1
  617. package/dist/profile/profile-registry.js +14 -1
  618. package/dist/profile/profile-registry.js.map +1 -1
  619. package/dist/profile/role-catalog.d.ts +0 -1
  620. package/dist/profile/role-catalog.d.ts.map +1 -1
  621. package/dist/profile/role-catalog.js +17 -15
  622. package/dist/profile/role-catalog.js.map +1 -1
  623. package/dist/profile/role-orchestrator.d.ts.map +1 -1
  624. package/dist/profile/role-orchestrator.js +8 -7
  625. package/dist/profile/role-orchestrator.js.map +1 -1
  626. package/dist/profile/role-runner.d.ts.map +1 -1
  627. package/dist/profile/role-runner.js +3 -2
  628. package/dist/profile/role-runner.js.map +1 -1
  629. package/dist/profile/root-facade.d.ts.map +1 -1
  630. package/dist/profile/root-facade.js +2 -1
  631. package/dist/profile/root-facade.js.map +1 -1
  632. package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
  633. package/dist/profile/skill-discovery-wiring.js +7 -2
  634. package/dist/profile/skill-discovery-wiring.js.map +1 -1
  635. package/dist/profile/state-store.d.ts.map +1 -1
  636. package/dist/profile/state-store.js +13 -9
  637. package/dist/profile/state-store.js.map +1 -1
  638. package/dist/profile/todo-plugin.d.ts.map +1 -1
  639. package/dist/profile/todo-plugin.js +9 -4
  640. package/dist/profile/todo-plugin.js.map +1 -1
  641. package/dist/profiles/builtin-suites.d.ts +13 -6
  642. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  643. package/dist/profiles/builtin-suites.js +15 -6
  644. package/dist/profiles/builtin-suites.js.map +1 -1
  645. package/dist/profiles/suite-loader.d.ts +25 -1
  646. package/dist/profiles/suite-loader.d.ts.map +1 -1
  647. package/dist/profiles/suite-loader.js +34 -9
  648. package/dist/profiles/suite-loader.js.map +1 -1
  649. package/dist/remote/server-entry.d.ts.map +1 -1
  650. package/dist/remote/server-entry.js +3 -2
  651. package/dist/remote/server-entry.js.map +1 -1
  652. package/dist/remote/session-source.d.ts.map +1 -1
  653. package/dist/remote/session-source.js +8 -4
  654. package/dist/remote/session-source.js.map +1 -1
  655. package/dist/share/session-share.d.ts.map +1 -1
  656. package/dist/share/session-share.js +14 -2
  657. package/dist/share/session-share.js.map +1 -1
  658. package/dist/testing/plugin-testkit.d.ts.map +1 -1
  659. package/dist/testing/plugin-testkit.js +4 -3
  660. package/dist/testing/plugin-testkit.js.map +1 -1
  661. package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
  662. package/dist/testing/runtime-delivery-queue.js +2 -1
  663. package/dist/testing/runtime-delivery-queue.js.map +1 -1
  664. package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
  665. package/dist/testing/session-plugin-testkit.js +10 -7
  666. package/dist/testing/session-plugin-testkit.js.map +1 -1
  667. package/dist/utils/ansi.d.ts.map +1 -1
  668. package/dist/utils/ansi.js +2 -1
  669. package/dist/utils/ansi.js.map +1 -1
  670. package/dist/utils/clipboard.d.ts.map +1 -1
  671. package/dist/utils/clipboard.js +7 -6
  672. package/dist/utils/clipboard.js.map +1 -1
  673. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  674. package/dist/utils/image-resize-worker.js +3 -2
  675. package/dist/utils/image-resize-worker.js.map +1 -1
  676. package/dist/utils/photon.d.ts +2 -2
  677. package/dist/utils/photon.d.ts.map +1 -1
  678. package/dist/utils/photon.js +2 -2
  679. package/dist/utils/photon.js.map +1 -1
  680. package/dist/utils/shell.d.ts.map +1 -1
  681. package/dist/utils/shell.js +9 -8
  682. package/dist/utils/shell.js.map +1 -1
  683. package/dist/utils/tools-manager.d.ts.map +1 -1
  684. package/dist/utils/tools-manager.js +23 -13
  685. package/dist/utils/tools-manager.js.map +1 -1
  686. package/dist/utils/version-check.d.ts.map +1 -1
  687. package/dist/utils/version-check.js +5 -1
  688. package/dist/utils/version-check.js.map +1 -1
  689. package/docs/compaction.md +1 -3
  690. package/docs/docs.json +4 -0
  691. package/docs/index.md +1 -0
  692. package/docs/keybindings.md +3 -0
  693. package/docs/mcp.md +103 -0
  694. package/docs/models.md +14 -22
  695. package/docs/providers.md +0 -1
  696. package/docs/quickstart.md +1 -1
  697. package/docs/rpc.md +1 -26
  698. package/docs/sdk.md +4 -6
  699. package/docs/settings.md +10 -12
  700. package/docs/skills.md +1 -9
  701. package/docs/terminal-setup.md +2 -3
  702. package/docs/usage.md +7 -6
  703. package/examples/extensions/with-deps/package-lock.json +2 -2
  704. package/examples/extensions/with-deps/package.json +1 -1
  705. package/examples/extensions/with-deps/plugin.json +1 -1
  706. package/examples/sdk/10-settings.ts +2 -4
  707. package/examples/sdk/12-full-control.ts +1 -2
  708. package/package.json +1 -3
  709. package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
  710. package/dist/core/extensions/microcompact.d.ts +0 -80
  711. package/dist/core/extensions/microcompact.d.ts.map +0 -1
  712. package/dist/core/extensions/microcompact.js +0 -134
  713. package/dist/core/extensions/microcompact.js.map +0 -1
  714. package/dist/server/create-harness.d.ts +0 -26
  715. package/dist/server/create-harness.d.ts.map +0 -1
  716. package/dist/server/create-harness.js +0 -106
  717. package/dist/server/create-harness.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"user-message-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, getKeybindings, Spacer, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\n\ninterface UserMessageItem {\n\tid: string; // Entry ID in the session\n\ttext: string; // The message text\n\ttimestamp?: string; // Optional timestamp if available\n\t/** First line of the reply that followed this message; conversational\n\t * context for recognizing \"which prompt am I returning to\". */\n\treplySummary?: string;\n}\n\n/**\n * Custom user message list component with selection\n */\nclass UserMessageList implements Component {\n\tprivate messages: UserMessageItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tpublic onSelect?: (entryId: string) => void;\n\tpublic onCancel?: () => void;\n\tprivate maxVisible: number = 10; // Max messages visible\n\n\tconstructor(messages: UserMessageItem[], initialSelectedId?: string) {\n\t\t// Store messages in chronological order (oldest to newest)\n\t\tthis.messages = messages;\n\t\tconst initialIndex = initialSelectedId ? messages.findIndex((message) => message.id === initialSelectedId) : -1;\n\t\t// Start with selected message if provided, else default to the most recent\n\t\tthis.selectedIndex = initialIndex >= 0 ? initialIndex : Math.max(0, messages.length - 1);\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.messages.length === 0) {\n\t\t\tlines.push(theme.fg(\"muted\", \" No user messages found\"));\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.messages.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.messages.length);\n\n\t\t// Render visible messages (2 lines per message + blank line)\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst message = this.messages[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\n\t\t\t// Normalize message to single line\n\t\t\tconst normalizedMessage = message.text.replace(/\\n/g, \" \").trim();\n\n\t\t\t// First line: cursor + message\n\t\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"› \") : \" \";\n\t\t\tconst maxMsgWidth = width - 2; // Account for cursor (2 chars)\n\t\t\tconst truncatedMsg = truncateToWidth(normalizedMessage, maxMsgWidth);\n\t\t\tconst messageLine = cursor + (isSelected ? theme.bold(truncatedMsg) : truncatedMsg);\n\n\t\t\tlines.push(messageLine);\n\n\t\t\t// Second line: position in history plus the first line of the reply\n\t\t\t// that followed (absent when the message never got a reply) so the\n\t\t\t// picker reads as \"which turn am I returning to\", not a bare text list.\n\t\t\tconst position = i + 1;\n\t\t\tconst parts = [`Message ${position} of ${this.messages.length}`];\n\t\t\tif (message.replySummary !== undefined) {\n\t\t\t\tconst maxSummaryWidth = Math.max(10, width - 2 - parts[0].length - 5);\n\t\t\t\tparts.push(`↳ ${truncateToWidth(message.replySummary, maxSummaryWidth)}`);\n\t\t\t}\n\t\t\tconst metadataLine = theme.fg(\"muted\", ` ${parts.join(\" \")}`);\n\t\t\tlines.push(metadataLine);\n\t\t\tlines.push(\"\"); // Blank line between messages\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.messages.length) {\n\t\t\tconst scrollInfo = theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.messages.length})`);\n\t\t\tlines.push(scrollInfo);\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\t// Up arrow - go to previous (older) message, wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.messages.length - 1 : this.selectedIndex - 1;\n\t\t}\n\t\t// Down arrow - go to next (newer) message, wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.messages.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t}\n\t\t// Enter - select message and branch\n\t\telse if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selected = this.messages[this.selectedIndex];\n\t\t\tif (selected && this.onSelect) {\n\t\t\t\tthis.onSelect(selected.id);\n\t\t\t}\n\t\t}\n\t\t// Escape - cancel\n\t\telse if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tif (this.onCancel) {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Component that renders a user message selector for branching\n */\nexport class UserMessageSelectorComponent extends Container {\n\tprivate messageList: UserMessageList;\n\n\tconstructor(\n\t\tmessages: UserMessageItem[],\n\t\tonSelect: (entryId: string) => void,\n\t\tonCancel: () => void,\n\t\tinitialSelectedId?: string,\n\t) {\n\t\tsuper();\n\n\t\t// Add header\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.bold(\"Fork from Message\"), 1, 0));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"muted\", \"Select a user message to copy the active path up to that point into a new session\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create message list\n\t\tthis.messageList = new UserMessageList(messages, initialSelectedId);\n\t\tthis.messageList.onSelect = onSelect;\n\t\tthis.messageList.onCancel = onCancel;\n\n\t\tthis.addChild(this.messageList);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Auto-cancel if no messages\n\t\tif (messages.length === 0) {\n\t\t\tsetTimeout(() => onCancel(), 100);\n\t\t}\n\t}\n\n\tgetMessageList(): UserMessageList {\n\t\treturn this.messageList;\n\t}\n}\n"]}
1
+ {"version":3,"file":"user-message-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, getKeybindings, Spacer, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\n\ninterface UserMessageItem {\n\tid: string; // Entry ID in the session\n\ttext: string; // The message text\n\ttimestamp?: string; // Optional timestamp if available\n\t/** First line of the reply that followed this message; conversational\n\t * context for recognizing \"which prompt am I returning to\". */\n\treplySummary?: string;\n}\n\n/**\n * Custom user message list component with selection\n */\nclass UserMessageList implements Component {\n\tprivate messages: UserMessageItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tpublic onSelect?: (entryId: string) => void;\n\tpublic onCancel?: () => void;\n\tprivate maxVisible: number = 10; // Max messages visible\n\n\tconstructor(messages: UserMessageItem[], initialSelectedId?: string) {\n\t\t// Store messages in chronological order (oldest to newest)\n\t\tthis.messages = messages;\n\t\tconst initialIndex = initialSelectedId ? messages.findIndex((message) => message.id === initialSelectedId) : -1;\n\t\t// Start with selected message if provided, else default to the most recent\n\t\tthis.selectedIndex = initialIndex >= 0 ? initialIndex : Math.max(0, messages.length - 1);\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.messages.length === 0) {\n\t\t\tlines.push(theme.fg(\"muted\", ` ${t(\"No user messages found\")}`));\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.messages.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.messages.length);\n\n\t\t// Render visible messages (2 lines per message + blank line)\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst message = this.messages[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\n\t\t\t// Normalize message to single line\n\t\t\tconst normalizedMessage = message.text.replace(/\\n/g, \" \").trim();\n\n\t\t\t// First line: cursor + message\n\t\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"› \") : \" \";\n\t\t\tconst maxMsgWidth = width - 2; // Account for cursor (2 chars)\n\t\t\tconst truncatedMsg = truncateToWidth(normalizedMessage, maxMsgWidth);\n\t\t\tconst messageLine = cursor + (isSelected ? theme.bold(truncatedMsg) : truncatedMsg);\n\n\t\t\tlines.push(messageLine);\n\n\t\t\t// Second line: position in history plus the first line of the reply\n\t\t\t// that followed (absent when the message never got a reply) so the\n\t\t\t// picker reads as \"which turn am I returning to\", not a bare text list.\n\t\t\tconst position = i + 1;\n\t\t\tconst parts = [t(\"Message {position} of {total}\", { position, total: this.messages.length })];\n\t\t\tif (message.replySummary !== undefined) {\n\t\t\t\tconst maxSummaryWidth = Math.max(10, width - 2 - parts[0].length - 5);\n\t\t\t\tparts.push(`↳ ${truncateToWidth(message.replySummary, maxSummaryWidth)}`);\n\t\t\t}\n\t\t\tconst metadataLine = theme.fg(\"muted\", ` ${parts.join(\" \")}`);\n\t\t\tlines.push(metadataLine);\n\t\t\tlines.push(\"\"); // Blank line between messages\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.messages.length) {\n\t\t\tconst scrollInfo = theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.messages.length})`);\n\t\t\tlines.push(scrollInfo);\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\t// Up arrow - go to previous (older) message, wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.messages.length - 1 : this.selectedIndex - 1;\n\t\t}\n\t\t// Down arrow - go to next (newer) message, wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.messages.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t}\n\t\t// Enter - select message and branch\n\t\telse if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selected = this.messages[this.selectedIndex];\n\t\t\tif (selected && this.onSelect) {\n\t\t\t\tthis.onSelect(selected.id);\n\t\t\t}\n\t\t}\n\t\t// Escape - cancel\n\t\telse if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tif (this.onCancel) {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Component that renders a user message selector for branching\n */\nexport class UserMessageSelectorComponent extends Container {\n\tprivate messageList: UserMessageList;\n\n\tconstructor(\n\t\tmessages: UserMessageItem[],\n\t\tonSelect: (entryId: string) => void,\n\t\tonCancel: () => void,\n\t\tinitialSelectedId?: string,\n\t) {\n\t\tsuper();\n\n\t\t// Add header\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.bold(t(\"Fork from Message\")), 1, 0));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"muted\", t(\"Select a user message to copy the active path up to that point into a new session\")),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create message list\n\t\tthis.messageList = new UserMessageList(messages, initialSelectedId);\n\t\tthis.messageList.onSelect = onSelect;\n\t\tthis.messageList.onCancel = onCancel;\n\n\t\tthis.addChild(this.messageList);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Auto-cancel if no messages\n\t\tif (messages.length === 0) {\n\t\t\tsetTimeout(() => onCancel(), 100);\n\t\t}\n\t}\n\n\tgetMessageList(): UserMessageList {\n\t\treturn this.messageList;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/workflow-view.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workflow overlay view (§9 L2/L3 of docs/design/工作流编排插件设计.md).\n *\n * Read-only panorama (L2) and transition stream (L3) rendered from the\n * session's `workflow.state` / `workflow.transition` custom entries — the\n * same isomorphic read the footer performs on `goal.state`, so the plugin\n * does not need to be present and this module never imports plugin code.\n * Waiting-condition labels mirror the engine's `computeWaitingOn` order\n * (active-limit precedes write-scope conflict); plan lookups read the latest\n * `plan.state` snapshot the same way.\n *\n * Operations are never executed here: approve/reject/skip/cancel forward an\n * action text (e.g. `approve stage s2-review`) to the conversation input and\n * the main agent drives it through workflow_advance — rendering and execution\n * stay separated (设计 §9 L2 \"转发到对话\").\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport type { SessionEntry } from \"../../../core/session-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// View model (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\ntype StageStatus = \"pending\" | \"active\" | \"awaiting_review\" | \"completed\" | \"failed\" | \"skipped\";\n\nconst STAGE_STATUSES: readonly string[] = [\"pending\", \"active\", \"awaiting_review\", \"completed\", \"failed\", \"skipped\"];\n\n/** One selectable stage row of the L2 panorama tree. */\nexport interface WorkflowStageRow {\n\tworkflowId: string;\n\tstageId: string;\n\ttitle: string;\n\tdepth: number;\n\tstatus: StageStatus;\n\t/** §8.1 waiting-condition label, or null when nothing blocks the stage. */\n\twaitingOn: string | null;\n\tattempts: number;\n\tevidenceCount: number;\n\t/** Conflicting active write stage id (write-scope marker), or null. */\n\tscopeConflict: string | null;\n\t/** Diamond edge collapsed to a back-reference instead of a duplicate subtree. */\n\tbackReference: boolean;\n}\n\n/** One workflow block of the L2 panorama. */\nexport interface WorkflowBlock {\n\tworkflowId: string;\n\ttitle: string;\n\tstatus: string;\n\trevision: number;\n\tgoalId: string | undefined;\n\tactiveCount: number;\n\tmaxActiveStages: number;\n\tretreatCount: number;\n\tmaxRetreats: number;\n\tdiagnostics: string[];\n\tstages: WorkflowStageRow[];\n}\n\n/** One L3 transition row (already newest-first, capped by the builder). */\nexport interface WorkflowTransitionRow {\n\trevision: number;\n\tworkflowId: string;\n\tstageId: string | undefined;\n\tfrom: string;\n\tto: string;\n\ttrigger: string;\n\tcode: string;\n\tmessage: string;\n\tdetail: string | undefined;\n}\n\nexport interface WorkflowViewModel {\n\t/** Undefined when the session has no `workflow.state` entry at all. */\n\tpanorama: WorkflowBlock[] | undefined;\n\ttransitions: WorkflowTransitionRow[];\n\t/** Newest non-terminal workflow id (footer's pick), for workflow-level actions. */\n\tactiveWorkflowId: string | undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\ninterface ParsedStageSpec {\n\tid: string;\n\ttitle: string;\n\tdependsOn: string[];\n\tplanId: string | undefined;\n\tkind: \"read\" | \"write\";\n\tscope: string[] | undefined;\n\tacceptanceIds: string[];\n}\n\ninterface ParsedStageRuntime {\n\tstageId: string;\n\tstatus: StageStatus;\n\tattempts: number;\n\tevidenceCount: number;\n\tcoveredAcceptanceIds: Set<string>;\n}\n\ninterface ParsedWorkflow {\n\tid: string;\n\ttitle: string;\n\tstatus: string;\n\trevision: number;\n\tgoalId: string | undefined;\n\tmaxActiveStages: number;\n\tmaxRetreats: number;\n\tretreatCount: number;\n\tdiagnostics: string[];\n\tstages: ParsedStageSpec[];\n\truntime: Map<string, ParsedStageRuntime>;\n}\n\nfunction parseStageSpec(value: unknown): ParsedStageSpec | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = stringOrUndefined(value.id);\n\tif (id === undefined) return undefined;\n\tconst dependsOn = Array.isArray(value.dependsOn) ? value.dependsOn.filter(isString) : [];\n\tconst acceptance =\n\t\tisRecord(value.objective) && Array.isArray(value.objective.acceptance) ? value.objective.acceptance : [];\n\tconst scope = Array.isArray(value.scope) ? value.scope.filter(isString) : undefined;\n\treturn {\n\t\tid,\n\t\ttitle: stringOrUndefined(value.title) ?? id,\n\t\tdependsOn,\n\t\tplanId: stringOrUndefined(value.planId),\n\t\tkind: value.kind === \"read\" ? \"read\" : \"write\",\n\t\tscope: scope !== undefined && scope.length > 0 ? scope : undefined,\n\t\tacceptanceIds: acceptance\n\t\t\t.map((item) => (isRecord(item) ? stringOrUndefined(item.id) : undefined))\n\t\t\t.filter((item): item is string => item !== undefined),\n\t};\n}\n\nfunction isString(value: unknown): value is string {\n\treturn typeof value === \"string\";\n}\n\nfunction parseStageRuntime(value: unknown): ParsedStageRuntime | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst stageId = stringOrUndefined(value.stageId);\n\tconst status = stringOrUndefined(value.status);\n\tif (stageId === undefined || status === undefined || !STAGE_STATUSES.includes(status)) return undefined;\n\tconst evidence = Array.isArray(value.evidence) ? value.evidence : [];\n\tconst covered = new Set<string>();\n\tlet evidenceCount = 0;\n\tfor (const item of evidence) {\n\t\tif (!isRecord(item)) continue;\n\t\tevidenceCount++;\n\t\tconst acceptanceId = stringOrUndefined(item.acceptanceId);\n\t\tif (acceptanceId !== undefined) covered.add(acceptanceId);\n\t}\n\treturn {\n\t\tstageId,\n\t\tstatus: status as StageStatus,\n\t\tattempts: typeof value.attempts === \"number\" ? value.attempts : 0,\n\t\tevidenceCount,\n\t\tcoveredAcceptanceIds: covered,\n\t};\n}\n\nfunction parseWorkflowRecord(value: unknown): ParsedWorkflow | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = stringOrUndefined(value.id);\n\tconst title = stringOrUndefined(value.title);\n\tconst status = stringOrUndefined(value.status);\n\tif (id === undefined || title === undefined || status === undefined) return undefined;\n\tconst stages: ParsedStageSpec[] = [];\n\tfor (const item of Array.isArray(value.stages) ? value.stages : []) {\n\t\tconst spec = parseStageSpec(item);\n\t\tif (spec !== undefined) stages.push(spec);\n\t}\n\tconst runtime = new Map<string, ParsedStageRuntime>();\n\tfor (const item of Array.isArray(value.runtime) ? value.runtime : []) {\n\t\tconst parsed = parseStageRuntime(item);\n\t\tif (parsed !== undefined) runtime.set(parsed.stageId, parsed);\n\t}\n\tconst diagnostics = Array.isArray(value.diagnostics) ? value.diagnostics.filter(isString) : [];\n\treturn {\n\t\tid,\n\t\ttitle,\n\t\tstatus,\n\t\trevision: typeof value.revision === \"number\" ? value.revision : 0,\n\t\tgoalId: stringOrUndefined(value.goalId),\n\t\tmaxActiveStages: typeof value.maxActiveStages === \"number\" ? value.maxActiveStages : 4,\n\t\tmaxRetreats: typeof value.maxRetreats === \"number\" ? value.maxRetreats : 3,\n\t\tretreatCount: typeof value.retreatCount === \"number\" ? value.retreatCount : 0,\n\t\tdiagnostics,\n\t\tstages,\n\t\truntime,\n\t};\n}\n\n/** Latest `plan.state` snapshot reduced to id -> status (plan-dangling / plan-incomplete labels). */\nfunction parsePlanStatuses(data: unknown): Map<string, string> {\n\tconst statuses = new Map<string, string>();\n\tif (!isRecord(data) || !Array.isArray(data.plans)) return statuses;\n\tfor (const item of data.plans) {\n\t\tif (!isRecord(item)) continue;\n\t\tconst id = stringOrUndefined(item.id);\n\t\tconst status = stringOrUndefined(item.status);\n\t\tif (id !== undefined && status !== undefined) statuses.set(id, status);\n\t}\n\treturn statuses;\n}\n\nfunction parseTransition(value: unknown): WorkflowTransitionRow | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst workflowId = stringOrUndefined(value.workflowId);\n\tconst from = stringOrUndefined(value.from);\n\tconst to = stringOrUndefined(value.to);\n\tconst reason = isRecord(value.reason) ? value.reason : undefined;\n\tconst code = reason !== undefined ? stringOrUndefined(reason.code) : undefined;\n\tif (\n\t\tworkflowId === undefined ||\n\t\tfrom === undefined ||\n\t\tto === undefined ||\n\t\tcode === undefined ||\n\t\ttypeof value.revision !== \"number\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\trevision: value.revision,\n\t\tworkflowId,\n\t\tstageId: stringOrUndefined(value.stageId),\n\t\tfrom,\n\t\tto,\n\t\ttrigger: stringOrUndefined(value.trigger) ?? \"tool\",\n\t\tcode,\n\t\tmessage: reason !== undefined ? (stringOrUndefined(reason.message) ?? \"\") : \"\",\n\t\tdetail: reason !== undefined ? stringOrUndefined(reason.detail) : undefined,\n\t};\n}\n\nfunction scopesIntersect(a: string[] | undefined, b: string[] | undefined): boolean {\n\tif (a === undefined || a.length === 0 || b === undefined || b.length === 0) return true;\n\treturn a.some((tag) => b.includes(tag));\n}\n\nfunction findScopeConflict(workflow: ParsedWorkflow, spec: ParsedStageSpec): string | null {\n\tif (spec.kind !== \"write\") return null;\n\tfor (const other of workflow.stages) {\n\t\tif (other.id === spec.id || other.kind !== \"write\") continue;\n\t\tif (workflow.runtime.get(other.id)?.status !== \"active\") continue;\n\t\tif (scopesIntersect(spec.scope, other.scope)) return other.id;\n\t}\n\treturn null;\n}\n\nfunction uncoveredAcceptanceIds(spec: ParsedStageSpec, runtime: ParsedStageRuntime | undefined): string[] {\n\tif (runtime === undefined) return [...spec.acceptanceIds];\n\treturn spec.acceptanceIds.filter((id) => !runtime.coveredAcceptanceIds.has(id));\n}\n\n/**\n * §8.1 waiting-condition label, mirroring the engine's `computeWaitingOn`\n * check order (active-limit precedes write-scope conflict) so the overlay\n * names the same condition the audit stream recorded. Plan lookups use the\n * latest `plan.state` snapshot instead of the engine's live dependency.\n */\nfunction computeWaitingOn(\n\tworkflow: ParsedWorkflow,\n\tspec: ParsedStageSpec,\n\truntime: ParsedStageRuntime | undefined,\n\tplanStatuses: Map<string, string>,\n): string | null {\n\tconst status = runtime?.status ?? \"pending\";\n\tif (status === \"awaiting_review\") return \"review\";\n\tif (status === \"pending\") {\n\t\tif (workflow.status === \"draft\") return \"not-yet-active\";\n\t\tif ((runtime?.attempts ?? 0) > 0) {\n\t\t\tif (spec.acceptanceIds.length === 0) return \"retry-wait\";\n\t\t\treturn `acceptance-missing:[${uncoveredAcceptanceIds(spec, runtime).join(\", \")}]`;\n\t\t}\n\t\tconst incomplete = spec.dependsOn.filter((dep) => {\n\t\t\tconst dependency = workflow.runtime.get(dep)?.status;\n\t\t\treturn dependency !== \"completed\" && dependency !== \"skipped\";\n\t\t});\n\t\tif (incomplete.length > 0) return `deps-incomplete:[${incomplete.join(\", \")}]`;\n\t\tif (spec.planId !== undefined && !planStatuses.has(spec.planId)) return \"plan-dangling\";\n\t\tconst activeCount = [...workflow.runtime.values()].filter((item) => item.status === \"active\").length;\n\t\tif (activeCount >= workflow.maxActiveStages) return \"active-limit\";\n\t\tconst conflict = findScopeConflict(workflow, spec);\n\t\tif (conflict !== null) return `write-scope-conflict:[${conflict}]`;\n\t\treturn \"not-yet-active\";\n\t}\n\tif (status === \"active\") {\n\t\tif (spec.planId === undefined) return null;\n\t\tconst planStatus = planStatuses.get(spec.planId);\n\t\tif (planStatus === undefined) return \"plan-dangling\";\n\t\tif (planStatus !== \"completed\") return \"plan-incomplete\";\n\t\treturn null;\n\t}\n\treturn null;\n}\n\nfunction buildStageRows(workflow: ParsedWorkflow, planStatuses: Map<string, string>): WorkflowStageRow[] {\n\tconst rows: WorkflowStageRow[] = [];\n\tconst visited = new Set<string>();\n\tconst walk = (spec: ParsedStageSpec, depth: number): void => {\n\t\tif (visited.has(spec.id)) {\n\t\t\trows.push({\n\t\t\t\tworkflowId: workflow.id,\n\t\t\t\tstageId: spec.id,\n\t\t\t\ttitle: spec.title,\n\t\t\t\tdepth,\n\t\t\t\tstatus: workflow.runtime.get(spec.id)?.status ?? \"pending\",\n\t\t\t\twaitingOn: null,\n\t\t\t\tattempts: 0,\n\t\t\t\tevidenceCount: 0,\n\t\t\t\tscopeConflict: null,\n\t\t\t\tbackReference: true,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tvisited.add(spec.id);\n\t\tconst runtime = workflow.runtime.get(spec.id);\n\t\trows.push({\n\t\t\tworkflowId: workflow.id,\n\t\t\tstageId: spec.id,\n\t\t\ttitle: spec.title,\n\t\t\tdepth,\n\t\t\tstatus: runtime?.status ?? \"pending\",\n\t\t\twaitingOn: computeWaitingOn(workflow, spec, runtime, planStatuses),\n\t\t\tattempts: runtime?.attempts ?? 0,\n\t\t\tevidenceCount: runtime?.evidenceCount ?? 0,\n\t\t\tscopeConflict: findScopeConflict(workflow, spec),\n\t\t\tbackReference: false,\n\t\t});\n\t\tfor (const child of workflow.stages.filter((item) => item.dependsOn.includes(spec.id))) {\n\t\t\twalk(child, depth + 1);\n\t\t}\n\t};\n\tfor (const root of workflow.stages.filter((item) => item.dependsOn.length === 0)) {\n\t\twalk(root, 0);\n\t}\n\t// Stages unreachable from a root (defensive; the engine validates acyclic\n\t// graphs) still render at the top level, mirroring the L1 text panorama.\n\tfor (const spec of workflow.stages) {\n\t\tif (!visited.has(spec.id)) walk(spec, 0);\n\t}\n\treturn rows;\n}\n\n/**\n * Build the L2/L3 view model from session entries: the latest\n * `workflow.state` snapshot plus the `workflow.transition` audit stream\n * (newest first, capped). Malformed records are skipped, never thrown.\n */\nexport function buildWorkflowViewModel(entries: readonly SessionEntry[], transitionLimit = 30): WorkflowViewModel {\n\tlet stateData: unknown;\n\tlet hasStateEntry = false;\n\tlet planData: unknown;\n\tconst transitions: WorkflowTransitionRow[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\") continue;\n\t\tif (entry.customType === \"workflow.state\") {\n\t\t\thasStateEntry = true;\n\t\t\tstateData = entry.data;\n\t\t} else if (entry.customType === \"plan.state\") {\n\t\t\tplanData = entry.data;\n\t\t} else if (entry.customType === \"workflow.transition\") {\n\t\t\tconst parsed = parseTransition(entry.data);\n\t\t\tif (parsed !== undefined) transitions.push(parsed);\n\t\t}\n\t}\n\n\tconst planStatuses = parsePlanStatuses(planData);\n\tlet blocks: WorkflowBlock[] | undefined;\n\tif (hasStateEntry) {\n\t\tconst workflows = isRecord(stateData) && Array.isArray(stateData.workflows) ? stateData.workflows : [];\n\t\tblocks = workflows\n\t\t\t.map((item) => {\n\t\t\t\tconst parsed = parseWorkflowRecord(item);\n\t\t\t\tif (parsed === undefined) return undefined;\n\t\t\t\treturn {\n\t\t\t\t\tworkflowId: parsed.id,\n\t\t\t\t\ttitle: parsed.title,\n\t\t\t\t\tstatus: parsed.status,\n\t\t\t\t\trevision: parsed.revision,\n\t\t\t\t\tgoalId: parsed.goalId,\n\t\t\t\t\tactiveCount: [...parsed.runtime.values()].filter((item) => item.status === \"active\").length,\n\t\t\t\t\tmaxActiveStages: parsed.maxActiveStages,\n\t\t\t\t\tretreatCount: parsed.retreatCount,\n\t\t\t\t\tmaxRetreats: parsed.maxRetreats,\n\t\t\t\t\tdiagnostics: [...parsed.diagnostics],\n\t\t\t\t\tstages: buildStageRows(parsed, planStatuses),\n\t\t\t\t} satisfies WorkflowBlock;\n\t\t\t})\n\t\t\t.filter((block): block is WorkflowBlock => block !== undefined);\n\t}\n\n\tconst activeRecord = blocks?.filter((block) => block.status === \"draft\" || block.status === \"running\").at(-1);\n\tconst activeWorkflowId = activeRecord?.workflowId ?? blocks?.at(-1)?.workflowId;\n\n\treturn {\n\t\tpanorama: blocks,\n\t\ttransitions: transitions.slice(-transitionLimit).reverse(),\n\t\tactiveWorkflowId,\n\t};\n}\n\n/** Forwarded action vocabulary (§9 L2): rendered here, executed via workflow_advance by the main agent. */\nexport type WorkflowForwardAction = \"approve\" | \"reject\" | \"skip\" | \"cancel\";\n\n/** Action text injected into the conversation input, e.g. `approve stage s2-review`. */\nexport function buildWorkflowActionText(\n\taction: WorkflowForwardAction,\n\tworkflowId: string,\n\tstageId: string | undefined,\n): string {\n\tif (action === \"cancel\" || stageId === undefined) return `cancel workflow ${workflowId}`;\n\treturn `${action} stage ${stageId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Component (L2 panorama + L3 log)\n// ---------------------------------------------------------------------------\n\n/** Selectable row shape used by the component; stage rows carry action targets. */\ninterface ViewRow {\n\ttext: string;\n\tstage: { workflowId: string; stageId: string } | undefined;\n}\n\nfunction stageStatusColor(status: StageStatus): (text: string) => string {\n\tswitch (status) {\n\t\tcase \"active\":\n\t\t\treturn (text) => theme.fg(\"accent\", text);\n\t\tcase \"awaiting_review\":\n\t\t\treturn (text) => theme.fg(\"warning\", text);\n\t\tcase \"completed\":\n\t\t\treturn (text) => theme.fg(\"success\", text);\n\t\tcase \"failed\":\n\t\t\treturn (text) => theme.fg(\"error\", text);\n\t\tcase \"skipped\":\n\t\t\treturn (text) => theme.fg(\"dim\", text);\n\t\tcase \"pending\":\n\t\t\treturn (text) => theme.fg(\"muted\", text);\n\t}\n}\n\nfunction workflowStatusColor(status: string): (text: string) => string {\n\tif (status === \"running\") return (text) => theme.fg(\"accent\", text);\n\tif (status === \"completed\") return (text) => theme.fg(\"success\", text);\n\tif (status === \"failed\") return (text) => theme.fg(\"error\", text);\n\treturn (text) => theme.fg(\"dim\", text);\n}\n\nfunction transitionCodeColor(code: string): (text: string) => string {\n\tif (code.includes(\"failed\") || code.includes(\"retreat\") || code.includes(\"error\") || code.includes(\"limit\")) {\n\t\treturn (text) => theme.fg(\"error\", text);\n\t}\n\tif (code.includes(\"held\") || code.includes(\"retry\") || code.includes(\"amended\")) {\n\t\treturn (text) => theme.fg(\"warning\", text);\n\t}\n\treturn (text) => theme.fg(\"muted\", text);\n}\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass WorkflowRowsView implements Component {\n\tprivate view: WorkflowViewComponent;\n\n\tconstructor(view: WorkflowViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface WorkflowViewConfig {\n\t/** Entries provider; rescanned when the array identity or length changes (append-only sessions). */\n\tgetEntries: () => readonly SessionEntry[];\n\t/** Maximum visible rows before the list scrolls. */\n\tmaxRows: number;\n\t/** Request a TUI re-render (used for transient status flashes). */\n\trequestRender?: () => void;\n}\n\nexport class WorkflowViewComponent extends Container {\n\tpublic onClose?: () => void;\n\tpublic onForwardAction?: (text: string) => void;\n\n\tprivate config: WorkflowViewConfig;\n\tprivate mode: \"panorama\" | \"log\" = \"panorama\";\n\tprivate rows: ViewRow[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\tprivate flashText: Text;\n\tprivate cache: { entries: readonly SessionEntry[]; length: number; model: WorkflowViewModel } | undefined;\n\tprivate flashTimeout: ReturnType<typeof setTimeout> | null = null;\n\n\tconstructor(config: WorkflowViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(\" Workflow Overview\")), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.flashText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new WorkflowRowsView(this));\n\t\tthis.addChild(this.flashText);\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tdispose(): void {\n\t\tif (this.flashTimeout !== null) {\n\t\t\tclearTimeout(this.flashTimeout);\n\t\t\tthis.flashTimeout = null;\n\t\t}\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"panorama\" ? \"panorama\" : \"transition log (newest first)\";\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", \"move\")];\n\t\tif (this.mode === \"panorama\") {\n\t\t\tparts.push(\n\t\t\t\trawKeyHint(\"tab/l\", \"log\"),\n\t\t\t\trawKeyHint(\"a\", \"approve\"),\n\t\t\t\trawKeyHint(\"r\", \"reject\"),\n\t\t\t\trawKeyHint(\"s\", \"skip\"),\n\t\t\t\trawKeyHint(\"c\", \"cancel\"),\n\t\t\t);\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", \"panorama\"));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", \"close\"));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate getModel(): WorkflowViewModel {\n\t\tconst entries = this.config.getEntries();\n\t\tif (this.cache && this.cache.entries === entries && this.cache.length === entries.length) {\n\t\t\treturn this.cache.model;\n\t\t}\n\t\tconst model = buildWorkflowViewModel(entries);\n\t\tthis.cache = { entries, length: entries.length, model };\n\t\treturn model;\n\t}\n\n\tprivate buildRows(model: WorkflowViewModel): ViewRow[] {\n\t\tconst rows: ViewRow[] = [];\n\t\tif (this.mode === \"log\") {\n\t\t\tif (model.transitions.length === 0) {\n\t\t\t\trows.push({ text: \" no workflow transitions recorded\", stage: undefined });\n\t\t\t\treturn rows;\n\t\t\t}\n\t\t\tfor (const transition of model.transitions) {\n\t\t\t\tconst stage = transition.stageId !== undefined ? `/${transition.stageId}` : \"\";\n\t\t\t\tconst detail = transition.detail !== undefined ? ` — ${transition.detail}` : \"\";\n\t\t\t\tconst code = transitionCodeColor(transition.code)(transition.code);\n\t\t\t\trows.push({\n\t\t\t\t\ttext: ` #${transition.revision} ${transition.workflowId}${stage} ${transition.from} -> ${transition.to} [${transition.trigger}] ${code}: ${transition.message}${detail}`,\n\t\t\t\t\tstage: undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn rows;\n\t\t}\n\n\t\tconst blocks = model.panorama;\n\t\tif (blocks === undefined) {\n\t\t\trows.push({ text: \" no workflow.state entry in this session\", stage: undefined });\n\t\t\treturn rows;\n\t\t}\n\t\tif (blocks.length === 0) {\n\t\t\trows.push({ text: \" no workflows in this session; create one with workflow_set\", stage: undefined });\n\t\t\treturn rows;\n\t\t}\n\t\tfor (const block of blocks) {\n\t\t\tconst status = workflowStatusColor(block.status)(block.status);\n\t\t\trows.push({\n\t\t\t\ttext: ` workflow \"${block.title}\" (${block.workflowId}) — ${status} · revision ${block.revision} · active ${block.activeCount}/${block.maxActiveStages} · retreats ${block.retreatCount}/${block.maxRetreats}`,\n\t\t\t\tstage: undefined,\n\t\t\t});\n\t\t\tif (block.goalId !== undefined) {\n\t\t\t\trows.push({ text: ` goal: ${block.goalId}`, stage: undefined });\n\t\t\t}\n\t\t\tfor (const stage of block.stages) {\n\t\t\t\trows.push({\n\t\t\t\t\ttext: this.formatStageRow(stage),\n\t\t\t\t\tstage: { workflowId: block.workflowId, stageId: stage.stageId },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (block.diagnostics.length > 0) {\n\t\t\t\trows.push({ text: \" diagnostics:\", stage: undefined });\n\t\t\t\tfor (const diagnostic of block.diagnostics) {\n\t\t\t\t\trows.push({ text: theme.fg(\"warning\", ` - ${diagnostic}`), stage: undefined });\n\t\t\t\t}\n\t\t\t}\n\t\t\trows.push({ text: \"\", stage: undefined });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate formatStageRow(stage: WorkflowStageRow): string {\n\t\tconst pad = \" \".repeat(stage.depth + 1);\n\t\tif (stage.backReference) {\n\t\t\treturn `${pad} -> ${stage.stageId} (shown above)`;\n\t\t}\n\t\tconst bits = [`- ${stage.stageId} [${stageStatusColor(stage.status)(stage.status)}] ${stage.title}`];\n\t\tif (stage.waitingOn !== null) bits.push(theme.fg(\"dim\", `— waiting: ${stage.waitingOn}`));\n\t\tif (stage.attempts > 0) bits.push(theme.fg(\"dim\", `· attempts ${stage.attempts}`));\n\t\tif (stage.evidenceCount > 0) bits.push(theme.fg(\"dim\", `· evidence ${stage.evidenceCount}`));\n\t\tif (stage.scopeConflict !== null) {\n\t\t\tbits.push(theme.fg(\"warning\", `⚠ scope:${stage.scopeConflict}`));\n\t\t}\n\t\treturn `${pad}${bits.join(\" \")}`;\n\t}\n\n\t/** Rows are rebuilt lazily on access; the key couples rebuild + selection restore. */\n\tprivate syncRows(): void {\n\t\tconst model = this.getModel();\n\t\tconst previous = this.rows[this.selectedIndex]?.stage;\n\t\tthis.rows = this.buildRows(model);\n\t\tif (previous !== undefined) {\n\t\t\tconst restored = this.rows.findIndex((row) => row.stage?.stageId === previous.stageId);\n\t\t\tif (restored !== -1) this.selectedIndex = restored;\n\t\t}\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row.text}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this final\n\t\t// indicator row), the same contract as agents-view renderRows: the\n\t\t// overlay's grid footprint must not change with mode switches or row\n\t\t// counts, or the chat/editor layout boundary moves between frames.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate flash(message: string): void {\n\t\tthis.flashText.setText(theme.fg(\"warning\", ` ${message}`));\n\t\tif (this.flashTimeout !== null) clearTimeout(this.flashTimeout);\n\t\tthis.flashTimeout = setTimeout(() => {\n\t\t\tthis.flashText.setText(\"\");\n\t\t\tthis.flashTimeout = null;\n\t\t\tthis.config.requestRender?.();\n\t\t}, 2500);\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate toggleMode(): void {\n\t\tthis.mode = this.mode === \"panorama\" ? \"log\" : \"panorama\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate forward(action: WorkflowForwardAction): void {\n\t\tconst selected = this.rows[this.selectedIndex];\n\t\tif (selected?.stage === undefined) {\n\t\t\tif (action === \"cancel\") {\n\t\t\t\tconst workflowId = this.getModel().activeWorkflowId;\n\t\t\t\tif (workflowId === undefined) {\n\t\t\t\t\tthis.flash(\"No workflow to cancel\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onForwardAction?.(buildWorkflowActionText(action, workflowId, undefined));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.flash(\"Select a stage row first\");\n\t\t\treturn;\n\t\t}\n\t\tthis.onForwardAction?.(buildWorkflowActionText(action, selected.stage.workflowId, selected.stage.stageId));\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tthis.toggleMode();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t} else if (keyData === \"a\") {\n\t\t\tthis.forward(\"approve\");\n\t\t} else if (keyData === \"r\") {\n\t\t\tthis.forward(\"reject\");\n\t\t} else if (keyData === \"s\") {\n\t\t\tthis.forward(\"skip\");\n\t\t} else if (keyData === \"c\") {\n\t\t\tthis.forward(\"cancel\");\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"workflow-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/workflow-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAkB,SAAS,EAAyC,MAAM,kBAAkB,CAAC;AAEpG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AASrE,KAAK,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,iBAAiB,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAIjG,wDAAwD;AACxD,MAAM,WAAW,gBAAgB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,4EAA2E;IAC3E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iFAAiF;IACjF,aAAa,EAAE,OAAO,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,2EAA2E;AAC3E,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IACjC,uEAAuE;IACvE,QAAQ,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACtC,WAAW,EAAE,qBAAqB,EAAE,CAAC;IACrC,mFAAmF;IACnF,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAkRD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,eAAe,SAAK,GAAG,iBAAiB,CAmDhH;AAED,4GAA2G;AAC3G,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7E,wFAAwF;AACxF,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,CAGR;AA6DD,MAAM,WAAW,kBAAkB;IAClC,oGAAoG;IACpG,UAAU,EAAE,MAAM,SAAS,YAAY,EAAE,CAAC;IAC1C,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,qBAAa,qBAAsB,SAAQ,SAAS;IAC5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,QAAQ,CAAO;IACvB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,KAAK,CAA6F;IAC1G,OAAO,CAAC,YAAY,CAA8C;IAElE,YAAY,MAAM,EAAE,kBAAkB,EAiBrC;IAED,OAAO,IAAI,IAAI,CAKd;IAED,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,SAAS;IAqEjB,OAAO,CAAC,cAAc;IAmBtB,sFAAsF;IACtF,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,WAAW;IAOnB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuBlC;IAED,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,OAAO;IAkBf,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAuBjC;CACD","sourcesContent":["/**\n * Workflow overlay view (§9 L2/L3 of docs/design/工作流编排插件设计.md).\n *\n * Read-only panorama (L2) and transition stream (L3) rendered from the\n * session's `workflow.state` / `workflow.transition` custom entries — the\n * same isomorphic read the footer performs on `goal.state`, so the plugin\n * does not need to be present and this module never imports plugin code.\n * Waiting-condition labels mirror the engine's `computeWaitingOn` order\n * (active-limit precedes write-scope conflict); plan lookups read the latest\n * `plan.state` snapshot the same way.\n *\n * Operations are never executed here: approve/reject/skip/cancel forward an\n * action text (e.g. `approve stage s2-review`) to the conversation input and\n * the main agent drives it through workflow_advance — rendering and execution\n * stay separated (设计 §9 L2 \"转发到对话\").\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport type { SessionEntry } from \"../../../core/session-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// View model (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\ntype StageStatus = \"pending\" | \"active\" | \"awaiting_review\" | \"completed\" | \"failed\" | \"skipped\";\n\nconst STAGE_STATUSES: readonly string[] = [\"pending\", \"active\", \"awaiting_review\", \"completed\", \"failed\", \"skipped\"];\n\n/** One selectable stage row of the L2 panorama tree. */\nexport interface WorkflowStageRow {\n\tworkflowId: string;\n\tstageId: string;\n\ttitle: string;\n\tdepth: number;\n\tstatus: StageStatus;\n\t/** §8.1 waiting-condition label, or null when nothing blocks the stage. */\n\twaitingOn: string | null;\n\tattempts: number;\n\tevidenceCount: number;\n\t/** Conflicting active write stage id (write-scope marker), or null. */\n\tscopeConflict: string | null;\n\t/** Diamond edge collapsed to a back-reference instead of a duplicate subtree. */\n\tbackReference: boolean;\n}\n\n/** One workflow block of the L2 panorama. */\nexport interface WorkflowBlock {\n\tworkflowId: string;\n\ttitle: string;\n\tstatus: string;\n\trevision: number;\n\tgoalId: string | undefined;\n\tactiveCount: number;\n\tmaxActiveStages: number;\n\tretreatCount: number;\n\tmaxRetreats: number;\n\tdiagnostics: string[];\n\tstages: WorkflowStageRow[];\n}\n\n/** One L3 transition row (already newest-first, capped by the builder). */\nexport interface WorkflowTransitionRow {\n\trevision: number;\n\tworkflowId: string;\n\tstageId: string | undefined;\n\tfrom: string;\n\tto: string;\n\ttrigger: string;\n\tcode: string;\n\tmessage: string;\n\tdetail: string | undefined;\n}\n\nexport interface WorkflowViewModel {\n\t/** Undefined when the session has no `workflow.state` entry at all. */\n\tpanorama: WorkflowBlock[] | undefined;\n\ttransitions: WorkflowTransitionRow[];\n\t/** Newest non-terminal workflow id (footer's pick), for workflow-level actions. */\n\tactiveWorkflowId: string | undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\ninterface ParsedStageSpec {\n\tid: string;\n\ttitle: string;\n\tdependsOn: string[];\n\tplanId: string | undefined;\n\tkind: \"read\" | \"write\";\n\tscope: string[] | undefined;\n\tacceptanceIds: string[];\n}\n\ninterface ParsedStageRuntime {\n\tstageId: string;\n\tstatus: StageStatus;\n\tattempts: number;\n\tevidenceCount: number;\n\tcoveredAcceptanceIds: Set<string>;\n}\n\ninterface ParsedWorkflow {\n\tid: string;\n\ttitle: string;\n\tstatus: string;\n\trevision: number;\n\tgoalId: string | undefined;\n\tmaxActiveStages: number;\n\tmaxRetreats: number;\n\tretreatCount: number;\n\tdiagnostics: string[];\n\tstages: ParsedStageSpec[];\n\truntime: Map<string, ParsedStageRuntime>;\n}\n\nfunction parseStageSpec(value: unknown): ParsedStageSpec | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = stringOrUndefined(value.id);\n\tif (id === undefined) return undefined;\n\tconst dependsOn = Array.isArray(value.dependsOn) ? value.dependsOn.filter(isString) : [];\n\tconst acceptance =\n\t\tisRecord(value.objective) && Array.isArray(value.objective.acceptance) ? value.objective.acceptance : [];\n\tconst scope = Array.isArray(value.scope) ? value.scope.filter(isString) : undefined;\n\treturn {\n\t\tid,\n\t\ttitle: stringOrUndefined(value.title) ?? id,\n\t\tdependsOn,\n\t\tplanId: stringOrUndefined(value.planId),\n\t\tkind: value.kind === \"read\" ? \"read\" : \"write\",\n\t\tscope: scope !== undefined && scope.length > 0 ? scope : undefined,\n\t\tacceptanceIds: acceptance\n\t\t\t.map((item) => (isRecord(item) ? stringOrUndefined(item.id) : undefined))\n\t\t\t.filter((item): item is string => item !== undefined),\n\t};\n}\n\nfunction isString(value: unknown): value is string {\n\treturn typeof value === \"string\";\n}\n\nfunction parseStageRuntime(value: unknown): ParsedStageRuntime | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst stageId = stringOrUndefined(value.stageId);\n\tconst status = stringOrUndefined(value.status);\n\tif (stageId === undefined || status === undefined || !STAGE_STATUSES.includes(status)) return undefined;\n\tconst evidence = Array.isArray(value.evidence) ? value.evidence : [];\n\tconst covered = new Set<string>();\n\tlet evidenceCount = 0;\n\tfor (const item of evidence) {\n\t\tif (!isRecord(item)) continue;\n\t\tevidenceCount++;\n\t\tconst acceptanceId = stringOrUndefined(item.acceptanceId);\n\t\tif (acceptanceId !== undefined) covered.add(acceptanceId);\n\t}\n\treturn {\n\t\tstageId,\n\t\tstatus: status as StageStatus,\n\t\tattempts: typeof value.attempts === \"number\" ? value.attempts : 0,\n\t\tevidenceCount,\n\t\tcoveredAcceptanceIds: covered,\n\t};\n}\n\nfunction parseWorkflowRecord(value: unknown): ParsedWorkflow | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = stringOrUndefined(value.id);\n\tconst title = stringOrUndefined(value.title);\n\tconst status = stringOrUndefined(value.status);\n\tif (id === undefined || title === undefined || status === undefined) return undefined;\n\tconst stages: ParsedStageSpec[] = [];\n\tfor (const item of Array.isArray(value.stages) ? value.stages : []) {\n\t\tconst spec = parseStageSpec(item);\n\t\tif (spec !== undefined) stages.push(spec);\n\t}\n\tconst runtime = new Map<string, ParsedStageRuntime>();\n\tfor (const item of Array.isArray(value.runtime) ? value.runtime : []) {\n\t\tconst parsed = parseStageRuntime(item);\n\t\tif (parsed !== undefined) runtime.set(parsed.stageId, parsed);\n\t}\n\tconst diagnostics = Array.isArray(value.diagnostics) ? value.diagnostics.filter(isString) : [];\n\treturn {\n\t\tid,\n\t\ttitle,\n\t\tstatus,\n\t\trevision: typeof value.revision === \"number\" ? value.revision : 0,\n\t\tgoalId: stringOrUndefined(value.goalId),\n\t\tmaxActiveStages: typeof value.maxActiveStages === \"number\" ? value.maxActiveStages : 4,\n\t\tmaxRetreats: typeof value.maxRetreats === \"number\" ? value.maxRetreats : 3,\n\t\tretreatCount: typeof value.retreatCount === \"number\" ? value.retreatCount : 0,\n\t\tdiagnostics,\n\t\tstages,\n\t\truntime,\n\t};\n}\n\n/** Latest `plan.state` snapshot reduced to id -> status (plan-dangling / plan-incomplete labels). */\nfunction parsePlanStatuses(data: unknown): Map<string, string> {\n\tconst statuses = new Map<string, string>();\n\tif (!isRecord(data) || !Array.isArray(data.plans)) return statuses;\n\tfor (const item of data.plans) {\n\t\tif (!isRecord(item)) continue;\n\t\tconst id = stringOrUndefined(item.id);\n\t\tconst status = stringOrUndefined(item.status);\n\t\tif (id !== undefined && status !== undefined) statuses.set(id, status);\n\t}\n\treturn statuses;\n}\n\nfunction parseTransition(value: unknown): WorkflowTransitionRow | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst workflowId = stringOrUndefined(value.workflowId);\n\tconst from = stringOrUndefined(value.from);\n\tconst to = stringOrUndefined(value.to);\n\tconst reason = isRecord(value.reason) ? value.reason : undefined;\n\tconst code = reason !== undefined ? stringOrUndefined(reason.code) : undefined;\n\tif (\n\t\tworkflowId === undefined ||\n\t\tfrom === undefined ||\n\t\tto === undefined ||\n\t\tcode === undefined ||\n\t\ttypeof value.revision !== \"number\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\trevision: value.revision,\n\t\tworkflowId,\n\t\tstageId: stringOrUndefined(value.stageId),\n\t\tfrom,\n\t\tto,\n\t\ttrigger: stringOrUndefined(value.trigger) ?? \"tool\",\n\t\tcode,\n\t\tmessage: reason !== undefined ? (stringOrUndefined(reason.message) ?? \"\") : \"\",\n\t\tdetail: reason !== undefined ? stringOrUndefined(reason.detail) : undefined,\n\t};\n}\n\nfunction scopesIntersect(a: string[] | undefined, b: string[] | undefined): boolean {\n\tif (a === undefined || a.length === 0 || b === undefined || b.length === 0) return true;\n\treturn a.some((tag) => b.includes(tag));\n}\n\nfunction findScopeConflict(workflow: ParsedWorkflow, spec: ParsedStageSpec): string | null {\n\tif (spec.kind !== \"write\") return null;\n\tfor (const other of workflow.stages) {\n\t\tif (other.id === spec.id || other.kind !== \"write\") continue;\n\t\tif (workflow.runtime.get(other.id)?.status !== \"active\") continue;\n\t\tif (scopesIntersect(spec.scope, other.scope)) return other.id;\n\t}\n\treturn null;\n}\n\nfunction uncoveredAcceptanceIds(spec: ParsedStageSpec, runtime: ParsedStageRuntime | undefined): string[] {\n\tif (runtime === undefined) return [...spec.acceptanceIds];\n\treturn spec.acceptanceIds.filter((id) => !runtime.coveredAcceptanceIds.has(id));\n}\n\n/**\n * §8.1 waiting-condition label, mirroring the engine's `computeWaitingOn`\n * check order (active-limit precedes write-scope conflict) so the overlay\n * names the same condition the audit stream recorded. Plan lookups use the\n * latest `plan.state` snapshot instead of the engine's live dependency.\n */\nfunction computeWaitingOn(\n\tworkflow: ParsedWorkflow,\n\tspec: ParsedStageSpec,\n\truntime: ParsedStageRuntime | undefined,\n\tplanStatuses: Map<string, string>,\n): string | null {\n\tconst status = runtime?.status ?? \"pending\";\n\tif (status === \"awaiting_review\") return \"review\";\n\tif (status === \"pending\") {\n\t\tif (workflow.status === \"draft\") return \"not-yet-active\";\n\t\tif ((runtime?.attempts ?? 0) > 0) {\n\t\t\tif (spec.acceptanceIds.length === 0) return \"retry-wait\";\n\t\t\treturn `acceptance-missing:[${uncoveredAcceptanceIds(spec, runtime).join(\", \")}]`;\n\t\t}\n\t\tconst incomplete = spec.dependsOn.filter((dep) => {\n\t\t\tconst dependency = workflow.runtime.get(dep)?.status;\n\t\t\treturn dependency !== \"completed\" && dependency !== \"skipped\";\n\t\t});\n\t\tif (incomplete.length > 0) return `deps-incomplete:[${incomplete.join(\", \")}]`;\n\t\tif (spec.planId !== undefined && !planStatuses.has(spec.planId)) return \"plan-dangling\";\n\t\tconst activeCount = [...workflow.runtime.values()].filter((item) => item.status === \"active\").length;\n\t\tif (activeCount >= workflow.maxActiveStages) return \"active-limit\";\n\t\tconst conflict = findScopeConflict(workflow, spec);\n\t\tif (conflict !== null) return `write-scope-conflict:[${conflict}]`;\n\t\treturn \"not-yet-active\";\n\t}\n\tif (status === \"active\") {\n\t\tif (spec.planId === undefined) return null;\n\t\tconst planStatus = planStatuses.get(spec.planId);\n\t\tif (planStatus === undefined) return \"plan-dangling\";\n\t\tif (planStatus !== \"completed\") return \"plan-incomplete\";\n\t\treturn null;\n\t}\n\treturn null;\n}\n\nfunction buildStageRows(workflow: ParsedWorkflow, planStatuses: Map<string, string>): WorkflowStageRow[] {\n\tconst rows: WorkflowStageRow[] = [];\n\tconst visited = new Set<string>();\n\tconst walk = (spec: ParsedStageSpec, depth: number): void => {\n\t\tif (visited.has(spec.id)) {\n\t\t\trows.push({\n\t\t\t\tworkflowId: workflow.id,\n\t\t\t\tstageId: spec.id,\n\t\t\t\ttitle: spec.title,\n\t\t\t\tdepth,\n\t\t\t\tstatus: workflow.runtime.get(spec.id)?.status ?? \"pending\",\n\t\t\t\twaitingOn: null,\n\t\t\t\tattempts: 0,\n\t\t\t\tevidenceCount: 0,\n\t\t\t\tscopeConflict: null,\n\t\t\t\tbackReference: true,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tvisited.add(spec.id);\n\t\tconst runtime = workflow.runtime.get(spec.id);\n\t\trows.push({\n\t\t\tworkflowId: workflow.id,\n\t\t\tstageId: spec.id,\n\t\t\ttitle: spec.title,\n\t\t\tdepth,\n\t\t\tstatus: runtime?.status ?? \"pending\",\n\t\t\twaitingOn: computeWaitingOn(workflow, spec, runtime, planStatuses),\n\t\t\tattempts: runtime?.attempts ?? 0,\n\t\t\tevidenceCount: runtime?.evidenceCount ?? 0,\n\t\t\tscopeConflict: findScopeConflict(workflow, spec),\n\t\t\tbackReference: false,\n\t\t});\n\t\tfor (const child of workflow.stages.filter((item) => item.dependsOn.includes(spec.id))) {\n\t\t\twalk(child, depth + 1);\n\t\t}\n\t};\n\tfor (const root of workflow.stages.filter((item) => item.dependsOn.length === 0)) {\n\t\twalk(root, 0);\n\t}\n\t// Stages unreachable from a root (defensive; the engine validates acyclic\n\t// graphs) still render at the top level, mirroring the L1 text panorama.\n\tfor (const spec of workflow.stages) {\n\t\tif (!visited.has(spec.id)) walk(spec, 0);\n\t}\n\treturn rows;\n}\n\n/**\n * Build the L2/L3 view model from session entries: the latest\n * `workflow.state` snapshot plus the `workflow.transition` audit stream\n * (newest first, capped). Malformed records are skipped, never thrown.\n */\nexport function buildWorkflowViewModel(entries: readonly SessionEntry[], transitionLimit = 30): WorkflowViewModel {\n\tlet stateData: unknown;\n\tlet hasStateEntry = false;\n\tlet planData: unknown;\n\tconst transitions: WorkflowTransitionRow[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\") continue;\n\t\tif (entry.customType === \"workflow.state\") {\n\t\t\thasStateEntry = true;\n\t\t\tstateData = entry.data;\n\t\t} else if (entry.customType === \"plan.state\") {\n\t\t\tplanData = entry.data;\n\t\t} else if (entry.customType === \"workflow.transition\") {\n\t\t\tconst parsed = parseTransition(entry.data);\n\t\t\tif (parsed !== undefined) transitions.push(parsed);\n\t\t}\n\t}\n\n\tconst planStatuses = parsePlanStatuses(planData);\n\tlet blocks: WorkflowBlock[] | undefined;\n\tif (hasStateEntry) {\n\t\tconst workflows = isRecord(stateData) && Array.isArray(stateData.workflows) ? stateData.workflows : [];\n\t\tblocks = workflows\n\t\t\t.map((item) => {\n\t\t\t\tconst parsed = parseWorkflowRecord(item);\n\t\t\t\tif (parsed === undefined) return undefined;\n\t\t\t\treturn {\n\t\t\t\t\tworkflowId: parsed.id,\n\t\t\t\t\ttitle: parsed.title,\n\t\t\t\t\tstatus: parsed.status,\n\t\t\t\t\trevision: parsed.revision,\n\t\t\t\t\tgoalId: parsed.goalId,\n\t\t\t\t\tactiveCount: [...parsed.runtime.values()].filter((item) => item.status === \"active\").length,\n\t\t\t\t\tmaxActiveStages: parsed.maxActiveStages,\n\t\t\t\t\tretreatCount: parsed.retreatCount,\n\t\t\t\t\tmaxRetreats: parsed.maxRetreats,\n\t\t\t\t\tdiagnostics: [...parsed.diagnostics],\n\t\t\t\t\tstages: buildStageRows(parsed, planStatuses),\n\t\t\t\t} satisfies WorkflowBlock;\n\t\t\t})\n\t\t\t.filter((block): block is WorkflowBlock => block !== undefined);\n\t}\n\n\tconst activeRecord = blocks?.filter((block) => block.status === \"draft\" || block.status === \"running\").at(-1);\n\tconst activeWorkflowId = activeRecord?.workflowId ?? blocks?.at(-1)?.workflowId;\n\n\treturn {\n\t\tpanorama: blocks,\n\t\ttransitions: transitions.slice(-transitionLimit).reverse(),\n\t\tactiveWorkflowId,\n\t};\n}\n\n/** Forwarded action vocabulary (§9 L2): rendered here, executed via workflow_advance by the main agent. */\nexport type WorkflowForwardAction = \"approve\" | \"reject\" | \"skip\" | \"cancel\";\n\n/** Action text injected into the conversation input, e.g. `approve stage s2-review`. */\nexport function buildWorkflowActionText(\n\taction: WorkflowForwardAction,\n\tworkflowId: string,\n\tstageId: string | undefined,\n): string {\n\tif (action === \"cancel\" || stageId === undefined) return `cancel workflow ${workflowId}`;\n\treturn `${action} stage ${stageId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Component (L2 panorama + L3 log)\n// ---------------------------------------------------------------------------\n\n/** Selectable row shape used by the component; stage rows carry action targets. */\ninterface ViewRow {\n\ttext: string;\n\tstage: { workflowId: string; stageId: string } | undefined;\n}\n\nfunction stageStatusColor(status: StageStatus): (text: string) => string {\n\tswitch (status) {\n\t\tcase \"active\":\n\t\t\treturn (text) => theme.fg(\"accent\", text);\n\t\tcase \"awaiting_review\":\n\t\t\treturn (text) => theme.fg(\"warning\", text);\n\t\tcase \"completed\":\n\t\t\treturn (text) => theme.fg(\"success\", text);\n\t\tcase \"failed\":\n\t\t\treturn (text) => theme.fg(\"error\", text);\n\t\tcase \"skipped\":\n\t\t\treturn (text) => theme.fg(\"dim\", text);\n\t\tcase \"pending\":\n\t\t\treturn (text) => theme.fg(\"muted\", text);\n\t}\n}\n\nfunction workflowStatusColor(status: string): (text: string) => string {\n\tif (status === \"running\") return (text) => theme.fg(\"accent\", text);\n\tif (status === \"completed\") return (text) => theme.fg(\"success\", text);\n\tif (status === \"failed\") return (text) => theme.fg(\"error\", text);\n\treturn (text) => theme.fg(\"dim\", text);\n}\n\nfunction transitionCodeColor(code: string): (text: string) => string {\n\tif (code.includes(\"failed\") || code.includes(\"retreat\") || code.includes(\"error\") || code.includes(\"limit\")) {\n\t\treturn (text) => theme.fg(\"error\", text);\n\t}\n\tif (code.includes(\"held\") || code.includes(\"retry\") || code.includes(\"amended\")) {\n\t\treturn (text) => theme.fg(\"warning\", text);\n\t}\n\treturn (text) => theme.fg(\"muted\", text);\n}\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass WorkflowRowsView implements Component {\n\tprivate view: WorkflowViewComponent;\n\n\tconstructor(view: WorkflowViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface WorkflowViewConfig {\n\t/** Entries provider; rescanned when the array identity or length changes (append-only sessions). */\n\tgetEntries: () => readonly SessionEntry[];\n\t/** Maximum visible rows before the list scrolls. */\n\tmaxRows: number;\n\t/** Request a TUI re-render (used for transient status flashes). */\n\trequestRender?: () => void;\n}\n\nexport class WorkflowViewComponent extends Container {\n\tpublic onClose?: () => void;\n\tpublic onForwardAction?: (text: string) => void;\n\n\tprivate config: WorkflowViewConfig;\n\tprivate mode: \"panorama\" | \"log\" = \"panorama\";\n\tprivate rows: ViewRow[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\tprivate flashText: Text;\n\tprivate cache: { entries: readonly SessionEntry[]; length: number; model: WorkflowViewModel } | undefined;\n\tprivate flashTimeout: ReturnType<typeof setTimeout> | null = null;\n\n\tconstructor(config: WorkflowViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(` ${t(\"Workflow Overview\")}`)), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.flashText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new WorkflowRowsView(this));\n\t\tthis.addChild(this.flashText);\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tdispose(): void {\n\t\tif (this.flashTimeout !== null) {\n\t\t\tclearTimeout(this.flashTimeout);\n\t\t\tthis.flashTimeout = null;\n\t\t}\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"panorama\" ? t(\"panorama\") : t(\"transition log (newest first)\");\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", t(\"move\"))];\n\t\tif (this.mode === \"panorama\") {\n\t\t\tparts.push(\n\t\t\t\trawKeyHint(\"tab/l\", t(\"log\")),\n\t\t\t\trawKeyHint(\"a\", t(\"approve\")),\n\t\t\t\trawKeyHint(\"r\", t(\"reject\")),\n\t\t\t\trawKeyHint(\"s\", t(\"skip\")),\n\t\t\t\trawKeyHint(\"c\", t(\"cancel\")),\n\t\t\t);\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"panorama\")));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", t(\"close\")));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate getModel(): WorkflowViewModel {\n\t\tconst entries = this.config.getEntries();\n\t\tif (this.cache && this.cache.entries === entries && this.cache.length === entries.length) {\n\t\t\treturn this.cache.model;\n\t\t}\n\t\tconst model = buildWorkflowViewModel(entries);\n\t\tthis.cache = { entries, length: entries.length, model };\n\t\treturn model;\n\t}\n\n\tprivate buildRows(model: WorkflowViewModel): ViewRow[] {\n\t\tconst rows: ViewRow[] = [];\n\t\tif (this.mode === \"log\") {\n\t\t\tif (model.transitions.length === 0) {\n\t\t\t\trows.push({ text: ` ${t(\"no workflow transitions recorded\")}`, stage: undefined });\n\t\t\t\treturn rows;\n\t\t\t}\n\t\t\tfor (const transition of model.transitions) {\n\t\t\t\tconst stage = transition.stageId !== undefined ? `/${transition.stageId}` : \"\";\n\t\t\t\tconst detail = transition.detail !== undefined ? ` — ${transition.detail}` : \"\";\n\t\t\t\tconst code = transitionCodeColor(transition.code)(transition.code);\n\t\t\t\trows.push({\n\t\t\t\t\ttext: ` #${transition.revision} ${transition.workflowId}${stage} ${transition.from} -> ${transition.to} [${transition.trigger}] ${code}: ${transition.message}${detail}`,\n\t\t\t\t\tstage: undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn rows;\n\t\t}\n\n\t\tconst blocks = model.panorama;\n\t\tif (blocks === undefined) {\n\t\t\trows.push({ text: ` ${t(\"no workflow.state entry in this session\")}`, stage: undefined });\n\t\t\treturn rows;\n\t\t}\n\t\tif (blocks.length === 0) {\n\t\t\trows.push({\n\t\t\t\ttext: ` ${t(\"no workflows in this session; create one with workflow_set\")}`,\n\t\t\t\tstage: undefined,\n\t\t\t});\n\t\t\treturn rows;\n\t\t}\n\t\tfor (const block of blocks) {\n\t\t\tconst status = workflowStatusColor(block.status)(block.status);\n\t\t\trows.push({\n\t\t\t\ttext: ` ${t(\n\t\t\t\t\t'workflow \"{title}\" ({workflowId}) — {status} · revision {revision} · active {activeCount}/{maxActiveStages} · retreats {retreatCount}/{maxRetreats}',\n\t\t\t\t\t{\n\t\t\t\t\t\ttitle: block.title,\n\t\t\t\t\t\tworkflowId: block.workflowId,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t\trevision: block.revision,\n\t\t\t\t\t\tactiveCount: block.activeCount,\n\t\t\t\t\t\tmaxActiveStages: block.maxActiveStages,\n\t\t\t\t\t\tretreatCount: block.retreatCount,\n\t\t\t\t\t\tmaxRetreats: block.maxRetreats,\n\t\t\t\t\t},\n\t\t\t\t)}`,\n\t\t\t\tstage: undefined,\n\t\t\t});\n\t\t\tif (block.goalId !== undefined) {\n\t\t\t\trows.push({ text: ` ${t(\"goal: {goalId}\", { goalId: block.goalId })}`, stage: undefined });\n\t\t\t}\n\t\t\tfor (const stage of block.stages) {\n\t\t\t\trows.push({\n\t\t\t\t\ttext: this.formatStageRow(stage),\n\t\t\t\t\tstage: { workflowId: block.workflowId, stageId: stage.stageId },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (block.diagnostics.length > 0) {\n\t\t\t\trows.push({ text: ` ${t(\"diagnostics:\")}`, stage: undefined });\n\t\t\t\tfor (const diagnostic of block.diagnostics) {\n\t\t\t\t\trows.push({ text: theme.fg(\"warning\", ` - ${diagnostic}`), stage: undefined });\n\t\t\t\t}\n\t\t\t}\n\t\t\trows.push({ text: \"\", stage: undefined });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate formatStageRow(stage: WorkflowStageRow): string {\n\t\tconst pad = \" \".repeat(stage.depth + 1);\n\t\tif (stage.backReference) {\n\t\t\treturn `${pad} -> ${stage.stageId} ${t(\"(shown above)\")}`;\n\t\t}\n\t\tconst bits = [`- ${stage.stageId} [${stageStatusColor(stage.status)(stage.status)}] ${stage.title}`];\n\t\tif (stage.waitingOn !== null) {\n\t\t\tbits.push(theme.fg(\"dim\", `— ${t(\"waiting: {condition}\", { condition: stage.waitingOn })}`));\n\t\t}\n\t\tif (stage.attempts > 0) bits.push(theme.fg(\"dim\", t(\"· attempts {count}\", { count: stage.attempts })));\n\t\tif (stage.evidenceCount > 0) {\n\t\t\tbits.push(theme.fg(\"dim\", t(\"· evidence {count}\", { count: stage.evidenceCount })));\n\t\t}\n\t\tif (stage.scopeConflict !== null) {\n\t\t\tbits.push(theme.fg(\"warning\", `⚠ ${t(\"scope:{conflict}\", { conflict: stage.scopeConflict })}`));\n\t\t}\n\t\treturn `${pad}${bits.join(\" \")}`;\n\t}\n\n\t/** Rows are rebuilt lazily on access; the key couples rebuild + selection restore. */\n\tprivate syncRows(): void {\n\t\tconst model = this.getModel();\n\t\tconst previous = this.rows[this.selectedIndex]?.stage;\n\t\tthis.rows = this.buildRows(model);\n\t\tif (previous !== undefined) {\n\t\t\tconst restored = this.rows.findIndex((row) => row.stage?.stageId === previous.stageId);\n\t\t\tif (restored !== -1) this.selectedIndex = restored;\n\t\t}\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row.text}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this final\n\t\t// indicator row), the same contract as agents-view renderRows: the\n\t\t// overlay's grid footprint must not change with mode switches or row\n\t\t// counts, or the chat/editor layout boundary moves between frames.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate flash(message: string): void {\n\t\tthis.flashText.setText(theme.fg(\"warning\", ` ${message}`));\n\t\tif (this.flashTimeout !== null) clearTimeout(this.flashTimeout);\n\t\tthis.flashTimeout = setTimeout(() => {\n\t\t\tthis.flashText.setText(\"\");\n\t\t\tthis.flashTimeout = null;\n\t\t\tthis.config.requestRender?.();\n\t\t}, 2500);\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate toggleMode(): void {\n\t\tthis.mode = this.mode === \"panorama\" ? \"log\" : \"panorama\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate forward(action: WorkflowForwardAction): void {\n\t\tconst selected = this.rows[this.selectedIndex];\n\t\tif (selected?.stage === undefined) {\n\t\t\tif (action === \"cancel\") {\n\t\t\t\tconst workflowId = this.getModel().activeWorkflowId;\n\t\t\t\tif (workflowId === undefined) {\n\t\t\t\t\tthis.flash(t(\"No workflow to cancel\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onForwardAction?.(buildWorkflowActionText(action, workflowId, undefined));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.flash(t(\"Select a stage row first\"));\n\t\t\treturn;\n\t\t}\n\t\tthis.onForwardAction?.(buildWorkflowActionText(action, selected.stage.workflowId, selected.stage.stageId));\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tthis.toggleMode();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t} else if (keyData === \"a\") {\n\t\t\tthis.forward(\"approve\");\n\t\t} else if (keyData === \"r\") {\n\t\t\tthis.forward(\"reject\");\n\t\t} else if (keyData === \"s\") {\n\t\t\tthis.forward(\"skip\");\n\t\t} else if (keyData === \"c\") {\n\t\t\tthis.forward(\"cancel\");\n\t\t}\n\t}\n}\n"]}
@@ -15,6 +15,7 @@
15
15
  * stay separated (设计 §9 L2 "转发到对话").
16
16
  */
17
17
  import { Container, getKeybindings, Text, truncateToWidth } from "@agent-forge/tui";
18
+ import { t } from "../../../core/i18n/index.js";
18
19
  import { theme } from "../theme/theme.js";
19
20
  import { DynamicBorder } from "./dynamic-border.js";
20
21
  import { keyHint, rawKeyHint } from "./keybinding-hints.js";
@@ -396,7 +397,7 @@ export class WorkflowViewComponent extends Container {
396
397
  constructor(config) {
397
398
  super();
398
399
  this.config = config;
399
- this.titleText = new Text(theme.fg("accent", theme.bold(" Workflow Overview")), 1, 0);
400
+ this.titleText = new Text(theme.fg("accent", theme.bold(` ${t("Workflow Overview")}`)), 1, 0);
400
401
  this.modeHintText = new Text("", 1, 0);
401
402
  this.helpText = new Text("", 1, 0);
402
403
  this.flashText = new Text("", 1, 0);
@@ -416,19 +417,19 @@ export class WorkflowViewComponent extends Container {
416
417
  }
417
418
  }
418
419
  updateModeTexts() {
419
- const label = this.mode === "panorama" ? "panorama" : "transition log (newest first)";
420
+ const label = this.mode === "panorama" ? t("panorama") : t("transition log (newest first)");
420
421
  this.modeHintText.setText(theme.fg("dim", ` ${label}`));
421
422
  this.helpText.setText(this.buildHelpLine());
422
423
  }
423
424
  buildHelpLine() {
424
- const parts = [rawKeyHint("↑↓", "move")];
425
+ const parts = [rawKeyHint("↑↓", t("move"))];
425
426
  if (this.mode === "panorama") {
426
- parts.push(rawKeyHint("tab/l", "log"), rawKeyHint("a", "approve"), rawKeyHint("r", "reject"), rawKeyHint("s", "skip"), rawKeyHint("c", "cancel"));
427
+ parts.push(rawKeyHint("tab/l", t("log")), rawKeyHint("a", t("approve")), rawKeyHint("r", t("reject")), rawKeyHint("s", t("skip")), rawKeyHint("c", t("cancel")));
427
428
  }
428
429
  else {
429
- parts.push(rawKeyHint("tab/l", "panorama"));
430
+ parts.push(rawKeyHint("tab/l", t("panorama")));
430
431
  }
431
- parts.push(keyHint("tui.select.cancel", "close"));
432
+ parts.push(keyHint("tui.select.cancel", t("close")));
432
433
  return ` ${parts.join(" ")}`;
433
434
  }
434
435
  getModel() {
@@ -444,7 +445,7 @@ export class WorkflowViewComponent extends Container {
444
445
  const rows = [];
445
446
  if (this.mode === "log") {
446
447
  if (model.transitions.length === 0) {
447
- rows.push({ text: " no workflow transitions recorded", stage: undefined });
448
+ rows.push({ text: ` ${t("no workflow transitions recorded")}`, stage: undefined });
448
449
  return rows;
449
450
  }
450
451
  for (const transition of model.transitions) {
@@ -460,21 +461,33 @@ export class WorkflowViewComponent extends Container {
460
461
  }
461
462
  const blocks = model.panorama;
462
463
  if (blocks === undefined) {
463
- rows.push({ text: " no workflow.state entry in this session", stage: undefined });
464
+ rows.push({ text: ` ${t("no workflow.state entry in this session")}`, stage: undefined });
464
465
  return rows;
465
466
  }
466
467
  if (blocks.length === 0) {
467
- rows.push({ text: " no workflows in this session; create one with workflow_set", stage: undefined });
468
+ rows.push({
469
+ text: ` ${t("no workflows in this session; create one with workflow_set")}`,
470
+ stage: undefined,
471
+ });
468
472
  return rows;
469
473
  }
470
474
  for (const block of blocks) {
471
475
  const status = workflowStatusColor(block.status)(block.status);
472
476
  rows.push({
473
- text: ` workflow "${block.title}" (${block.workflowId}) — ${status} · revision ${block.revision} · active ${block.activeCount}/${block.maxActiveStages} · retreats ${block.retreatCount}/${block.maxRetreats}`,
477
+ text: ` ${t('workflow "{title}" ({workflowId}) — {status} · revision {revision} · active {activeCount}/{maxActiveStages} · retreats {retreatCount}/{maxRetreats}', {
478
+ title: block.title,
479
+ workflowId: block.workflowId,
480
+ status,
481
+ revision: block.revision,
482
+ activeCount: block.activeCount,
483
+ maxActiveStages: block.maxActiveStages,
484
+ retreatCount: block.retreatCount,
485
+ maxRetreats: block.maxRetreats,
486
+ })}`,
474
487
  stage: undefined,
475
488
  });
476
489
  if (block.goalId !== undefined) {
477
- rows.push({ text: ` goal: ${block.goalId}`, stage: undefined });
490
+ rows.push({ text: ` ${t("goal: {goalId}", { goalId: block.goalId })}`, stage: undefined });
478
491
  }
479
492
  for (const stage of block.stages) {
480
493
  rows.push({
@@ -483,7 +496,7 @@ export class WorkflowViewComponent extends Container {
483
496
  });
484
497
  }
485
498
  if (block.diagnostics.length > 0) {
486
- rows.push({ text: " diagnostics:", stage: undefined });
499
+ rows.push({ text: ` ${t("diagnostics:")}`, stage: undefined });
487
500
  for (const diagnostic of block.diagnostics) {
488
501
  rows.push({ text: theme.fg("warning", ` - ${diagnostic}`), stage: undefined });
489
502
  }
@@ -495,17 +508,19 @@ export class WorkflowViewComponent extends Container {
495
508
  formatStageRow(stage) {
496
509
  const pad = " ".repeat(stage.depth + 1);
497
510
  if (stage.backReference) {
498
- return `${pad} -> ${stage.stageId} (shown above)`;
511
+ return `${pad} -> ${stage.stageId} ${t("(shown above)")}`;
499
512
  }
500
513
  const bits = [`- ${stage.stageId} [${stageStatusColor(stage.status)(stage.status)}] ${stage.title}`];
501
- if (stage.waitingOn !== null)
502
- bits.push(theme.fg("dim", `— waiting: ${stage.waitingOn}`));
514
+ if (stage.waitingOn !== null) {
515
+ bits.push(theme.fg("dim", `— ${t("waiting: {condition}", { condition: stage.waitingOn })}`));
516
+ }
503
517
  if (stage.attempts > 0)
504
- bits.push(theme.fg("dim", `· attempts ${stage.attempts}`));
505
- if (stage.evidenceCount > 0)
506
- bits.push(theme.fg("dim", `· evidence ${stage.evidenceCount}`));
518
+ bits.push(theme.fg("dim", t("· attempts {count}", { count: stage.attempts })));
519
+ if (stage.evidenceCount > 0) {
520
+ bits.push(theme.fg("dim", t("· evidence {count}", { count: stage.evidenceCount })));
521
+ }
507
522
  if (stage.scopeConflict !== null) {
508
- bits.push(theme.fg("warning", `⚠ scope:${stage.scopeConflict}`));
523
+ bits.push(theme.fg("warning", `⚠ ${t("scope:{conflict}", { conflict: stage.scopeConflict })}`));
509
524
  }
510
525
  return `${pad}${bits.join(" ")}`;
511
526
  }
@@ -590,13 +605,13 @@ export class WorkflowViewComponent extends Container {
590
605
  if (action === "cancel") {
591
606
  const workflowId = this.getModel().activeWorkflowId;
592
607
  if (workflowId === undefined) {
593
- this.flash("No workflow to cancel");
608
+ this.flash(t("No workflow to cancel"));
594
609
  return;
595
610
  }
596
611
  this.onForwardAction?.(buildWorkflowActionText(action, workflowId, undefined));
597
612
  return;
598
613
  }
599
- this.flash("Select a stage row first");
614
+ this.flash(t("Select a stage row first"));
600
615
  return;
601
616
  }
602
617
  this.onForwardAction?.(buildWorkflowActionText(action, selected.stage.workflowId, selected.stage.stageId));