@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,43 @@
1
+ export type MergeResult = {
2
+ readonly status: 'clean';
3
+ readonly commitHash: string;
4
+ } | {
5
+ readonly status: 'conflict';
6
+ readonly conflictFiles: readonly string[];
7
+ };
8
+ export interface WorktreeInfo {
9
+ readonly path: string;
10
+ readonly branch: string;
11
+ readonly parallelKey: string;
12
+ }
13
+ /** Manages git worktrees for parallel coding slots in workflows. */
14
+ export interface WorktreeManager {
15
+ /** Create a worktree for a parallel slot. Returns the worktree path. */
16
+ create(repoPath: string, branchName: string, baseBranch: string): Promise<string>;
17
+ /** Merge a worktree branch into the base branch. */
18
+ merge(repoPath: string, branchName: string, baseBranch: string): Promise<MergeResult>;
19
+ /** Remove a worktree and optionally delete its branch. */
20
+ remove(worktreePath: string, deleteBranch?: boolean): Promise<void>;
21
+ /** List active worktrees managed by workflows. */
22
+ listActive(): readonly WorktreeInfo[];
23
+ }
24
+ /**
25
+ * Git worktree manager for parallel coding workflows. Uses `execFile`
26
+ * with argument arrays exclusively -- never shell string concatenation.
27
+ */
28
+ export declare class GitWorktreeManager implements WorktreeManager {
29
+ private readonly worktreeBaseDir;
30
+ private readonly activeWorktrees;
31
+ constructor(worktreeBaseDir: string);
32
+ create(repoPath: string, branchName: string, baseBranch: string): Promise<string>;
33
+ merge(repoPath: string, branchName: string, baseBranch: string): Promise<MergeResult>;
34
+ remove(worktreePath: string, deleteBranch?: boolean): Promise<void>;
35
+ listActive(): readonly WorktreeInfo[];
36
+ /**
37
+ * Find the main working tree directory from any worktree path.
38
+ * Uses `git rev-parse --git-common-dir` to locate the shared .git directory,
39
+ * then resolves to its parent (the main working tree).
40
+ */
41
+ private findMainWorktree;
42
+ private getHeadCommitHash;
43
+ }
@@ -0,0 +1,106 @@
1
+ import { execFile as execFileCb } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { resolve } from 'node:path';
4
+ const execFileAsync = promisify(execFileCb);
5
+ // ---------------------------------------------------------------------------
6
+ // Implementation
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Git worktree manager for parallel coding workflows. Uses `execFile`
10
+ * with argument arrays exclusively -- never shell string concatenation.
11
+ */
12
+ export class GitWorktreeManager {
13
+ worktreeBaseDir;
14
+ activeWorktrees = [];
15
+ constructor(worktreeBaseDir) {
16
+ this.worktreeBaseDir = worktreeBaseDir;
17
+ }
18
+ async create(repoPath, branchName, baseBranch) {
19
+ const worktreePath = resolve(this.worktreeBaseDir, branchName);
20
+ await execFileAsync('git', ['worktree', 'add', worktreePath, '-b', branchName, baseBranch], { cwd: repoPath });
21
+ this.activeWorktrees.push({
22
+ path: worktreePath,
23
+ branch: branchName,
24
+ parallelKey: branchName,
25
+ });
26
+ return worktreePath;
27
+ }
28
+ async merge(repoPath, branchName, baseBranch) {
29
+ await execFileAsync('git', ['checkout', baseBranch], { cwd: repoPath });
30
+ try {
31
+ await execFileAsync('git', ['merge', '--no-ff', branchName], { cwd: repoPath });
32
+ const commitHash = await this.getHeadCommitHash(repoPath);
33
+ return { status: 'clean', commitHash };
34
+ }
35
+ catch (err) {
36
+ const execErr = err;
37
+ const conflictFiles = parseConflictFiles(execErr.stdout ?? '', execErr.stderr ?? '');
38
+ // Abort the failed merge to leave the repo in a clean state
39
+ await execFileAsync('git', ['merge', '--abort'], { cwd: repoPath }).catch(() => { });
40
+ return { status: 'conflict', conflictFiles };
41
+ }
42
+ }
43
+ async remove(worktreePath, deleteBranch) {
44
+ const info = this.activeWorktrees.find((w) => w.path === worktreePath);
45
+ const branchName = info?.branch;
46
+ // Discover the main repo directory from the worktree before removing it
47
+ const mainRepoDir = await this.findMainWorktree(worktreePath);
48
+ await execFileAsync('git', ['worktree', 'remove', worktreePath, '--force'], {
49
+ cwd: mainRepoDir,
50
+ });
51
+ // Remove from tracking
52
+ const idx = this.activeWorktrees.findIndex((w) => w.path === worktreePath);
53
+ if (idx >= 0) {
54
+ this.activeWorktrees.splice(idx, 1);
55
+ }
56
+ if (deleteBranch && branchName) {
57
+ try {
58
+ await execFileAsync('git', ['branch', '-D', branchName], {
59
+ cwd: mainRepoDir,
60
+ });
61
+ }
62
+ catch {
63
+ // Branch may already be deleted
64
+ }
65
+ }
66
+ }
67
+ listActive() {
68
+ return [...this.activeWorktrees];
69
+ }
70
+ /**
71
+ * Find the main working tree directory from any worktree path.
72
+ * Uses `git rev-parse --git-common-dir` to locate the shared .git directory,
73
+ * then resolves to its parent (the main working tree).
74
+ */
75
+ async findMainWorktree(worktreePath) {
76
+ // --git-common-dir returns the shared .git directory across all worktrees
77
+ const { stdout: commonDir } = await execFileAsync('git', ['rev-parse', '--git-common-dir'], {
78
+ cwd: worktreePath,
79
+ });
80
+ // commonDir is the path to the shared .git directory (e.g., /repo/.git)
81
+ return resolve(worktreePath, commonDir.trim(), '..');
82
+ }
83
+ async getHeadCommitHash(repoPath) {
84
+ const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: repoPath });
85
+ return stdout.trim();
86
+ }
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Helpers
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Parse conflict file paths from git merge output. Git lists conflicting
93
+ * files in both stdout (CONFLICT lines) and stderr.
94
+ */
95
+ function parseConflictFiles(stdout, stderr) {
96
+ const combined = `${stdout}\n${stderr}`;
97
+ const conflicts = [];
98
+ // Match "CONFLICT (content): Merge conflict in <path>"
99
+ const pattern = /CONFLICT\s+\([^)]+\):\s+Merge conflict in\s+(.+)/g;
100
+ let match;
101
+ while ((match = pattern.exec(combined)) !== null) {
102
+ conflicts.push(match[1].trim());
103
+ }
104
+ return conflicts;
105
+ }
106
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/workflow/worktree.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ FROM mcr.microsoft.com/devcontainers/universal:latest
3
3
  # Standard IronCurtain directory structure
4
4
  # The universal image uses 'codespace' as the non-root user (uid 1000).
5
5
  USER root
6
- RUN apt-get update && apt-get install -y --no-install-recommends socat && rm -rf /var/lib/apt/lists/*
6
+ RUN apt-get update && apt-get install -y --no-install-recommends socat sudo git-lfs && rm -rf /var/lib/apt/lists/*
7
7
 
8
8
  # IronCurtain CA (for MITM proxy trust)
9
9
  # This file is copied into a temporary build context by ensureImage().
@@ -26,10 +26,21 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
26
26
  ENV UV_NATIVE_TLS=1
27
27
  ENV UV_PYTHON_INSTALL_DIR=/opt/uv-python
28
28
  RUN uv python install 3.12
29
+ # Install pip so agents can use `pip install` directly.
30
+ RUN apt-get update && apt-get install -y --no-install-recommends python3-pip && rm -rf /var/lib/apt/lists/*
29
31
 
30
32
  RUN mkdir -p /workspace /etc/ironcurtain /run/ironcurtain && \
31
33
  chown codespace:codespace /workspace /etc/ironcurtain /run/ironcurtain
32
34
 
35
+ RUN npm install -g node-gyp
36
+
37
+ # Playwright + Chromium: pre-install so containers work with --network=none.
38
+ # Install system deps as root, then browser to a shared path.
39
+ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
40
+ RUN npx playwright install-deps chromium && \
41
+ npx playwright install chromium && \
42
+ chmod -R o+rx /opt/playwright-browsers
43
+
33
44
  WORKDIR /workspace
34
45
  USER codespace
35
46
 
@@ -10,7 +10,7 @@ USER root
10
10
  RUN apt-get update && \
11
11
  apt-get install -y --no-install-recommends \
12
12
  # Existing
13
- git socat ca-certificates \
13
+ git git-lfs sudo socat ca-certificates curl \
14
14
  # Build tools for native extensions
15
15
  build-essential cmake pkg-config \
16
16
  # Graphics/Qt runtime + dev
@@ -26,6 +26,13 @@ RUN apt-get update && \
26
26
  fontconfig fonts-dejavu-core \
27
27
  && rm -rf /var/lib/apt/lists/*
28
28
 
29
+ # Grant passwordless sudo to codespace (matches devcontainers/universal behavior)
30
+ RUN echo "codespace ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/codespace && \
31
+ chmod 0440 /etc/sudoers.d/codespace
32
+
33
+ # Initialize git-lfs
34
+ RUN git lfs install --system
35
+
29
36
  # IronCurtain CA (for MITM proxy trust)
30
37
  # This file is copied into a temporary build context by ensureImage().
31
38
  COPY ironcurtain-ca-cert.pem /usr/local/share/ca-certificates/ironcurtain-ca.crt
@@ -48,9 +55,18 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
48
55
  ENV UV_NATIVE_TLS=1
49
56
  ENV UV_PYTHON_INSTALL_DIR=/opt/uv-python
50
57
  RUN uv python install 3.12
58
+ # Install pip so agents can use `pip install` directly.
59
+ RUN apt-get update && apt-get install -y --no-install-recommends python3-pip && rm -rf /var/lib/apt/lists/*
51
60
 
52
61
  RUN npm install -g node-gyp
53
62
 
63
+ # Playwright + Chromium: pre-install so containers work with --network=none.
64
+ # Install system deps as root, then browser to a shared path.
65
+ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
66
+ RUN npx playwright install-deps chromium && \
67
+ npx playwright install chromium && \
68
+ chmod -R o+rx /opt/playwright-browsers
69
+
54
70
  RUN mkdir -p /workspace /etc/ironcurtain /run/ironcurtain && \
55
71
  chown codespace:codespace /workspace /etc/ironcurtain /run/ironcurtain
56
72
 
@@ -4,6 +4,52 @@
4
4
  # Non-PTY mode: CMD is "sleep infinity" (agent commands arrive via docker exec).
5
5
  # PTY mode: CMD is the socat PTY command from buildPtyCommand().
6
6
 
7
+ # Runtime UID remap (Linux only).
8
+ #
9
+ # Issue #232: when the host UID is not 1000, bind-mounted directories
10
+ # (e.g., the conversation-state dir) appear inside the container owned
11
+ # by the host UID, and the baked codespace user (UID 1000) cannot write
12
+ # to them. The host-side launcher passes `--user 0:0` plus the host
13
+ # UID/GID via IRONCURTAIN_AGENT_UID / IRONCURTAIN_AGENT_GID so this
14
+ # block (running as root) can renumber the codespace account to match
15
+ # the host before dropping privileges. On macOS, Docker Desktop's
16
+ # VirtioFS translates UIDs transparently and the env vars are not set,
17
+ # so this block is skipped.
18
+ if [ "$(id -u)" = "0" ] && [ -n "$IRONCURTAIN_AGENT_UID" ] && [ -n "$IRONCURTAIN_AGENT_GID" ]; then
19
+ if [ "$IRONCURTAIN_AGENT_UID" != "1000" ] || [ "$IRONCURTAIN_AGENT_GID" != "1000" ]; then
20
+ # Renumber the codespace user/group to the host UID/GID, then fix
21
+ # ownership on the baked home dir and workspace mount so the
22
+ # remapped codespace user can read/write them. Bind-mounted
23
+ # subdirectories (conversation state, sockets, orientation) keep
24
+ # their host-side ownership, which now matches codespace.
25
+ #
26
+ # FAIL HARD on remap errors. Previously these commands ran without
27
+ # return-code checks: if `usermod -u $HOST_UID codespace` collided
28
+ # with an existing image user (plausible for system UIDs like 33
29
+ # `www-data` or 100 `systemd-network`), the entrypoint would
30
+ # silently continue, then `chown` and `runuser -u codespace`
31
+ # would operate on the still-UID-1000 codespace — recreating the
32
+ # original issue #232 bug with no diagnostic. Abort with an explicit
33
+ # error instead so the operator sees what went wrong.
34
+ groupmod -g "$IRONCURTAIN_AGENT_GID" codespace || {
35
+ echo "[ironcurtain] groupmod failed: cannot remap codespace group to GID $IRONCURTAIN_AGENT_GID (already in use?)" >&2
36
+ exit 1
37
+ }
38
+ usermod -u "$IRONCURTAIN_AGENT_UID" -g "$IRONCURTAIN_AGENT_GID" codespace || {
39
+ echo "[ironcurtain] usermod failed: cannot remap codespace user to UID $IRONCURTAIN_AGENT_UID (already in use?)" >&2
40
+ exit 1
41
+ }
42
+ chown -R "$IRONCURTAIN_AGENT_UID:$IRONCURTAIN_AGENT_GID" /home/codespace /workspace || {
43
+ echo "[ironcurtain] chown failed: cannot reset ownership of /home/codespace and /workspace to $IRONCURTAIN_AGENT_UID:$IRONCURTAIN_AGENT_GID" >&2
44
+ exit 1
45
+ }
46
+ fi
47
+ # Re-exec the entrypoint as the (possibly remapped) codespace user.
48
+ # The remainder of this script runs under codespace, so $HOME and
49
+ # sudoers (which keys on the username) resolve correctly.
50
+ exec runuser -u codespace -- "$0" "$@"
51
+ fi
52
+
7
53
  # Bridge UDS to local TCP so HTTPS_PROXY works
8
54
  MITM_SOCK="/run/ironcurtain/mitm-proxy.sock"
9
55
  PROXY_PORT=18080
@@ -2,6 +2,31 @@
2
2
  # IronCurtain entrypoint for Goose containers.
3
3
  # Sets up proxy bridges, writes Goose config, then hands off to CMD.
4
4
 
5
+ # Runtime UID remap (Linux only). See entrypoint-claude-code.sh for the
6
+ # full rationale (issue #232). Skipped on macOS where Docker Desktop
7
+ # translates UIDs and the env vars are not set.
8
+ if [ "$(id -u)" = "0" ] && [ -n "$IRONCURTAIN_AGENT_UID" ] && [ -n "$IRONCURTAIN_AGENT_GID" ]; then
9
+ if [ "$IRONCURTAIN_AGENT_UID" != "1000" ] || [ "$IRONCURTAIN_AGENT_GID" != "1000" ]; then
10
+ # Fail hard on remap errors — see entrypoint-claude-code.sh for the
11
+ # full rationale. Without explicit checks, a UID collision (host UID
12
+ # already in use by a system user baked into the image) silently
13
+ # recreates the original issue #232 bug.
14
+ groupmod -g "$IRONCURTAIN_AGENT_GID" codespace || {
15
+ echo "[ironcurtain] groupmod failed: cannot remap codespace group to GID $IRONCURTAIN_AGENT_GID (already in use?)" >&2
16
+ exit 1
17
+ }
18
+ usermod -u "$IRONCURTAIN_AGENT_UID" -g "$IRONCURTAIN_AGENT_GID" codespace || {
19
+ echo "[ironcurtain] usermod failed: cannot remap codespace user to UID $IRONCURTAIN_AGENT_UID (already in use?)" >&2
20
+ exit 1
21
+ }
22
+ chown -R "$IRONCURTAIN_AGENT_UID:$IRONCURTAIN_AGENT_GID" /home/codespace /workspace || {
23
+ echo "[ironcurtain] chown failed: cannot reset ownership of /home/codespace and /workspace to $IRONCURTAIN_AGENT_UID:$IRONCURTAIN_AGENT_GID" >&2
24
+ exit 1
25
+ }
26
+ fi
27
+ exec runuser -u codespace -- "$0" "$@"
28
+ fi
29
+
5
30
  # 1. Bridge MITM proxy UDS to local TCP (same as Claude Code entrypoint)
6
31
  MITM_SOCK="/run/ironcurtain/mitm-proxy.sock"
7
32
  PROXY_PORT=18080
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@provos/ironcurtain",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "description": "Secure agent runtime with trusted process mediation",
6
6
  "license": "Apache-2.0",
@@ -44,11 +44,14 @@
44
44
  "src/config/generated/compiled-policy.json",
45
45
  "src/config/generated/tool-annotations.json",
46
46
  "src/config/generated/test-scenarios.json",
47
+ "src/workflow/workflows/",
48
+ "packages/web-ui/docs/workflow-state-machine.png",
47
49
  "README.md",
48
50
  "LICENSE"
49
51
  ],
50
52
  "scripts": {
51
- "build": "tsc && node scripts/copy-assets.mjs",
53
+ "build": "tsc && node scripts/copy-assets.mjs && npm run build:web-ui --if-present",
54
+ "build:web-ui": "npm run build -w packages/web-ui",
52
55
  "start": "tsx src/cli.ts start",
53
56
  "annotate-tools": "tsx src/cli.ts annotate-tools",
54
57
  "compile-policy": "tsx src/cli.ts compile-policy",
@@ -58,7 +61,8 @@
58
61
  "config": "tsx src/cli.ts config",
59
62
  "setup": "tsx src/cli.ts setup",
60
63
  "prepublishOnly": "npm run build",
61
- "test": "vitest run",
64
+ "test": "bash scripts/test.sh",
65
+ "test:web-ui": "npm test -w packages/web-ui",
62
66
  "test:watch": "vitest",
63
67
  "lint": "eslint src/ test/",
64
68
  "format": "prettier --log-level=warn --write 'src/**/*.ts' 'test/**/*.ts'",
@@ -70,7 +74,7 @@
70
74
  "@ai-sdk/anthropic": "^3.0.49",
71
75
  "@ai-sdk/google": "^3.0.33",
72
76
  "@ai-sdk/openai": "^3.0.36",
73
- "@anthropic-ai/sandbox-runtime": "^0.0.42",
77
+ "@anthropic-ai/sandbox-runtime": "^0.0.49",
74
78
  "@clack/prompts": "^1.0.1",
75
79
  "@cyanheads/git-mcp-server": "^2.8.4",
76
80
  "@modelcontextprotocol/sdk": "^1.27.1",
@@ -89,9 +93,14 @@
89
93
  "minimatch": "^10.2.1",
90
94
  "node-forge": "^1.3.3",
91
95
  "ora": "^9.3.0",
96
+ "p-limit": "^7.3.0",
92
97
  "shell-quote": "^1.8.3",
93
98
  "turndown": "^7.2.2",
94
- "uuid": "^13.0.0",
99
+ "undici": "^7.24.0",
100
+ "uuid": "^14.0.0",
101
+ "ws": "^8.20.0",
102
+ "xstate": "^5.30.0",
103
+ "yaml": "^2.8.3",
95
104
  "zod": "^4.3.6"
96
105
  },
97
106
  "optionalDependencies": {
@@ -102,13 +111,19 @@
102
111
  "minimatch": "^10.2.1"
103
112
  },
104
113
  "lint-staged": {
105
- "*.ts": [
114
+ "!(packages/**)/*.ts": [
106
115
  "prettier --check",
107
116
  "eslint"
117
+ ],
118
+ "packages/web-ui/**/*.{ts,svelte}": [
119
+ "prettier --check --config packages/web-ui/.prettierrc",
120
+ "npm run lint -w packages/web-ui",
121
+ "npm run check -w packages/web-ui"
108
122
  ]
109
123
  },
110
124
  "devDependencies": {
111
125
  "@eslint/js": "^10.0.1",
126
+ "@modelcontextprotocol/server-filesystem": "^2026.1.14",
112
127
  "@types/jsdom": "^28.0.0",
113
128
  "@types/node": "^25.3.0",
114
129
  "@types/node-forge": "^1.3.14",
@@ -123,7 +138,6 @@
123
138
  "tsx": "^4.19.0",
124
139
  "typescript": "^5.7.0",
125
140
  "typescript-eslint": "^8.56.0",
126
- "vitest": "^4.0.18",
127
- "ws": "^8.19.0"
141
+ "vitest": "^4.0.18"
128
142
  }
129
143
  }
@@ -0,0 +1,113 @@
1
+ # IronCurtain Web UI
2
+
3
+ Opt-in web dashboard for the IronCurtain daemon. Provides a browser-based interface to monitor sessions, respond to escalations, manage scheduled jobs, and track resource budgets. The frontend is a Svelte 5 SPA that communicates with the daemon over a JSON-RPC WebSocket protocol with bearer token authentication.
4
+
5
+ ![Dashboard](docs/dashboard.png)
6
+
7
+ ## Quick Start
8
+
9
+ Start the daemon with the `--web-ui` flag:
10
+
11
+ ```bash
12
+ ironcurtain daemon --web-ui
13
+ ```
14
+
15
+ The daemon prints an auth URL to stderr:
16
+
17
+ ```
18
+ Web UI: http://localhost:7400/?token=<TOKEN>
19
+ ```
20
+
21
+ Open that URL in a browser. The token is required -- paste it into the login screen if the URL parameter is lost. To use a custom port, pass `--web-port <port>`.
22
+
23
+ ## Features
24
+
25
+ - Dashboard with session, escalation, and job summary stats
26
+ - Interactive chat sessions with persona selection and markdown-rendered responses
27
+ - Escalation approval/denial with whitelist candidate selection
28
+ - Job management: run, enable, disable, recompile, remove
29
+ - Collapsible tool call groups in session output
30
+ - Three themes: Iron (dark charcoal + amber), Daylight (light + teal), Midnight (navy + blue)
31
+ - Real-time updates pushed over WebSocket
32
+ - Resource budget tracking per session (tokens, steps, cost, wall-clock time)
33
+
34
+ ## Development
35
+
36
+ ### With the real daemon (two terminals)
37
+
38
+ ```bash
39
+ # Terminal 1 -- daemon with dev mode (skips Origin validation for Vite's port)
40
+ ironcurtain daemon --web-ui --web-ui-dev
41
+
42
+ # Terminal 2 -- Vite dev server with hot reload
43
+ cd packages/web-ui && npm run dev
44
+ ```
45
+
46
+ Open `http://localhost:5173?token=<TOKEN>` (copy the token from Terminal 1). Vite proxies `/ws` to the daemon on port 7400.
47
+
48
+ ### With the mock server (no Docker or LLM needed)
49
+
50
+ ```bash
51
+ # Terminal 1
52
+ cd packages/web-ui && npm run mock-server
53
+
54
+ # Terminal 2
55
+ cd packages/web-ui && npm run dev
56
+ ```
57
+
58
+ Open `http://localhost:5173?token=mock-dev-token`. The mock server simulates the full protocol with canned data -- chat messages produce realistic event sequences (thinking, tool calls, markdown response), sending a message containing "escalate" triggers an escalation flow, and three sample jobs support enable/disable/remove.
59
+
60
+ See [CLAUDE.md](./CLAUDE.md) for component conventions, directory structure, and theme system details.
61
+
62
+ ## Testing
63
+
64
+ Three tiers:
65
+
66
+ ### Mock server (manual testing)
67
+
68
+ ```bash
69
+ npm run mock-server # Start canned WebSocket server on :7400
70
+ npm run dev # Start Vite on :5173 in another terminal
71
+ ```
72
+
73
+ ### Unit tests
74
+
75
+ ```bash
76
+ npm test # Run all unit tests (vitest)
77
+ npm run test:watch # Watch mode during development
78
+ ```
79
+
80
+ Covers WebSocket event handling, output grouping logic, and request correlation. Tests run against pure TypeScript modules extracted from Svelte components for testability.
81
+
82
+ ### E2E tests (Playwright)
83
+
84
+ ```bash
85
+ npx playwright install chromium # One-time browser install
86
+ npm run e2e # Run all E2E tests
87
+ npm run e2e:headed # Run with visible browser
88
+ ```
89
+
90
+ Playwright auto-starts both the mock server and Vite dev server. Tests cover dashboard stats, session lifecycle, escalation approve/deny, job actions, theme switching, and error states.
91
+
92
+ ## Tech Stack
93
+
94
+ - **Svelte 5** -- runes-based reactivity (`$state`, `$derived`, `$effect`)
95
+ - **Vite** -- dev server and production bundler
96
+ - **Tailwind CSS v3** -- utility-first styling with CSS custom property theming
97
+ - **phosphor-svelte** -- icons (tree-shaken via Vite plugin)
98
+ - **marked + DOMPurify** -- safe markdown rendering
99
+ - **clsx + tailwind-merge** -- conditional class merging (shadcn-svelte pattern)
100
+
101
+ ## Architecture
102
+
103
+ The daemon's `WebUiServer` (in `src/web-ui/`) starts an HTTP server that serves the compiled static assets from `dist/web-ui-static/` and upgrades `/ws` connections to WebSocket.
104
+
105
+ Communication uses a JSON-RPC protocol over WebSocket:
106
+
107
+ - **Requests**: `{ id, method, params? }` -- client calls like `sessions.create`, `escalations.resolve`, `jobs.run`
108
+ - **Responses**: `{ id, ok, payload?, error? }` -- correlated by `id`
109
+ - **Events**: `{ event, payload, seq }` -- server-push notifications like `session.output`, `escalation.created`, `daemon.status`
110
+
111
+ Authentication is via a bearer token generated at daemon startup. The token is passed as a `?token=` query parameter on the initial page load and sent with the WebSocket connection. The `--web-ui-dev` flag disables Origin header validation so the Vite dev server on port 5173 can connect to the daemon on port 7400.
112
+
113
+ Production builds output to `dist/web-ui-static/` (via `npm run build` in the workspace root or `npm run build` in this package). The daemon serves these files as static assets with no additional build step at runtime.