@provos/ironcurtain 0.9.1 → 0.11.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 (502) hide show
  1. package/README.md +69 -10
  2. package/dist/auth/oauth-provider.js +1 -4
  3. package/dist/auth/oauth-provider.js.map +1 -1
  4. package/dist/cli.js +40 -2
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/config-command.js +174 -10
  7. package/dist/config/config-command.js.map +1 -1
  8. package/dist/config/first-start.js +61 -0
  9. package/dist/config/first-start.js.map +1 -1
  10. package/dist/config/generated/compiled-policy.json +528 -161
  11. package/dist/config/generated/test-scenarios.json +4810 -170
  12. package/dist/config/generated/tool-annotations.json +34 -47
  13. package/dist/config/index.d.ts +58 -0
  14. package/dist/config/index.js +97 -15
  15. package/dist/config/index.js.map +1 -1
  16. package/dist/config/mcp-servers.json +2 -2
  17. package/dist/config/model-provider.d.ts +8 -2
  18. package/dist/config/model-provider.js +52 -9
  19. package/dist/config/model-provider.js.map +1 -1
  20. package/dist/config/paths.d.ts +181 -0
  21. package/dist/config/paths.js +326 -23
  22. package/dist/config/paths.js.map +1 -1
  23. package/dist/config/types.d.ts +7 -1
  24. package/dist/config/user-config.d.ts +61 -4
  25. package/dist/config/user-config.js +108 -21
  26. package/dist/config/user-config.js.map +1 -1
  27. package/dist/config/validate-policy-dir.d.ts +10 -0
  28. package/dist/config/validate-policy-dir.js +59 -0
  29. package/dist/config/validate-policy-dir.js.map +1 -0
  30. package/dist/cron/compile-task-policy.js +1 -0
  31. package/dist/cron/compile-task-policy.js.map +1 -1
  32. package/dist/cron/job-commands.js +22 -2
  33. package/dist/cron/job-commands.js.map +1 -1
  34. package/dist/cron/types.d.ts +16 -2
  35. package/dist/cron/types.js +1 -3
  36. package/dist/cron/types.js.map +1 -1
  37. package/dist/daemon/daemon-command.js +16 -2
  38. package/dist/daemon/daemon-command.js.map +1 -1
  39. package/dist/daemon/ironcurtain-daemon.d.ts +44 -1
  40. package/dist/daemon/ironcurtain-daemon.js +210 -8
  41. package/dist/daemon/ironcurtain-daemon.js.map +1 -1
  42. package/dist/docker/adapters/claude-code.d.ts +2 -1
  43. package/dist/docker/adapters/claude-code.js +320 -131
  44. package/dist/docker/adapters/claude-code.js.map +1 -1
  45. package/dist/docker/adapters/goose.d.ts +12 -11
  46. package/dist/docker/adapters/goose.js +80 -27
  47. package/dist/docker/adapters/goose.js.map +1 -1
  48. package/dist/docker/agent-adapter.d.ts +178 -4
  49. package/dist/docker/agent-adapter.js +14 -0
  50. package/dist/docker/agent-adapter.js.map +1 -1
  51. package/dist/docker/agent-registry.js +3 -2
  52. package/dist/docker/agent-registry.js.map +1 -1
  53. package/dist/docker/code-mode-proxy.d.ts +27 -0
  54. package/dist/docker/code-mode-proxy.js +3 -0
  55. package/dist/docker/code-mode-proxy.js.map +1 -1
  56. package/dist/docker/container-lifecycle.d.ts +15 -0
  57. package/dist/docker/container-lifecycle.js +32 -0
  58. package/dist/docker/container-lifecycle.js.map +1 -0
  59. package/dist/docker/docker-agent-session.d.ts +113 -62
  60. package/dist/docker/docker-agent-session.js +241 -300
  61. package/dist/docker/docker-agent-session.js.map +1 -1
  62. package/dist/docker/docker-infrastructure.d.ts +256 -21
  63. package/dist/docker/docker-infrastructure.js +585 -30
  64. package/dist/docker/docker-infrastructure.js.map +1 -1
  65. package/dist/docker/docker-manager.d.ts +36 -1
  66. package/dist/docker/docker-manager.js +168 -26
  67. package/dist/docker/docker-manager.js.map +1 -1
  68. package/dist/docker/docker-progress-sink.d.ts +43 -0
  69. package/dist/docker/docker-progress-sink.js +299 -0
  70. package/dist/docker/docker-progress-sink.js.map +1 -0
  71. package/dist/docker/mitm-proxy.d.ts +90 -1
  72. package/dist/docker/mitm-proxy.js +720 -40
  73. package/dist/docker/mitm-proxy.js.map +1 -1
  74. package/dist/docker/oauth-credentials.d.ts +46 -3
  75. package/dist/docker/oauth-credentials.js +56 -14
  76. package/dist/docker/oauth-credentials.js.map +1 -1
  77. package/dist/docker/oauth-token-manager.js +2 -2
  78. package/dist/docker/oauth-token-manager.js.map +1 -1
  79. package/dist/docker/orientation.d.ts +1 -1
  80. package/dist/docker/provider-config.d.ts +81 -2
  81. package/dist/docker/provider-config.js +222 -28
  82. package/dist/docker/provider-config.js.map +1 -1
  83. package/dist/docker/proxy-tools.d.ts +0 -2
  84. package/dist/docker/proxy-tools.js +2 -7
  85. package/dist/docker/proxy-tools.js.map +1 -1
  86. package/dist/docker/pty-session.d.ts +49 -1
  87. package/dist/docker/pty-session.js +212 -90
  88. package/dist/docker/pty-session.js.map +1 -1
  89. package/dist/docker/pty-types.d.ts +0 -2
  90. package/dist/docker/pty-types.js +0 -2
  91. package/dist/docker/pty-types.js.map +1 -1
  92. package/dist/docker/resource-limits.d.ts +125 -0
  93. package/dist/docker/resource-limits.js +200 -0
  94. package/dist/docker/resource-limits.js.map +1 -0
  95. package/dist/docker/spawn-with-idle-timeout.d.ts +39 -0
  96. package/dist/docker/spawn-with-idle-timeout.js +152 -0
  97. package/dist/docker/spawn-with-idle-timeout.js.map +1 -0
  98. package/dist/docker/sse-extractor.d.ts +51 -0
  99. package/dist/docker/sse-extractor.js +303 -0
  100. package/dist/docker/sse-extractor.js.map +1 -0
  101. package/dist/docker/token-stream-bus.d.ts +83 -0
  102. package/dist/docker/token-stream-bus.js +98 -0
  103. package/dist/docker/token-stream-bus.js.map +1 -0
  104. package/dist/docker/token-stream-types.d.ts +71 -0
  105. package/dist/docker/token-stream-types.js +8 -0
  106. package/dist/docker/token-stream-types.js.map +1 -0
  107. package/dist/docker/types.d.ts +61 -6
  108. package/dist/doctor/checks.d.ts +138 -0
  109. package/dist/doctor/checks.js +511 -0
  110. package/dist/doctor/checks.js.map +1 -0
  111. package/dist/doctor/doctor-command.d.ts +29 -0
  112. package/dist/doctor/doctor-command.js +160 -0
  113. package/dist/doctor/doctor-command.js.map +1 -0
  114. package/dist/doctor/mcp-liveness.d.ts +28 -0
  115. package/dist/doctor/mcp-liveness.js +84 -0
  116. package/dist/doctor/mcp-liveness.js.map +1 -0
  117. package/dist/doctor/oauth-checks.d.ts +23 -0
  118. package/dist/doctor/oauth-checks.js +157 -0
  119. package/dist/doctor/oauth-checks.js.map +1 -0
  120. package/dist/doctor/output.d.ts +26 -0
  121. package/dist/doctor/output.js +82 -0
  122. package/dist/doctor/output.js.map +1 -0
  123. package/dist/escalation/listener-command.js +0 -3
  124. package/dist/escalation/listener-command.js.map +1 -1
  125. package/dist/event-bus/typed-event-bus.d.ts +26 -0
  126. package/dist/event-bus/typed-event-bus.js +35 -0
  127. package/dist/event-bus/typed-event-bus.js.map +1 -0
  128. package/dist/index.js +32 -9
  129. package/dist/index.js.map +1 -1
  130. package/dist/logger.js +31 -2
  131. package/dist/logger.js.map +1 -1
  132. package/dist/memory/auto-save.d.ts +18 -4
  133. package/dist/memory/auto-save.js +46 -6
  134. package/dist/memory/auto-save.js.map +1 -1
  135. package/dist/memory/memory-policy.d.ts +41 -0
  136. package/dist/memory/memory-policy.js +36 -0
  137. package/dist/memory/memory-policy.js.map +1 -0
  138. package/dist/mux/mux-app.d.ts +2 -0
  139. package/dist/mux/mux-app.js +30 -34
  140. package/dist/mux/mux-app.js.map +1 -1
  141. package/dist/mux/mux-command.d.ts +10 -1
  142. package/dist/mux/mux-command.js +62 -35
  143. package/dist/mux/mux-command.js.map +1 -1
  144. package/dist/mux/mux-renderer.js +22 -17
  145. package/dist/mux/mux-renderer.js.map +1 -1
  146. package/dist/mux/pty-bridge.d.ts +2 -0
  147. package/dist/mux/pty-bridge.js +3 -0
  148. package/dist/mux/pty-bridge.js.map +1 -1
  149. package/dist/mux/session-scanner.d.ts +7 -0
  150. package/dist/mux/session-scanner.js +21 -2
  151. package/dist/mux/session-scanner.js.map +1 -1
  152. package/dist/mux/types.d.ts +0 -4
  153. package/dist/mux/types.js.map +1 -1
  154. package/dist/{pipeline → observability}/llm-logger.d.ts +9 -3
  155. package/dist/{pipeline → observability}/llm-logger.js +16 -4
  156. package/dist/observability/llm-logger.js.map +1 -0
  157. package/dist/observe/observe-command.d.ts +12 -0
  158. package/dist/observe/observe-command.js +298 -0
  159. package/dist/observe/observe-command.js.map +1 -0
  160. package/dist/observe/observe-renderer.d.ts +24 -0
  161. package/dist/observe/observe-renderer.js +87 -0
  162. package/dist/observe/observe-renderer.js.map +1 -0
  163. package/dist/observe/observe-tui-rain.d.ts +42 -0
  164. package/dist/observe/observe-tui-rain.js +531 -0
  165. package/dist/observe/observe-tui-rain.js.map +1 -0
  166. package/dist/observe/observe-tui-text-panel.d.ts +46 -0
  167. package/dist/observe/observe-tui-text-panel.js +525 -0
  168. package/dist/observe/observe-tui-text-panel.js.map +1 -0
  169. package/dist/observe/observe-tui-types.d.ts +270 -0
  170. package/dist/observe/observe-tui-types.js +200 -0
  171. package/dist/observe/observe-tui-types.js.map +1 -0
  172. package/dist/observe/observe-tui-word-scorer.d.ts +143 -0
  173. package/dist/observe/observe-tui-word-scorer.js +572 -0
  174. package/dist/observe/observe-tui-word-scorer.js.map +1 -0
  175. package/dist/observe/observe-tui.d.ts +59 -0
  176. package/dist/observe/observe-tui.js +592 -0
  177. package/dist/observe/observe-tui.js.map +1 -0
  178. package/dist/persona/compile-persona-policy.js +1 -0
  179. package/dist/persona/compile-persona-policy.js.map +1 -1
  180. package/dist/persona/memory-gate.d.ts +19 -0
  181. package/dist/persona/memory-gate.js +33 -0
  182. package/dist/persona/memory-gate.js.map +1 -0
  183. package/dist/persona/persona-command.js +41 -6
  184. package/dist/persona/persona-command.js.map +1 -1
  185. package/dist/persona/resolve.d.ts +22 -0
  186. package/dist/persona/resolve.js +45 -2
  187. package/dist/persona/resolve.js.map +1 -1
  188. package/dist/persona/types.d.ts +16 -0
  189. package/dist/pipeline/annotate.d.ts +7 -1
  190. package/dist/pipeline/annotate.js +92 -2
  191. package/dist/pipeline/annotate.js.map +1 -1
  192. package/dist/pipeline/compile.js +2 -0
  193. package/dist/pipeline/compile.js.map +1 -1
  194. package/dist/pipeline/constitution-compiler.d.ts +25 -14
  195. package/dist/pipeline/constitution-compiler.js +107 -38
  196. package/dist/pipeline/constitution-compiler.js.map +1 -1
  197. package/dist/pipeline/dynamic-list-types.d.ts +3 -6
  198. package/dist/pipeline/dynamic-list-types.js +3 -16
  199. package/dist/pipeline/dynamic-list-types.js.map +1 -1
  200. package/dist/pipeline/parallel-progress.d.ts +59 -0
  201. package/dist/pipeline/parallel-progress.js +263 -0
  202. package/dist/pipeline/parallel-progress.js.map +1 -0
  203. package/dist/pipeline/pipeline-runner.d.ts +49 -8
  204. package/dist/pipeline/pipeline-runner.js +419 -231
  205. package/dist/pipeline/pipeline-runner.js.map +1 -1
  206. package/dist/pipeline/pipeline-shared.d.ts +59 -1
  207. package/dist/pipeline/pipeline-shared.js +127 -12
  208. package/dist/pipeline/pipeline-shared.js.map +1 -1
  209. package/dist/pipeline/policy-verifier.js +16 -3
  210. package/dist/pipeline/policy-verifier.js.map +1 -1
  211. package/dist/pipeline/proxy-mcp-connections.js +17 -2
  212. package/dist/pipeline/proxy-mcp-connections.js.map +1 -1
  213. package/dist/pipeline/scenario-generator.d.ts +4 -8
  214. package/dist/pipeline/scenario-generator.js +13 -46
  215. package/dist/pipeline/scenario-generator.js.map +1 -1
  216. package/dist/pipeline/server-prefilter.d.ts +31 -0
  217. package/dist/pipeline/server-prefilter.js +115 -0
  218. package/dist/pipeline/server-prefilter.js.map +1 -0
  219. package/dist/pipeline/types.d.ts +5 -0
  220. package/dist/sandbox/index.d.ts +14 -0
  221. package/dist/sandbox/index.js +335 -116
  222. package/dist/sandbox/index.js.map +1 -1
  223. package/dist/sandbox/ironcurtain-protocol.d.ts +52 -0
  224. package/dist/sandbox/ironcurtain-protocol.js +185 -0
  225. package/dist/sandbox/ironcurtain-protocol.js.map +1 -0
  226. package/dist/session/agent-session.d.ts +6 -0
  227. package/dist/session/agent-session.js +16 -5
  228. package/dist/session/agent-session.js.map +1 -1
  229. package/dist/session/cli-transport.js +0 -6
  230. package/dist/session/cli-transport.js.map +1 -1
  231. package/dist/session/index.d.ts +35 -14
  232. package/dist/session/index.js +324 -130
  233. package/dist/session/index.js.map +1 -1
  234. package/dist/session/preflight.d.ts +50 -13
  235. package/dist/session/preflight.js +252 -80
  236. package/dist/session/preflight.js.map +1 -1
  237. package/dist/session/prompts.d.ts +2 -5
  238. package/dist/session/prompts.js.map +1 -1
  239. package/dist/session/session-manager.d.ts +61 -6
  240. package/dist/session/session-manager.js +72 -10
  241. package/dist/session/session-manager.js.map +1 -1
  242. package/dist/session/session-metadata.d.ts +21 -5
  243. package/dist/session/session-metadata.js +34 -12
  244. package/dist/session/session-metadata.js.map +1 -1
  245. package/dist/session/types.d.ts +311 -5
  246. package/dist/session/types.js +57 -1
  247. package/dist/session/types.js.map +1 -1
  248. package/dist/signal/setup-signal.js +13 -21
  249. package/dist/signal/setup-signal.js.map +1 -1
  250. package/dist/signal/signal-bot-daemon.d.ts +16 -1
  251. package/dist/signal/signal-bot-daemon.js +39 -27
  252. package/dist/signal/signal-bot-daemon.js.map +1 -1
  253. package/dist/signal/signal-container.js +7 -1
  254. package/dist/signal/signal-container.js.map +1 -1
  255. package/dist/skills/discovery.d.ts +77 -0
  256. package/dist/skills/discovery.js +206 -0
  257. package/dist/skills/discovery.js.map +1 -0
  258. package/dist/skills/index.d.ts +4 -0
  259. package/dist/skills/index.js +3 -0
  260. package/dist/skills/index.js.map +1 -0
  261. package/dist/skills/staging.d.ts +28 -0
  262. package/dist/skills/staging.js +68 -0
  263. package/dist/skills/staging.js.map +1 -0
  264. package/dist/skills/types.d.ts +46 -0
  265. package/dist/skills/types.js +2 -0
  266. package/dist/skills/types.js.map +1 -0
  267. package/dist/trusted-process/approval-whitelist.d.ts +0 -2
  268. package/dist/trusted-process/approval-whitelist.js +17 -17
  269. package/dist/trusted-process/approval-whitelist.js.map +1 -1
  270. package/dist/trusted-process/async-mutex.d.ts +32 -0
  271. package/dist/trusted-process/async-mutex.js +50 -0
  272. package/dist/trusted-process/async-mutex.js.map +1 -0
  273. package/dist/trusted-process/audit-log.d.ts +38 -1
  274. package/dist/trusted-process/audit-log.js +82 -13
  275. package/dist/trusted-process/audit-log.js.map +1 -1
  276. package/dist/trusted-process/call-circuit-breaker.js +2 -1
  277. package/dist/trusted-process/call-circuit-breaker.js.map +1 -1
  278. package/dist/trusted-process/control-server.d.ts +101 -0
  279. package/dist/trusted-process/control-server.js +282 -0
  280. package/dist/trusted-process/control-server.js.map +1 -0
  281. package/dist/trusted-process/domain-utils.d.ts +6 -6
  282. package/dist/trusted-process/domain-utils.js +7 -23
  283. package/dist/trusted-process/domain-utils.js.map +1 -1
  284. package/dist/trusted-process/error-prefixes.d.ts +16 -0
  285. package/dist/trusted-process/error-prefixes.js +17 -0
  286. package/dist/trusted-process/error-prefixes.js.map +1 -0
  287. package/dist/trusted-process/index.d.ts +40 -23
  288. package/dist/trusted-process/index.js +131 -225
  289. package/dist/trusted-process/index.js.map +1 -1
  290. package/dist/trusted-process/list-matcher.d.ts +17 -0
  291. package/dist/trusted-process/list-matcher.js +31 -0
  292. package/dist/trusted-process/list-matcher.js.map +1 -0
  293. package/dist/trusted-process/mcp-client-manager.d.ts +35 -6
  294. package/dist/trusted-process/mcp-client-manager.js +40 -45
  295. package/dist/trusted-process/mcp-client-manager.js.map +1 -1
  296. package/dist/trusted-process/mcp-proxy-server.d.ts +31 -120
  297. package/dist/trusted-process/mcp-proxy-server.js +166 -657
  298. package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
  299. package/dist/trusted-process/policy-engine.d.ts +16 -4
  300. package/dist/trusted-process/policy-engine.js +90 -45
  301. package/dist/trusted-process/policy-engine.js.map +1 -1
  302. package/dist/trusted-process/policy-roots.d.ts +6 -0
  303. package/dist/trusted-process/policy-roots.js +20 -0
  304. package/dist/trusted-process/policy-roots.js.map +1 -1
  305. package/dist/trusted-process/sandbox-integration.d.ts +12 -0
  306. package/dist/trusted-process/sandbox-integration.js +26 -0
  307. package/dist/trusted-process/sandbox-integration.js.map +1 -1
  308. package/dist/trusted-process/tool-call-coordinator.d.ts +269 -0
  309. package/dist/trusted-process/tool-call-coordinator.js +508 -0
  310. package/dist/trusted-process/tool-call-coordinator.js.map +1 -0
  311. package/dist/trusted-process/tool-call-pipeline.d.ts +205 -0
  312. package/dist/trusted-process/tool-call-pipeline.js +798 -0
  313. package/dist/trusted-process/tool-call-pipeline.js.map +1 -0
  314. package/dist/trusted-process/tool-description-hints.d.ts +1 -1
  315. package/dist/types/argument-roles.d.ts +1 -1
  316. package/dist/types/argument-roles.js +14 -1
  317. package/dist/types/argument-roles.js.map +1 -1
  318. package/dist/types/audit.d.ts +9 -0
  319. package/dist/{session → types}/errors.d.ts +8 -2
  320. package/dist/{session → types}/errors.js +8 -2
  321. package/dist/types/errors.js.map +1 -0
  322. package/dist/types/reserved-servers.d.ts +11 -0
  323. package/dist/types/reserved-servers.js +12 -0
  324. package/dist/types/reserved-servers.js.map +1 -0
  325. package/dist/types/server-listing.d.ts +14 -0
  326. package/dist/types/server-listing.js +2 -0
  327. package/dist/types/server-listing.js.map +1 -0
  328. package/dist/types/slug.d.ts +2 -0
  329. package/dist/types/slug.js +2 -0
  330. package/dist/types/slug.js.map +1 -1
  331. package/dist/types/url-normalize.d.ts +16 -0
  332. package/dist/types/url-normalize.js +33 -0
  333. package/dist/types/url-normalize.js.map +1 -0
  334. package/dist/utils/error-message.d.ts +8 -0
  335. package/dist/utils/error-message.js +11 -0
  336. package/dist/utils/error-message.js.map +1 -0
  337. package/dist/utils/exec-error.d.ts +19 -0
  338. package/dist/utils/exec-error.js +16 -0
  339. package/dist/utils/exec-error.js.map +1 -0
  340. package/dist/utils/is-plain-object.d.ts +7 -0
  341. package/dist/utils/is-plain-object.js +12 -0
  342. package/dist/utils/is-plain-object.js.map +1 -0
  343. package/dist/utils/preflight-checks.d.ts +16 -0
  344. package/dist/utils/preflight-checks.js +178 -0
  345. package/dist/utils/preflight-checks.js.map +1 -0
  346. package/dist/web-ui/__tests__/json-rpc-dispatch.test.d.ts +7 -0
  347. package/dist/web-ui/__tests__/json-rpc-dispatch.test.js +725 -0
  348. package/dist/web-ui/__tests__/json-rpc-dispatch.test.js.map +1 -0
  349. package/dist/web-ui/dispatch/escalation-dispatch.d.ts +7 -0
  350. package/dist/web-ui/dispatch/escalation-dispatch.js +52 -0
  351. package/dist/web-ui/dispatch/escalation-dispatch.js.map +1 -0
  352. package/dist/web-ui/dispatch/job-dispatch.d.ts +8 -0
  353. package/dist/web-ui/dispatch/job-dispatch.js +83 -0
  354. package/dist/web-ui/dispatch/job-dispatch.js.map +1 -0
  355. package/dist/web-ui/dispatch/persona-dispatch.d.ts +6 -0
  356. package/dist/web-ui/dispatch/persona-dispatch.js +116 -0
  357. package/dist/web-ui/dispatch/persona-dispatch.js.map +1 -0
  358. package/dist/web-ui/dispatch/session-dispatch.d.ts +9 -0
  359. package/dist/web-ui/dispatch/session-dispatch.js +201 -0
  360. package/dist/web-ui/dispatch/session-dispatch.js.map +1 -0
  361. package/dist/web-ui/dispatch/token-stream-dispatch.d.ts +15 -0
  362. package/dist/web-ui/dispatch/token-stream-dispatch.js +55 -0
  363. package/dist/web-ui/dispatch/token-stream-dispatch.js.map +1 -0
  364. package/dist/web-ui/dispatch/types.d.ts +31 -0
  365. package/dist/web-ui/dispatch/types.js +68 -0
  366. package/dist/web-ui/dispatch/types.js.map +1 -0
  367. package/dist/web-ui/dispatch/workflow-dispatch.d.ts +103 -0
  368. package/dist/web-ui/dispatch/workflow-dispatch.js +925 -0
  369. package/dist/web-ui/dispatch/workflow-dispatch.js.map +1 -0
  370. package/dist/web-ui/json-rpc-dispatch.d.ts +12 -0
  371. package/dist/web-ui/json-rpc-dispatch.js +34 -0
  372. package/dist/web-ui/json-rpc-dispatch.js.map +1 -0
  373. package/dist/web-ui/state-graph.d.ts +13 -0
  374. package/dist/web-ui/state-graph.js +82 -0
  375. package/dist/web-ui/state-graph.js.map +1 -0
  376. package/dist/web-ui/token-stream-bridge.d.ts +76 -0
  377. package/dist/web-ui/token-stream-bridge.js +265 -0
  378. package/dist/web-ui/token-stream-bridge.js.map +1 -0
  379. package/dist/web-ui/web-event-bus.d.ts +152 -0
  380. package/dist/web-ui/web-event-bus.js +19 -0
  381. package/dist/web-ui/web-event-bus.js.map +1 -0
  382. package/dist/web-ui/web-session-transport.d.ts +31 -0
  383. package/dist/web-ui/web-session-transport.js +109 -0
  384. package/dist/web-ui/web-session-transport.js.map +1 -0
  385. package/dist/web-ui/web-ui-server.d.ts +76 -0
  386. package/dist/web-ui/web-ui-server.js +461 -0
  387. package/dist/web-ui/web-ui-server.js.map +1 -0
  388. package/dist/web-ui/web-ui-types.d.ts +290 -0
  389. package/dist/web-ui/web-ui-types.js +32 -0
  390. package/dist/web-ui/web-ui-types.js.map +1 -0
  391. package/dist/web-ui/ws-utils.d.ts +5 -0
  392. package/dist/web-ui/ws-utils.js +12 -0
  393. package/dist/web-ui/ws-utils.js.map +1 -0
  394. package/dist/web-ui-static/assets/index-BFO5z1js.js +76 -0
  395. package/dist/web-ui-static/assets/index-CCUwrkIL.css +1 -0
  396. package/dist/web-ui-static/assets/orbitron-latin-700-normal-4jsRXGGJ.woff2 +0 -0
  397. package/dist/web-ui-static/assets/orbitron-latin-700-normal-DmYOh-W9.woff +0 -0
  398. package/dist/web-ui-static/index.html +14 -0
  399. package/dist/workflow/artifacts.d.ts +59 -0
  400. package/dist/workflow/artifacts.js +188 -0
  401. package/dist/workflow/artifacts.js.map +1 -0
  402. package/dist/workflow/checkpoint-selection.d.ts +34 -0
  403. package/dist/workflow/checkpoint-selection.js +48 -0
  404. package/dist/workflow/checkpoint-selection.js.map +1 -0
  405. package/dist/workflow/checkpoint.d.ts +35 -0
  406. package/dist/workflow/checkpoint.js +84 -0
  407. package/dist/workflow/checkpoint.js.map +1 -0
  408. package/dist/workflow/cli-support.d.ts +92 -0
  409. package/dist/workflow/cli-support.js +423 -0
  410. package/dist/workflow/cli-support.js.map +1 -0
  411. package/dist/workflow/definition-loader.d.ts +32 -0
  412. package/dist/workflow/definition-loader.js +56 -0
  413. package/dist/workflow/definition-loader.js.map +1 -0
  414. package/dist/workflow/discovery.d.ts +78 -0
  415. package/dist/workflow/discovery.js +203 -0
  416. package/dist/workflow/discovery.js.map +1 -0
  417. package/dist/workflow/errors.d.ts +66 -0
  418. package/dist/workflow/errors.js +49 -0
  419. package/dist/workflow/errors.js.map +1 -0
  420. package/dist/workflow/guards.d.ts +8 -0
  421. package/dist/workflow/guards.js +38 -0
  422. package/dist/workflow/guards.js.map +1 -0
  423. package/dist/workflow/lint-integration.d.ts +64 -0
  424. package/dist/workflow/lint-integration.js +56 -0
  425. package/dist/workflow/lint-integration.js.map +1 -0
  426. package/dist/workflow/lint.d.ts +66 -0
  427. package/dist/workflow/lint.js +410 -0
  428. package/dist/workflow/lint.js.map +1 -0
  429. package/dist/workflow/machine-builder.d.ts +90 -0
  430. package/dist/workflow/machine-builder.js +485 -0
  431. package/dist/workflow/machine-builder.js.map +1 -0
  432. package/dist/workflow/message-log.d.ts +85 -0
  433. package/dist/workflow/message-log.js +40 -0
  434. package/dist/workflow/message-log.js.map +1 -0
  435. package/dist/workflow/orchestrator.d.ts +450 -0
  436. package/dist/workflow/orchestrator.js +1941 -0
  437. package/dist/workflow/orchestrator.js.map +1 -0
  438. package/dist/workflow/prompt-builder.d.ts +39 -0
  439. package/dist/workflow/prompt-builder.js +242 -0
  440. package/dist/workflow/prompt-builder.js.map +1 -0
  441. package/dist/workflow/run-state-command.d.ts +9 -0
  442. package/dist/workflow/run-state-command.js +414 -0
  443. package/dist/workflow/run-state-command.js.map +1 -0
  444. package/dist/workflow/run-state-debug-capture.d.ts +40 -0
  445. package/dist/workflow/run-state-debug-capture.js +101 -0
  446. package/dist/workflow/run-state-debug-capture.js.map +1 -0
  447. package/dist/workflow/status-parser.d.ts +68 -0
  448. package/dist/workflow/status-parser.js +259 -0
  449. package/dist/workflow/status-parser.js.map +1 -0
  450. package/dist/workflow/types.d.ts +498 -0
  451. package/dist/workflow/types.js +83 -0
  452. package/dist/workflow/types.js.map +1 -0
  453. package/dist/workflow/validate.d.ts +58 -0
  454. package/dist/workflow/validate.js +499 -0
  455. package/dist/workflow/validate.js.map +1 -0
  456. package/dist/workflow/workflow-command.d.ts +26 -0
  457. package/dist/workflow/workflow-command.js +648 -0
  458. package/dist/workflow/workflow-command.js.map +1 -0
  459. package/dist/workflow/workflow-discovery.d.ts +25 -0
  460. package/dist/workflow/workflow-discovery.js +100 -0
  461. package/dist/workflow/workflow-discovery.js.map +1 -0
  462. package/dist/workflow/workflow-manager.d.ts +122 -0
  463. package/dist/workflow/workflow-manager.js +308 -0
  464. package/dist/workflow/workflow-manager.js.map +1 -0
  465. package/dist/workflow/workflows/design-and-code/workflow.yaml +169 -0
  466. package/dist/workflow/workflows/test-email-summary/skills/email-formatting/SKILL.md +55 -0
  467. package/dist/workflow/workflows/test-email-summary/skills/gmail-query-syntax/SKILL.md +63 -0
  468. package/dist/workflow/workflows/test-email-summary/skills/json-schema-emails/SKILL.md +41 -0
  469. package/dist/workflow/workflows/test-email-summary/skills/json-schema-emails/schema.json +34 -0
  470. package/dist/workflow/workflows/test-email-summary/skills/summary-style-guide/SKILL.md +51 -0
  471. package/dist/workflow/workflows/test-email-summary/workflow.yaml +89 -0
  472. package/dist/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +201 -0
  473. package/dist/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +166 -0
  474. package/dist/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +185 -0
  475. package/dist/workflow/workflows/vuln-discovery/workflow.yaml +920 -0
  476. package/dist/workflow/worktree.d.ts +43 -0
  477. package/dist/workflow/worktree.js +106 -0
  478. package/dist/workflow/worktree.js.map +1 -0
  479. package/docker/Dockerfile.base +12 -1
  480. package/docker/Dockerfile.base.arm64 +17 -1
  481. package/docker/entrypoint-claude-code.sh +46 -0
  482. package/docker/entrypoint-goose.sh +25 -0
  483. package/package.json +22 -8
  484. package/packages/web-ui/README.md +113 -0
  485. package/packages/web-ui/docs/workflow-state-machine.png +0 -0
  486. package/src/config/generated/compiled-policy.json +528 -161
  487. package/src/config/generated/test-scenarios.json +4810 -170
  488. package/src/config/generated/tool-annotations.json +34 -47
  489. package/src/config/mcp-servers.json +2 -2
  490. package/src/workflow/workflows/design-and-code/workflow.yaml +169 -0
  491. package/src/workflow/workflows/test-email-summary/skills/email-formatting/SKILL.md +55 -0
  492. package/src/workflow/workflows/test-email-summary/skills/gmail-query-syntax/SKILL.md +63 -0
  493. package/src/workflow/workflows/test-email-summary/skills/json-schema-emails/SKILL.md +41 -0
  494. package/src/workflow/workflows/test-email-summary/skills/json-schema-emails/schema.json +34 -0
  495. package/src/workflow/workflows/test-email-summary/skills/summary-style-guide/SKILL.md +51 -0
  496. package/src/workflow/workflows/test-email-summary/workflow.yaml +89 -0
  497. package/src/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +201 -0
  498. package/src/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +166 -0
  499. package/src/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +185 -0
  500. package/src/workflow/workflows/vuln-discovery/workflow.yaml +920 -0
  501. package/dist/pipeline/llm-logger.js.map +0 -1
  502. package/dist/session/errors.js.map +0 -1
@@ -0,0 +1,648 @@
1
+ /**
2
+ * CLI entry point for `ironcurtain workflow`.
3
+ *
4
+ * Subcommands:
5
+ * start <definition> "task" [--model <model>] [--workspace <path>]
6
+ * resume <baseDir> [--state <stateName>] [--model <model>]
7
+ * inspect <baseDir> [--all]
8
+ */
9
+ import { existsSync, mkdirSync, readdirSync, statSync } from 'node:fs';
10
+ import { resolve } from 'node:path';
11
+ import { parseArgs } from 'node:util';
12
+ import { createInterface } from 'node:readline/promises';
13
+ import { getIronCurtainHome } from '../config/paths.js';
14
+ import { loadConfig } from '../config/index.js';
15
+ import { formatHelp } from '../cli-help.js';
16
+ import { FileCheckpointStore } from './checkpoint.js';
17
+ import { discoverWorkflows, resolveWorkflowPath, parseDefinitionFile } from './discovery.js';
18
+ import { discoverWorkflowRuns } from './workflow-discovery.js';
19
+ import { WorkflowManager } from './workflow-manager.js';
20
+ import { TypedEventBus } from '../event-bus/typed-event-bus.js';
21
+ import { countBySeverity, lintWorkflow } from './lint.js';
22
+ import { defaultLintContext, runPreflight } from './lint-integration.js';
23
+ import { loadDefinition } from './definition-loader.js';
24
+ import { MessageLog } from './message-log.js';
25
+ import { WorkflowOrchestrator } from './orchestrator.js';
26
+ import { createWorkflowSessionFactory, createConsoleTab, createGateHandler, printLifecycleEvent, printSummary, printResumeInfo, selectResumableWorkflow, synthesizeCheckpoint, runEventLoop, writeStdout, writeStderr, RED, BLUE, BOLD, DIM, MAGENTA, CYAN, YELLOW, RESET, } from './cli-support.js';
27
+ import { runRunState } from './run-state-command.js';
28
+ // ---------------------------------------------------------------------------
29
+ // Help specs
30
+ // ---------------------------------------------------------------------------
31
+ const workflowSpec = {
32
+ name: 'ironcurtain workflow',
33
+ description: 'Run multi-agent workflows',
34
+ usage: [
35
+ 'ironcurtain workflow list',
36
+ 'ironcurtain workflow start <name-or-path> "task" [--model <model>] [--workspace <path>] [--no-lint] [--strict-lint]',
37
+ 'ironcurtain workflow resume <baseDir> [--state <stateName>] [--model <model>] [--no-lint] [--strict-lint]',
38
+ 'ironcurtain workflow inspect <baseDir> [--all]',
39
+ 'ironcurtain workflow lint <name-or-path> [--strict]',
40
+ 'ironcurtain workflow run-state <name-or-path> <state> --artifacts <dir> [options]',
41
+ ],
42
+ subcommands: [
43
+ { name: 'list', description: 'List available workflow definitions' },
44
+ { name: 'start', description: 'Start a workflow by name or definition file path' },
45
+ { name: 'resume', description: 'Resume a checkpointed workflow' },
46
+ { name: 'inspect', description: 'Show workflow status, artifacts, and recent messages' },
47
+ { name: 'lint', description: 'Run semantic checks on a workflow definition' },
48
+ { name: 'run-state', description: 'Run a single agent state once against pre-staged artifacts' },
49
+ ],
50
+ options: [
51
+ { flag: 'model', description: 'Override the agent model (start, resume)', placeholder: '<model-id>' },
52
+ {
53
+ flag: 'workspace',
54
+ description: 'Use an existing directory as workspace (start only)',
55
+ placeholder: '<path>',
56
+ },
57
+ {
58
+ flag: 'state',
59
+ description: 'Synthesize checkpoint at this state (resume only)',
60
+ placeholder: '<name>',
61
+ },
62
+ { flag: 'all', description: 'Show full message log (inspect only)' },
63
+ { flag: 'no-lint', description: 'Skip pre-flight linting (start, resume)' },
64
+ { flag: 'strict-lint', description: 'Treat lint warnings as errors (start, resume)' },
65
+ { flag: 'strict', description: 'Treat lint warnings as errors (lint only)' },
66
+ { flag: 'help', short: 'h', description: 'Show this help message' },
67
+ ],
68
+ examples: [
69
+ 'ironcurtain workflow list',
70
+ 'ironcurtain workflow start design-and-code "Build a REST API"',
71
+ 'ironcurtain workflow start ./my-workflow.yaml "Build a REST API"',
72
+ 'ironcurtain workflow start design-and-code "task" --model anthropic:claude-haiku-4-5',
73
+ 'ironcurtain workflow resume /tmp/workflow-abc123',
74
+ 'ironcurtain workflow resume /tmp/workflow-abc123 --state review',
75
+ 'ironcurtain workflow resume /tmp/workflow-abc123 --model anthropic:claude-sonnet-4-6',
76
+ 'ironcurtain workflow inspect /tmp/workflow-abc123',
77
+ 'ironcurtain workflow inspect /tmp/workflow-abc123 --all',
78
+ ],
79
+ };
80
+ // ---------------------------------------------------------------------------
81
+ // Lint helpers
82
+ // ---------------------------------------------------------------------------
83
+ function formatDiagnostic(d) {
84
+ const sevColor = d.severity === 'error' ? RED : CYAN;
85
+ const location = d.stateId ? ` (state: ${d.stateId})` : '';
86
+ const lines = [`${DIM}[${d.code}]${RESET} ${sevColor}${d.severity}${RESET} ${d.message}${location}`];
87
+ if (d.hint)
88
+ lines.push(` ${DIM}hint: ${d.hint}${RESET}`);
89
+ return lines;
90
+ }
91
+ function printDiagnostics(diagnostics) {
92
+ for (const d of diagnostics) {
93
+ for (const line of formatDiagnostic(d))
94
+ writeStderr(line);
95
+ }
96
+ }
97
+ /**
98
+ * Loads + validates a workflow definition from a path via the shared
99
+ * {@link loadDefinition} helper. Prints CLI-formatted errors and exits on
100
+ * any failure (parse or validate). Validation errors take precedence over
101
+ * lint diagnostics.
102
+ */
103
+ function loadAndValidateDefinition(path) {
104
+ const result = loadDefinition(path);
105
+ if (result.ok)
106
+ return result.definition;
107
+ if (result.kind === 'validate' && result.issues) {
108
+ writeStderr(`${RED}Workflow validation failed:${RESET}`);
109
+ for (const issue of result.issues)
110
+ writeStderr(` ${RED}- ${issue}${RESET}`);
111
+ }
112
+ else {
113
+ writeStderr(`${RED}Failed to load workflow: ${result.message}${RESET}`);
114
+ }
115
+ process.exit(1);
116
+ }
117
+ /**
118
+ * Loads + lints a workflow definition file via the shared
119
+ * {@link runPreflight} helper. CLI-specific reporting: prints diagnostics
120
+ * to stderr and exits on any failure (load or lint). On success with
121
+ * warnings-only output, prints a short continue notice.
122
+ *
123
+ * Returns the loaded definition on success so callers can continue using it
124
+ * without re-parsing (start/resume have already routed through the same
125
+ * file before calling this).
126
+ */
127
+ export function runCliPreflightLint(definitionPath, mode) {
128
+ const result = runPreflight(definitionPath, mode);
129
+ if (result.ok) {
130
+ if (result.diagnostics.length > 0) {
131
+ printDiagnostics(result.diagnostics);
132
+ writeStderr(`${DIM}Lint: 0 errors, ${result.warnings} warning(s) — continuing.${RESET}`);
133
+ }
134
+ return result.definition;
135
+ }
136
+ if (result.kind === 'load') {
137
+ // Reuse `loadAndValidateDefinition`'s nicer per-issue formatting on
138
+ // validate failures by re-running it (cheap; reads the same file once
139
+ // more) — it owns the structured-issues bullet rendering. For parse
140
+ // failures it falls through and prints "Failed to load workflow:".
141
+ loadAndValidateDefinition(definitionPath);
142
+ // Unreachable: `loadAndValidateDefinition` always exits on failure.
143
+ process.exit(1);
144
+ }
145
+ // Lint failure (load succeeded). Match the previous output verbatim.
146
+ printDiagnostics(result.diagnostics);
147
+ writeStderr(`${RED}Lint failed: ${result.errors} error(s), ${result.warnings} warning(s).${RESET}`);
148
+ writeStderr(`${DIM}Rerun with --no-lint to bypass (not recommended).${RESET}`);
149
+ process.exit(1);
150
+ }
151
+ function resolveLintMode(noLint, strictLint) {
152
+ if (noLint === true)
153
+ return 'off';
154
+ if (strictLint === true)
155
+ return 'strict';
156
+ return 'warn';
157
+ }
158
+ export function parseArgsStrict(opts) {
159
+ try {
160
+ return parseArgs({ ...opts, strict: true });
161
+ }
162
+ catch (err) {
163
+ const message = err instanceof Error ? err.message : String(err);
164
+ writeStderr(`${RED}${message}${RESET}`);
165
+ writeStderr(`${DIM}Run with --help to see available options.${RESET}`);
166
+ process.exit(1);
167
+ }
168
+ }
169
+ // ---------------------------------------------------------------------------
170
+ // Subcommand implementations
171
+ // ---------------------------------------------------------------------------
172
+ async function runStart(args) {
173
+ const { values, positionals } = parseArgsStrict({
174
+ args,
175
+ options: {
176
+ model: { type: 'string' },
177
+ workspace: { type: 'string' },
178
+ 'no-lint': { type: 'boolean' },
179
+ 'strict-lint': { type: 'boolean' },
180
+ help: { type: 'boolean', short: 'h' },
181
+ },
182
+ allowPositionals: true,
183
+ });
184
+ if (values.help) {
185
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
186
+ return;
187
+ }
188
+ const definitionRef = positionals[0];
189
+ const taskDescription = positionals[1];
190
+ if (!definitionRef || !taskDescription) {
191
+ writeStderr(`${RED}Usage: ironcurtain workflow start <name-or-path> "task" [--model <model>]${RESET}`);
192
+ process.exit(1);
193
+ }
194
+ const resolvedDef = resolveWorkflowPath(definitionRef);
195
+ if (!resolvedDef) {
196
+ writeStderr(`${RED}Workflow not found: ${definitionRef}${RESET}`);
197
+ writeStderr(`${DIM}Looked in bundled and user workflow directories.${RESET}`);
198
+ writeStderr(`${DIM}Run 'ironcurtain workflow list' to see available workflows.${RESET}`);
199
+ process.exit(1);
200
+ }
201
+ // Pre-flight: validate + lint before any orchestrator side effects.
202
+ const lintMode = resolveLintMode(values['no-lint'], values['strict-lint']);
203
+ runCliPreflightLint(resolvedDef, lintMode);
204
+ let workspacePath;
205
+ if (values.workspace) {
206
+ const resolvedWs = resolve(values.workspace);
207
+ if (!existsSync(resolvedWs) || !statSync(resolvedWs).isDirectory()) {
208
+ writeStderr(`${RED}Workspace path is not a directory: ${resolvedWs}${RESET}`);
209
+ process.exit(1);
210
+ }
211
+ workspacePath = resolvedWs;
212
+ }
213
+ const modelOverride = values.model;
214
+ const baseDir = resolve(getIronCurtainHome(), 'workflow-runs');
215
+ mkdirSync(baseDir, { recursive: true });
216
+ const checkpointStore = new FileCheckpointStore(baseDir);
217
+ const gateHandler = createGateHandler();
218
+ const sessionFactory = createWorkflowSessionFactory(modelOverride);
219
+ const config = loadConfig();
220
+ const deps = {
221
+ createSession: sessionFactory,
222
+ createWorkflowTab: (label) => createConsoleTab(label),
223
+ raiseGate: gateHandler.raiseGate,
224
+ dismissGate: gateHandler.dismissGate,
225
+ baseDir,
226
+ checkpointStore,
227
+ userConfig: config.userConfig,
228
+ };
229
+ const orchestrator = new WorkflowOrchestrator(deps);
230
+ orchestrator.onEvent(printLifecycleEvent);
231
+ const controller = new AbortController();
232
+ process.on('SIGINT', () => {
233
+ writeStderr(`\n[workflow] Caught SIGINT, shutting down...`);
234
+ controller.abort();
235
+ });
236
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
237
+ try {
238
+ writeStdout(`${BOLD}${MAGENTA}Starting workflow${RESET}`);
239
+ writeStdout(`${DIM}Task: ${taskDescription}${RESET}`);
240
+ writeStdout(`${DIM}Base dir: ${baseDir}${RESET}`);
241
+ writeStdout('');
242
+ const workflowId = await orchestrator.start(resolvedDef, taskDescription, workspacePath);
243
+ const wsPath = workspacePath ?? resolve(baseDir, workflowId, 'workspace');
244
+ const artifactDir = resolve(wsPath, '.workflow');
245
+ await runEventLoop(orchestrator, workflowId, rl, controller.signal);
246
+ printSummary(orchestrator, workflowId, artifactDir);
247
+ const exitCode = computeExitCode(orchestrator, workflowId, controller.signal);
248
+ process.exit(exitCode);
249
+ }
250
+ finally {
251
+ rl.close();
252
+ await orchestrator.shutdownAll().catch(() => { });
253
+ writeStdout(`${DIM}Artifacts preserved at: ${baseDir}${RESET}`);
254
+ }
255
+ }
256
+ async function runResume(args) {
257
+ const { values, positionals } = parseArgsStrict({
258
+ args,
259
+ options: {
260
+ state: { type: 'string' },
261
+ model: { type: 'string' },
262
+ 'no-lint': { type: 'boolean' },
263
+ 'strict-lint': { type: 'boolean' },
264
+ help: { type: 'boolean', short: 'h' },
265
+ },
266
+ allowPositionals: true,
267
+ });
268
+ if (values.help) {
269
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
270
+ return;
271
+ }
272
+ const baseDirArg = positionals[0];
273
+ if (!baseDirArg) {
274
+ writeStderr(`${RED}Usage: ironcurtain workflow resume <baseDir> [--state <stateName>]${RESET}`);
275
+ process.exit(1);
276
+ }
277
+ const baseDir = resolve(baseDirArg);
278
+ if (!existsSync(baseDir)) {
279
+ writeStderr(`${RED}Base directory does not exist: ${baseDir}${RESET}`);
280
+ process.exit(1);
281
+ }
282
+ const modelOverride = values.model;
283
+ const overrideState = values.state;
284
+ const checkpointStore = new FileCheckpointStore(baseDir);
285
+ const gateHandler = createGateHandler();
286
+ const sessionFactory = createWorkflowSessionFactory(modelOverride);
287
+ let selected;
288
+ const hasCheckpoints = discoverWorkflowRuns(baseDir).some((r) => r.hasCheckpoint);
289
+ if (overrideState && !hasCheckpoints) {
290
+ // Find a definition path from the workflow directory
291
+ const definitionPath = findDefinitionPath(baseDir);
292
+ selected = synthesizeCheckpoint(baseDir, overrideState, definitionPath, checkpointStore);
293
+ }
294
+ else {
295
+ selected = selectResumableWorkflow(checkpointStore, baseDir);
296
+ }
297
+ // Pre-flight lint before orchestrator.resume(). The checkpoint carries
298
+ // a definitionPath we can re-validate + lint.
299
+ const defPath = selected.checkpoint.definitionPath;
300
+ if (defPath && existsSync(defPath)) {
301
+ const lintMode = resolveLintMode(values['no-lint'], values['strict-lint']);
302
+ runCliPreflightLint(defPath, lintMode);
303
+ }
304
+ printResumeInfo(baseDir, selected.workflowId, selected.checkpoint);
305
+ const config = loadConfig();
306
+ const deps = {
307
+ createSession: sessionFactory,
308
+ createWorkflowTab: (label) => createConsoleTab(label),
309
+ raiseGate: gateHandler.raiseGate,
310
+ dismissGate: gateHandler.dismissGate,
311
+ baseDir,
312
+ checkpointStore,
313
+ userConfig: config.userConfig,
314
+ };
315
+ const orchestrator = new WorkflowOrchestrator(deps);
316
+ orchestrator.onEvent(printLifecycleEvent);
317
+ const controller = new AbortController();
318
+ process.on('SIGINT', () => {
319
+ writeStderr(`\n[workflow] Caught SIGINT, shutting down...`);
320
+ controller.abort();
321
+ });
322
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
323
+ try {
324
+ writeStdout(`${BOLD}${MAGENTA}Resuming...${RESET}`);
325
+ writeStdout('');
326
+ await orchestrator.resume(selected.workflowId);
327
+ const wsPath = resolve(baseDir, selected.workflowId, 'workspace');
328
+ const artifactDir = resolve(wsPath, '.workflow');
329
+ await runEventLoop(orchestrator, selected.workflowId, rl, controller.signal);
330
+ printSummary(orchestrator, selected.workflowId, artifactDir);
331
+ const exitCode = computeExitCode(orchestrator, selected.workflowId, controller.signal);
332
+ process.exit(exitCode);
333
+ }
334
+ finally {
335
+ rl.close();
336
+ await orchestrator.shutdownAll().catch(() => { });
337
+ writeStdout(`${DIM}Artifacts preserved at: ${baseDir}${RESET}`);
338
+ }
339
+ }
340
+ function runInspect(args) {
341
+ const { values, positionals } = parseArgsStrict({
342
+ args,
343
+ options: {
344
+ all: { type: 'boolean' },
345
+ help: { type: 'boolean', short: 'h' },
346
+ },
347
+ allowPositionals: true,
348
+ });
349
+ if (values.help) {
350
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
351
+ return;
352
+ }
353
+ const baseDirArg = positionals[0];
354
+ if (!baseDirArg) {
355
+ writeStderr(`${RED}Usage: ironcurtain workflow inspect <baseDir> [--all]${RESET}`);
356
+ process.exit(1);
357
+ }
358
+ const baseDir = resolve(baseDirArg);
359
+ if (!existsSync(baseDir)) {
360
+ writeStderr(`${RED}Base directory does not exist: ${baseDir}${RESET}`);
361
+ process.exit(1);
362
+ }
363
+ const showAll = values.all === true;
364
+ const runs = discoverWorkflowRuns(baseDir);
365
+ if (runs.length === 0) {
366
+ writeStdout(`${DIM}No workflows found in ${baseDir}${RESET}`);
367
+ return;
368
+ }
369
+ // WorkflowManager owns the canonical "load a past run" logic. We point it at
370
+ // the user-supplied baseDir via `baseDirOverride` so the same loader works
371
+ // for both the daemon's home directory and arbitrary `inspect` targets.
372
+ // The CLI never starts workflows through this manager, so the event bus is
373
+ // a no-op sink and the orchestrator created lazily inside the manager is
374
+ // never used to spawn sessions.
375
+ const manager = new WorkflowManager({
376
+ eventBus: new TypedEventBus(),
377
+ baseDirOverride: baseDir,
378
+ });
379
+ for (const run of runs) {
380
+ const workflowId = run.workflowId;
381
+ const workflowDir = run.directoryPath;
382
+ const result = manager.loadPastRun(workflowId);
383
+ let checkpoint;
384
+ let loadedDef;
385
+ if ('error' in result) {
386
+ if (result.error === 'corrupted') {
387
+ // Behavior change: a malformed checkpoint or definition used to either
388
+ // throw (checkpoint) or be silently ignored (definition). We now print
389
+ // a clear error line and continue with the next workflow.
390
+ writeStdout(`${BOLD}${CYAN}Workflow: ${workflowId}${RESET}`);
391
+ writeStdout(` ${RED}Failed to load: ${result.message ?? 'unknown error'}${RESET}`);
392
+ writeStdout('');
393
+ continue;
394
+ }
395
+ // not_found: no checkpoint on disk. Preserve current behavior -- render
396
+ // the directory with `checkpoint = undefined` and silently parse the
397
+ // definition (without strict schema validation) for state descriptions.
398
+ checkpoint = undefined;
399
+ loadedDef = tryParseDefinitionForStateDescriptions(workflowDir);
400
+ }
401
+ else {
402
+ checkpoint = result.checkpoint;
403
+ loadedDef = result.definition;
404
+ }
405
+ writeStdout(`${BOLD}${CYAN}Workflow: ${workflowId}${RESET}`);
406
+ const stateDescriptions = loadedDef
407
+ ? new Map(Object.entries(loadedDef.states)
408
+ .filter(([, s]) => s.description)
409
+ .map(([id, s]) => [id, s.description]))
410
+ : undefined;
411
+ const defPath = resolve(workflowDir, 'definition.json');
412
+ if (checkpoint) {
413
+ const stateStr = String(checkpoint.machineState);
414
+ const desc = stateDescriptions?.get(stateStr);
415
+ const stateLabel = desc
416
+ ? `${BOLD}${stateStr}${RESET} ${DIM}\u2014 "${desc}"${RESET}`
417
+ : `${BOLD}${stateStr}${RESET}`;
418
+ writeStdout(` State: ${stateLabel}`);
419
+ writeStdout(` Timestamp: ${checkpoint.timestamp}`);
420
+ if (checkpoint.context.lastError) {
421
+ writeStdout(` Error: ${RED}${checkpoint.context.lastError}${RESET}`);
422
+ }
423
+ writeStdout(` Task: ${checkpoint.context.taskDescription.slice(0, 100)}`);
424
+ }
425
+ else {
426
+ writeStdout(` ${DIM}No checkpoint${RESET}`);
427
+ }
428
+ // Artifact directories
429
+ const wsPath = resolve(workflowDir, 'workspace', '.workflow');
430
+ if (existsSync(wsPath)) {
431
+ const artifactNames = readdirSync(wsPath).filter((e) => statSync(resolve(wsPath, e)).isDirectory());
432
+ writeStdout(` Artifacts: ${artifactNames.join(', ') || '(none)'}`);
433
+ }
434
+ if (existsSync(defPath)) {
435
+ writeStdout(` Definition: ${defPath}`);
436
+ }
437
+ // Informational lint of the checkpointed definition. Read-only — never
438
+ // affects exit code. Intentionally does NOT pass `workflowFilePath`:
439
+ // inspect operates on a past-run's `definition.json` whose sibling
440
+ // tree is the run directory, not the source workflow package, so
441
+ // WF010 (skill-reference) would emit false positives by looking for
442
+ // SKILL.md in a directory that never carried skills sidecars.
443
+ if (loadedDef) {
444
+ const diagnostics = lintWorkflow(loadedDef, defaultLintContext);
445
+ if (diagnostics.length > 0) {
446
+ const { errors, warnings } = countBySeverity(diagnostics);
447
+ writeStdout(` ${BOLD}Lint:${RESET} ${errors} error(s), ${warnings} warning(s)`);
448
+ for (const d of diagnostics) {
449
+ for (const line of formatDiagnostic(d))
450
+ writeStdout(` ${line}`);
451
+ }
452
+ }
453
+ }
454
+ // Message log
455
+ const logPath = resolve(workflowDir, 'messages.jsonl');
456
+ const messageLog = new MessageLog(logPath);
457
+ const entries = messageLog.readAll();
458
+ if (entries.length > 0) {
459
+ const displayEntries = showAll ? entries : entries.slice(-20);
460
+ const label = showAll
461
+ ? `All ${entries.length} messages`
462
+ : `Last ${displayEntries.length} of ${entries.length} messages`;
463
+ writeStdout(` ${BOLD}${label}:${RESET}`);
464
+ for (const entry of displayEntries) {
465
+ const ts = entry.ts.slice(11, 19); // HH:MM:SS
466
+ const prefix = ` ${DIM}${ts}${RESET}`;
467
+ switch (entry.type) {
468
+ case 'agent_sent':
469
+ writeStdout(`${prefix} ${CYAN}[sent/${entry.role}]${RESET} ${truncate(entry.message, 120)}`);
470
+ break;
471
+ case 'agent_received':
472
+ writeStdout(`${prefix} ${CYAN}[recv/${entry.role}]${RESET} verdict=${entry.verdict ?? '-'} ${truncate(entry.message, 80)}`);
473
+ break;
474
+ case 'agent_retry':
475
+ writeStdout(`${prefix} ${MAGENTA}[retry/${entry.role}]${RESET} ${entry.reason}`);
476
+ break;
477
+ case 'gate_raised':
478
+ writeStdout(`${prefix} ${BOLD}[gate]${RESET} events: ${entry.acceptedEvents.join(', ')}`);
479
+ break;
480
+ case 'gate_resolved':
481
+ writeStdout(`${prefix} ${BOLD}[gate resolved]${RESET} ${entry.event}`);
482
+ break;
483
+ case 'error':
484
+ writeStdout(`${prefix} ${RED}[error]${RESET} ${entry.error}`);
485
+ break;
486
+ case 'quota_exhausted':
487
+ writeStdout(`${prefix} ${YELLOW}[quota/${entry.role}]${RESET} resets=${entry.resetAt ?? 'unknown'} — ${truncate(entry.rawMessage, 80)}`);
488
+ break;
489
+ case 'transient_failure':
490
+ writeStdout(`${prefix} ${YELLOW}[transient/${entry.role}]${RESET} kind=${entry.kind} — ${truncate(entry.rawMessage, 80)}`);
491
+ break;
492
+ case 'state_transition': {
493
+ const toDesc = stateDescriptions?.get(entry.event);
494
+ const toLabel = toDesc ? `${entry.event} ${DIM}\u2014 "${toDesc}"${RESET}` : entry.event;
495
+ writeStdout(`${prefix} ${BLUE}[transition]${RESET} ${entry.from} -> ${toLabel}`);
496
+ break;
497
+ }
498
+ }
499
+ }
500
+ }
501
+ else {
502
+ writeStdout(` ${DIM}No message log${RESET}`);
503
+ }
504
+ writeStdout('');
505
+ }
506
+ }
507
+ /**
508
+ * Best-effort definition load used in the `not_found` branch of `loadPastRun`.
509
+ * Mirrors the pre-refactor behavior: parse-only (no schema validation), errors
510
+ * swallowed. The returned definition is used solely to populate state
511
+ * descriptions in the rendered message log.
512
+ */
513
+ function tryParseDefinitionForStateDescriptions(workflowDir) {
514
+ const defPath = resolve(workflowDir, 'definition.json');
515
+ if (!existsSync(defPath))
516
+ return undefined;
517
+ try {
518
+ return parseDefinitionFile(defPath);
519
+ }
520
+ catch {
521
+ // Non-fatal -- definition may be from an older schema.
522
+ return undefined;
523
+ }
524
+ }
525
+ // ---------------------------------------------------------------------------
526
+ // Helpers
527
+ // ---------------------------------------------------------------------------
528
+ function computeExitCode(orchestrator, workflowId, signal) {
529
+ if (signal.aborted)
530
+ return 130;
531
+ const status = orchestrator.getStatus(workflowId);
532
+ if (status?.phase === 'completed')
533
+ return 0;
534
+ return 1;
535
+ }
536
+ /** Finds the first definition.json path under a base directory's workflow runs. */
537
+ function findDefinitionPath(baseDir) {
538
+ const run = discoverWorkflowRuns(baseDir).find((r) => r.hasDefinition);
539
+ if (run)
540
+ return resolve(run.directoryPath, 'definition.json');
541
+ writeStderr(`${RED}No definition.json found in ${baseDir}${RESET}`);
542
+ process.exit(1);
543
+ }
544
+ function truncate(text, maxLen) {
545
+ const oneLine = text.replace(/\n/g, ' ').trim();
546
+ if (oneLine.length <= maxLen)
547
+ return oneLine;
548
+ return oneLine.slice(0, maxLen - 3) + '...';
549
+ }
550
+ // ---------------------------------------------------------------------------
551
+ // Lint subcommand
552
+ // ---------------------------------------------------------------------------
553
+ function runLintCommand(args) {
554
+ const { values, positionals } = parseArgsStrict({
555
+ args,
556
+ options: {
557
+ strict: { type: 'boolean' },
558
+ help: { type: 'boolean', short: 'h' },
559
+ },
560
+ allowPositionals: true,
561
+ });
562
+ if (values.help) {
563
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
564
+ return;
565
+ }
566
+ const definitionRef = positionals[0];
567
+ if (!definitionRef) {
568
+ writeStderr(`${RED}Usage: ironcurtain workflow lint <name-or-path> [--strict]${RESET}`);
569
+ process.exit(1);
570
+ }
571
+ const resolved = resolveWorkflowPath(definitionRef);
572
+ if (!resolved) {
573
+ writeStderr(`${RED}Workflow not found: ${definitionRef}${RESET}`);
574
+ writeStderr(`${DIM}Looked in bundled and user workflow directories.${RESET}`);
575
+ process.exit(1);
576
+ }
577
+ // Structural validation first — a malformed definition cannot be linted.
578
+ const definition = loadAndValidateDefinition(resolved);
579
+ const ctx = { ...defaultLintContext, workflowFilePath: resolved };
580
+ const diagnostics = lintWorkflow(definition, ctx);
581
+ if (diagnostics.length === 0) {
582
+ writeStderr(`${DIM}No lint diagnostics for ${resolved}.${RESET}`);
583
+ process.exit(0);
584
+ }
585
+ printDiagnostics(diagnostics);
586
+ const { errors, warnings } = countBySeverity(diagnostics);
587
+ writeStderr(`${DIM}Summary: ${errors} error(s), ${warnings} warning(s).${RESET}`);
588
+ if (errors > 0)
589
+ process.exit(1);
590
+ if (values.strict === true && warnings > 0)
591
+ process.exit(2);
592
+ process.exit(0);
593
+ }
594
+ // ---------------------------------------------------------------------------
595
+ // List subcommand
596
+ // ---------------------------------------------------------------------------
597
+ function runList() {
598
+ const workflows = discoverWorkflows();
599
+ if (workflows.length === 0) {
600
+ writeStdout(`${DIM}No workflow definitions found.${RESET}`);
601
+ return;
602
+ }
603
+ const nameWidth = Math.max(4, ...workflows.map((w) => w.name.length));
604
+ const sourceWidth = Math.max(6, ...workflows.map((w) => w.source.length));
605
+ const header = `${'NAME'.padEnd(nameWidth)} ${'SOURCE'.padEnd(sourceWidth)} DESCRIPTION`;
606
+ writeStdout(`${BOLD}${header}${RESET}`);
607
+ for (const wf of workflows) {
608
+ const line = `${wf.name.padEnd(nameWidth)} ${wf.source.padEnd(sourceWidth)} ${wf.description}`;
609
+ writeStdout(line);
610
+ }
611
+ }
612
+ // ---------------------------------------------------------------------------
613
+ // Main entry point
614
+ // ---------------------------------------------------------------------------
615
+ export async function main(args) {
616
+ const subcommand = args[0];
617
+ const subArgs = args.slice(1);
618
+ // Top-level help
619
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
620
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
621
+ return;
622
+ }
623
+ switch (subcommand) {
624
+ case 'list':
625
+ runList();
626
+ break;
627
+ case 'start':
628
+ await runStart(subArgs);
629
+ break;
630
+ case 'resume':
631
+ await runResume(subArgs);
632
+ break;
633
+ case 'inspect':
634
+ runInspect(subArgs);
635
+ break;
636
+ case 'lint':
637
+ runLintCommand(subArgs);
638
+ break;
639
+ case 'run-state':
640
+ await runRunState(subArgs);
641
+ break;
642
+ default:
643
+ writeStderr(`${RED}Unknown workflow subcommand: ${subcommand}${RESET}`);
644
+ process.stderr.write(formatHelp(workflowSpec) + '\n');
645
+ process.exit(1);
646
+ }
647
+ }
648
+ //# sourceMappingURL=workflow-command.js.map