@provos/ironcurtain 0.11.0 → 0.13.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 (472) hide show
  1. package/README.md +23 -19
  2. package/dist/cli-help.d.ts +12 -0
  3. package/dist/cli-help.js +21 -0
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.js +14 -6
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config/agent-model-guard.d.ts +14 -0
  8. package/dist/config/agent-model-guard.js +24 -0
  9. package/dist/config/agent-model-guard.js.map +1 -0
  10. package/dist/config/config-command.d.ts +33 -1
  11. package/dist/config/config-command.js +723 -11
  12. package/dist/config/config-command.js.map +1 -1
  13. package/dist/config/first-start.js +2 -8
  14. package/dist/config/first-start.js.map +1 -1
  15. package/dist/config/model-provider.d.ts +9 -0
  16. package/dist/config/model-provider.js +13 -0
  17. package/dist/config/model-provider.js.map +1 -1
  18. package/dist/config/openrouter-catalog.d.ts +46 -0
  19. package/dist/config/openrouter-catalog.js +111 -0
  20. package/dist/config/openrouter-catalog.js.map +1 -0
  21. package/dist/config/openrouter-models-fallback.d.ts +15 -0
  22. package/dist/config/openrouter-models-fallback.js +49 -0
  23. package/dist/config/openrouter-models-fallback.js.map +1 -0
  24. package/dist/config/paths.d.ts +48 -6
  25. package/dist/config/paths.js +63 -8
  26. package/dist/config/paths.js.map +1 -1
  27. package/dist/config/types.d.ts +8 -0
  28. package/dist/config/user-config.d.ts +179 -6
  29. package/dist/config/user-config.js +282 -5
  30. package/dist/config/user-config.js.map +1 -1
  31. package/dist/daemon/daemon-command.js +14 -5
  32. package/dist/daemon/daemon-command.js.map +1 -1
  33. package/dist/daemon/ironcurtain-daemon.d.ts +18 -0
  34. package/dist/daemon/ironcurtain-daemon.js +28 -1
  35. package/dist/daemon/ironcurtain-daemon.js.map +1 -1
  36. package/dist/daemon-client/daemon-client.d.ts +123 -0
  37. package/dist/daemon-client/daemon-client.js +324 -0
  38. package/dist/daemon-client/daemon-client.js.map +1 -0
  39. package/dist/docker/adapters/claude-code.js +109 -1
  40. package/dist/docker/adapters/claude-code.js.map +1 -1
  41. package/dist/docker/adapters/codex.d.ts +18 -0
  42. package/dist/docker/adapters/codex.js +376 -0
  43. package/dist/docker/adapters/codex.js.map +1 -0
  44. package/dist/docker/adapters/goose.js +38 -2
  45. package/dist/docker/adapters/goose.js.map +1 -1
  46. package/dist/docker/agent-adapter.d.ts +34 -6
  47. package/dist/docker/agent-adapter.js +2 -0
  48. package/dist/docker/agent-adapter.js.map +1 -1
  49. package/dist/docker/agent-registry.js +5 -0
  50. package/dist/docker/agent-registry.js.map +1 -1
  51. package/dist/docker/apple-container-manager.d.ts +49 -0
  52. package/dist/docker/apple-container-manager.js +486 -0
  53. package/dist/docker/apple-container-manager.js.map +1 -0
  54. package/dist/docker/ca.js +9 -2
  55. package/dist/docker/ca.js.map +1 -1
  56. package/dist/docker/code-mode-proxy.d.ts +11 -0
  57. package/dist/docker/code-mode-proxy.js +3 -1
  58. package/dist/docker/code-mode-proxy.js.map +1 -1
  59. package/dist/docker/container-lifecycle.d.ts +2 -2
  60. package/dist/docker/container-lifecycle.js +9 -0
  61. package/dist/docker/container-lifecycle.js.map +1 -1
  62. package/dist/docker/container-runtime.d.ts +29 -0
  63. package/dist/docker/container-runtime.js +76 -0
  64. package/dist/docker/container-runtime.js.map +1 -0
  65. package/dist/docker/docker-agent-session.d.ts +31 -0
  66. package/dist/docker/docker-agent-session.js +97 -7
  67. package/dist/docker/docker-agent-session.js.map +1 -1
  68. package/dist/docker/docker-infrastructure.d.ts +232 -15
  69. package/dist/docker/docker-infrastructure.js +762 -118
  70. package/dist/docker/docker-infrastructure.js.map +1 -1
  71. package/dist/docker/docker-manager.d.ts +25 -5
  72. package/dist/docker/docker-manager.js +388 -21
  73. package/dist/docker/docker-manager.js.map +1 -1
  74. package/dist/docker/docker-probe.d.ts +45 -0
  75. package/dist/docker/docker-probe.js +86 -0
  76. package/dist/docker/docker-probe.js.map +1 -0
  77. package/dist/docker/docker-progress-sink.d.ts +1 -1
  78. package/dist/docker/docker-resource-lifecycle.d.ts +71 -0
  79. package/dist/docker/docker-resource-lifecycle.js +454 -0
  80. package/dist/docker/docker-resource-lifecycle.js.map +1 -0
  81. package/dist/docker/gc-command.d.ts +2 -0
  82. package/dist/docker/gc-command.js +37 -0
  83. package/dist/docker/gc-command.js.map +1 -0
  84. package/dist/docker/mitm-proxy.d.ts +58 -5
  85. package/dist/docker/mitm-proxy.js +338 -26
  86. package/dist/docker/mitm-proxy.js.map +1 -1
  87. package/dist/docker/network-topology.d.ts +88 -0
  88. package/dist/docker/network-topology.js +167 -0
  89. package/dist/docker/network-topology.js.map +1 -0
  90. package/dist/docker/oauth-credentials.d.ts +13 -0
  91. package/dist/docker/oauth-credentials.js +125 -0
  92. package/dist/docker/oauth-credentials.js.map +1 -1
  93. package/dist/docker/openrouter.d.ts +107 -0
  94. package/dist/docker/openrouter.js +236 -0
  95. package/dist/docker/openrouter.js.map +1 -0
  96. package/dist/docker/orientation.js +1 -1
  97. package/dist/docker/orientation.js.map +1 -1
  98. package/dist/docker/package-types.d.ts +1 -1
  99. package/dist/docker/platform.d.ts +3 -1
  100. package/dist/docker/platform.js +3 -1
  101. package/dist/docker/platform.js.map +1 -1
  102. package/dist/docker/provider-config.d.ts +35 -1
  103. package/dist/docker/provider-config.js +93 -3
  104. package/dist/docker/provider-config.js.map +1 -1
  105. package/dist/docker/provision-lock.d.ts +46 -0
  106. package/dist/docker/provision-lock.js +152 -0
  107. package/dist/docker/provision-lock.js.map +1 -0
  108. package/dist/docker/pty-session.d.ts +22 -0
  109. package/dist/docker/pty-session.js +238 -84
  110. package/dist/docker/pty-session.js.map +1 -1
  111. package/dist/docker/pty-types.d.ts +15 -0
  112. package/dist/docker/pty-types.js +8 -0
  113. package/dist/docker/pty-types.js.map +1 -1
  114. package/dist/docker/registry-proxy.d.ts +46 -0
  115. package/dist/docker/registry-proxy.js +255 -1
  116. package/dist/docker/registry-proxy.js.map +1 -1
  117. package/dist/docker/resource-limits.d.ts +14 -5
  118. package/dist/docker/resource-limits.js +11 -8
  119. package/dist/docker/resource-limits.js.map +1 -1
  120. package/dist/docker/sse-extractor.js +55 -5
  121. package/dist/docker/sse-extractor.js.map +1 -1
  122. package/dist/docker/stream-delay.d.ts +86 -0
  123. package/dist/docker/stream-delay.js +218 -0
  124. package/dist/docker/stream-delay.js.map +1 -0
  125. package/dist/docker/token-stream-types.d.ts +15 -0
  126. package/dist/docker/trajectory-capture.d.ts +79 -0
  127. package/dist/docker/trajectory-capture.js +521 -0
  128. package/dist/docker/trajectory-capture.js.map +1 -0
  129. package/dist/docker/trajectory-reassembler.d.ts +286 -0
  130. package/dist/docker/trajectory-reassembler.js +1010 -0
  131. package/dist/docker/trajectory-reassembler.js.map +1 -0
  132. package/dist/docker/trajectory-tap.d.ts +100 -0
  133. package/dist/docker/trajectory-tap.js +410 -0
  134. package/dist/docker/trajectory-tap.js.map +1 -0
  135. package/dist/docker/trajectory-types.d.ts +187 -0
  136. package/dist/docker/trajectory-types.js +43 -0
  137. package/dist/docker/trajectory-types.js.map +1 -0
  138. package/dist/docker/types.d.ts +116 -12
  139. package/dist/doctor/checks.d.ts +39 -6
  140. package/dist/doctor/checks.js +129 -25
  141. package/dist/doctor/checks.js.map +1 -1
  142. package/dist/doctor/doctor-command.js +39 -9
  143. package/dist/doctor/doctor-command.js.map +1 -1
  144. package/dist/doctor/mcp-liveness.d.ts +1 -1
  145. package/dist/doctor/mcp-liveness.js +12 -4
  146. package/dist/doctor/mcp-liveness.js.map +1 -1
  147. package/dist/escalation/escalation-watcher.js +6 -0
  148. package/dist/escalation/escalation-watcher.js.map +1 -1
  149. package/dist/{mux → escalation}/trusted-input.d.ts +7 -4
  150. package/dist/{mux → escalation}/trusted-input.js +8 -5
  151. package/dist/escalation/trusted-input.js.map +1 -0
  152. package/dist/hash.js.map +1 -1
  153. package/dist/index.js +65 -16
  154. package/dist/index.js.map +1 -1
  155. package/dist/mux/mux-app.d.ts +9 -0
  156. package/dist/mux/mux-app.js +18 -16
  157. package/dist/mux/mux-app.js.map +1 -1
  158. package/dist/mux/mux-command.js +26 -8
  159. package/dist/mux/mux-command.js.map +1 -1
  160. package/dist/mux/mux-input-handler.d.ts +26 -2
  161. package/dist/mux/mux-input-handler.js +93 -11
  162. package/dist/mux/mux-input-handler.js.map +1 -1
  163. package/dist/mux/mux-renderer.d.ts +2 -1
  164. package/dist/mux/mux-renderer.js +67 -0
  165. package/dist/mux/mux-renderer.js.map +1 -1
  166. package/dist/mux/provider-profile-snapshot.d.ts +44 -0
  167. package/dist/mux/provider-profile-snapshot.js +56 -0
  168. package/dist/mux/provider-profile-snapshot.js.map +1 -0
  169. package/dist/mux/types.d.ts +3 -2
  170. package/dist/mux/types.js +6 -2
  171. package/dist/mux/types.js.map +1 -1
  172. package/dist/observe/observe-command.js +112 -125
  173. package/dist/observe/observe-command.js.map +1 -1
  174. package/dist/persona/broad-policy-validator.d.ts +95 -0
  175. package/dist/persona/broad-policy-validator.js +171 -0
  176. package/dist/persona/broad-policy-validator.js.map +1 -0
  177. package/dist/persona/compile-persona-policy.d.ts +54 -2
  178. package/dist/persona/compile-persona-policy.js +29 -4
  179. package/dist/persona/compile-persona-policy.js.map +1 -1
  180. package/dist/persona/event-bus-progress-reporter.d.ts +57 -0
  181. package/dist/persona/event-bus-progress-reporter.js +66 -0
  182. package/dist/persona/event-bus-progress-reporter.js.map +1 -0
  183. package/dist/persona/persona-command.js +46 -76
  184. package/dist/persona/persona-command.js.map +1 -1
  185. package/dist/persona/persona-compile-orchestrator.d.ts +101 -0
  186. package/dist/persona/persona-compile-orchestrator.js +504 -0
  187. package/dist/persona/persona-compile-orchestrator.js.map +1 -0
  188. package/dist/persona/persona-service.d.ts +137 -0
  189. package/dist/persona/persona-service.js +263 -0
  190. package/dist/persona/persona-service.js.map +1 -0
  191. package/dist/persona/policy-mutation-audit.d.ts +109 -0
  192. package/dist/persona/policy-mutation-audit.js +179 -0
  193. package/dist/persona/policy-mutation-audit.js.map +1 -0
  194. package/dist/persona/rule-delta.d.ts +30 -0
  195. package/dist/persona/rule-delta.js +82 -0
  196. package/dist/persona/rule-delta.js.map +1 -0
  197. package/dist/persona/types.d.ts +12 -0
  198. package/dist/pipeline/annotate.js +10 -2
  199. package/dist/pipeline/annotate.js.map +1 -1
  200. package/dist/pipeline/compile.js +14 -2
  201. package/dist/pipeline/compile.js.map +1 -1
  202. package/dist/pipeline/constitution-compiler.js.map +1 -1
  203. package/dist/pipeline/generate-with-repair.js.map +1 -1
  204. package/dist/pipeline/pipeline-runner.d.ts +63 -4
  205. package/dist/pipeline/pipeline-runner.js +159 -50
  206. package/dist/pipeline/pipeline-runner.js.map +1 -1
  207. package/dist/pipeline/pipeline-shared.d.ts +32 -3
  208. package/dist/pipeline/pipeline-shared.js +76 -8
  209. package/dist/pipeline/pipeline-shared.js.map +1 -1
  210. package/dist/pipeline/refresh-lists.js +3 -5
  211. package/dist/pipeline/refresh-lists.js.map +1 -1
  212. package/dist/pipeline/scenario-schema-validator.js.map +1 -1
  213. package/dist/{mux → pty}/pty-bridge.d.ts +41 -3
  214. package/dist/{mux → pty}/pty-bridge.js +71 -18
  215. package/dist/pty/pty-bridge.js.map +1 -0
  216. package/dist/pty/resolve-ironcurtain-bin.d.ts +17 -0
  217. package/dist/pty/resolve-ironcurtain-bin.js +22 -0
  218. package/dist/pty/resolve-ironcurtain-bin.js.map +1 -0
  219. package/dist/sandbox/index.d.ts +19 -4
  220. package/dist/sandbox/index.js +31 -18
  221. package/dist/sandbox/index.js.map +1 -1
  222. package/dist/servers/fetch-server.js +2 -0
  223. package/dist/servers/fetch-server.js.map +1 -1
  224. package/dist/session/index.d.ts +1 -1
  225. package/dist/session/index.js +20 -2
  226. package/dist/session/index.js.map +1 -1
  227. package/dist/session/preflight.d.ts +20 -35
  228. package/dist/session/preflight.js +92 -109
  229. package/dist/session/preflight.js.map +1 -1
  230. package/dist/session/resource-budget-tracker.js +8 -0
  231. package/dist/session/resource-budget-tracker.js.map +1 -1
  232. package/dist/session/session-manager.d.ts +7 -0
  233. package/dist/session/session-manager.js.map +1 -1
  234. package/dist/session/types.d.ts +23 -0
  235. package/dist/signal/bot-command.js +6 -1
  236. package/dist/signal/bot-command.js.map +1 -1
  237. package/dist/signal/setup-signal.js +1 -1
  238. package/dist/signal/setup-signal.js.map +1 -1
  239. package/dist/signal/signal-bot-daemon.d.ts +1 -0
  240. package/dist/signal/signal-bot-daemon.js +9 -2
  241. package/dist/signal/signal-bot-daemon.js.map +1 -1
  242. package/dist/signal/signal-container.d.ts +3 -3
  243. package/dist/signal/signal-container.js +2 -2
  244. package/dist/signal/signal-container.js.map +1 -1
  245. package/dist/trusted-process/call-circuit-breaker.d.ts +6 -0
  246. package/dist/trusted-process/call-circuit-breaker.js +22 -3
  247. package/dist/trusted-process/call-circuit-breaker.js.map +1 -1
  248. package/dist/trusted-process/container-command.d.ts +35 -0
  249. package/dist/trusted-process/container-command.js +49 -0
  250. package/dist/trusted-process/container-command.js.map +1 -0
  251. package/dist/trusted-process/mcp-error-utils.js +4 -1
  252. package/dist/trusted-process/mcp-error-utils.js.map +1 -1
  253. package/dist/trusted-process/mcp-proxy-server.js +37 -3
  254. package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
  255. package/dist/trusted-process/policy-engine.js +13 -2
  256. package/dist/trusted-process/policy-engine.js.map +1 -1
  257. package/dist/trusted-process/tcp-server-transport.d.ts +19 -1
  258. package/dist/trusted-process/tcp-server-transport.js +56 -10
  259. package/dist/trusted-process/tcp-server-transport.js.map +1 -1
  260. package/dist/trusted-process/tool-call-coordinator.d.ts +22 -8
  261. package/dist/trusted-process/tool-call-coordinator.js +149 -65
  262. package/dist/trusted-process/tool-call-coordinator.js.map +1 -1
  263. package/dist/trusted-process/tool-call-pipeline.d.ts +8 -0
  264. package/dist/trusted-process/tool-call-pipeline.js +68 -34
  265. package/dist/trusted-process/tool-call-pipeline.js.map +1 -1
  266. package/dist/util/atomic-write.d.ts +31 -0
  267. package/dist/util/atomic-write.js +43 -0
  268. package/dist/util/atomic-write.js.map +1 -0
  269. package/dist/utils/preflight-checks.js +1 -3
  270. package/dist/utils/preflight-checks.js.map +1 -1
  271. package/dist/utils/stdio-guard.d.ts +1 -0
  272. package/dist/utils/stdio-guard.js +27 -0
  273. package/dist/utils/stdio-guard.js.map +1 -0
  274. package/dist/web-ui/__tests__/config-dispatch.test.d.ts +13 -0
  275. package/dist/web-ui/__tests__/config-dispatch.test.js +383 -0
  276. package/dist/web-ui/__tests__/config-dispatch.test.js.map +1 -0
  277. package/dist/web-ui/__tests__/json-rpc-dispatch.test.js +6 -0
  278. package/dist/web-ui/__tests__/json-rpc-dispatch.test.js.map +1 -1
  279. package/dist/web-ui/conn-registry.d.ts +14 -0
  280. package/dist/web-ui/conn-registry.js +25 -0
  281. package/dist/web-ui/conn-registry.js.map +1 -0
  282. package/dist/web-ui/dispatch/config-dispatch.d.ts +15 -0
  283. package/dist/web-ui/dispatch/config-dispatch.js +277 -0
  284. package/dist/web-ui/dispatch/config-dispatch.js.map +1 -0
  285. package/dist/web-ui/dispatch/escalation-dispatch.js +11 -2
  286. package/dist/web-ui/dispatch/escalation-dispatch.js.map +1 -1
  287. package/dist/web-ui/dispatch/persona-dispatch.d.ts +46 -2
  288. package/dist/web-ui/dispatch/persona-dispatch.js +209 -56
  289. package/dist/web-ui/dispatch/persona-dispatch.js.map +1 -1
  290. package/dist/web-ui/dispatch/pty-dispatch.d.ts +15 -0
  291. package/dist/web-ui/dispatch/pty-dispatch.js +66 -0
  292. package/dist/web-ui/dispatch/pty-dispatch.js.map +1 -0
  293. package/dist/web-ui/dispatch/session-dispatch.js +89 -6
  294. package/dist/web-ui/dispatch/session-dispatch.js.map +1 -1
  295. package/dist/web-ui/dispatch/types.d.ts +35 -0
  296. package/dist/web-ui/dispatch/types.js +42 -1
  297. package/dist/web-ui/dispatch/types.js.map +1 -1
  298. package/dist/web-ui/dispatch/workflow-dispatch.js +116 -5
  299. package/dist/web-ui/dispatch/workflow-dispatch.js.map +1 -1
  300. package/dist/web-ui/json-rpc-dispatch.js +4 -1
  301. package/dist/web-ui/json-rpc-dispatch.js.map +1 -1
  302. package/dist/web-ui/pty-session-manager.d.ts +234 -0
  303. package/dist/web-ui/pty-session-manager.js +599 -0
  304. package/dist/web-ui/pty-session-manager.js.map +1 -0
  305. package/dist/web-ui/web-event-bus.d.ts +34 -1
  306. package/dist/web-ui/web-event-bus.js.map +1 -1
  307. package/dist/web-ui/web-session-transport.js.map +1 -1
  308. package/dist/web-ui/web-ui-server.d.ts +22 -0
  309. package/dist/web-ui/web-ui-server.js +41 -0
  310. package/dist/web-ui/web-ui-server.js.map +1 -1
  311. package/dist/web-ui/web-ui-types.d.ts +212 -5
  312. package/dist/web-ui/web-ui-types.js.map +1 -1
  313. package/dist/web-ui-static/assets/index-CCVI4nEK.css +1 -0
  314. package/dist/web-ui-static/assets/index-Dm012gvY.js +114 -0
  315. package/dist/web-ui-static/index.html +2 -2
  316. package/dist/workflow/cli-shared.d.ts +62 -0
  317. package/dist/workflow/cli-shared.js +117 -0
  318. package/dist/workflow/cli-shared.js.map +1 -0
  319. package/dist/workflow/cli-support.js +0 -2
  320. package/dist/workflow/cli-support.js.map +1 -1
  321. package/dist/workflow/container-snapshots.d.ts +29 -0
  322. package/dist/workflow/container-snapshots.js +137 -0
  323. package/dist/workflow/container-snapshots.js.map +1 -0
  324. package/dist/workflow/daemon-gate-commands.d.ts +21 -0
  325. package/dist/workflow/daemon-gate-commands.js +595 -0
  326. package/dist/workflow/daemon-gate-commands.js.map +1 -0
  327. package/dist/workflow/discovery.d.ts +29 -0
  328. package/dist/workflow/discovery.js +67 -7
  329. package/dist/workflow/discovery.js.map +1 -1
  330. package/dist/workflow/lane-template.d.ts +89 -0
  331. package/dist/workflow/lane-template.js +141 -0
  332. package/dist/workflow/lane-template.js.map +1 -0
  333. package/dist/workflow/lint.d.ts +7 -1
  334. package/dist/workflow/lint.js +186 -3
  335. package/dist/workflow/lint.js.map +1 -1
  336. package/dist/workflow/machine-builder.d.ts +90 -2
  337. package/dist/workflow/machine-builder.js +222 -29
  338. package/dist/workflow/machine-builder.js.map +1 -1
  339. package/dist/workflow/message-log.d.ts +15 -1
  340. package/dist/workflow/message-log.js.map +1 -1
  341. package/dist/workflow/orchestrator.d.ts +505 -1
  342. package/dist/workflow/orchestrator.js +1725 -69
  343. package/dist/workflow/orchestrator.js.map +1 -1
  344. package/dist/workflow/prompt-builder.js +2 -1
  345. package/dist/workflow/prompt-builder.js.map +1 -1
  346. package/dist/workflow/run-state-command.js +1 -1
  347. package/dist/workflow/run-state-command.js.map +1 -1
  348. package/dist/workflow/shutdown-signals.d.ts +7 -0
  349. package/dist/workflow/shutdown-signals.js +40 -0
  350. package/dist/workflow/shutdown-signals.js.map +1 -0
  351. package/dist/workflow/status-parser.js +19 -4
  352. package/dist/workflow/status-parser.js.map +1 -1
  353. package/dist/workflow/types.d.ts +123 -23
  354. package/dist/workflow/types.js +2 -0
  355. package/dist/workflow/types.js.map +1 -1
  356. package/dist/workflow/validate.d.ts +23 -1
  357. package/dist/workflow/validate.js +311 -22
  358. package/dist/workflow/validate.js.map +1 -1
  359. package/dist/workflow/workflow-command.d.ts +0 -17
  360. package/dist/workflow/workflow-command.js +118 -94
  361. package/dist/workflow/workflow-command.js.map +1 -1
  362. package/dist/workflow/workflow-discovery.d.ts +2 -0
  363. package/dist/workflow/workflow-discovery.js +22 -1
  364. package/dist/workflow/workflow-discovery.js.map +1 -1
  365. package/dist/workflow/workflow-manager.d.ts +34 -0
  366. package/dist/workflow/workflow-manager.js +52 -1
  367. package/dist/workflow/workflow-manager.js.map +1 -1
  368. package/dist/workflow/workflows/design-and-code/README.md +50 -0
  369. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/format_report.js +29 -0
  370. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/package.json +5 -0
  371. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/requirements.txt +1 -0
  372. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/run_eval.py +41 -0
  373. package/dist/workflow/workflows/deterministic-eval-smoke/workflow.yaml +57 -0
  374. package/dist/workflow/workflows/deterministic-verdict-smoke/scripts/classify.py +18 -0
  375. package/dist/workflow/workflows/deterministic-verdict-smoke/workflow.yaml +51 -0
  376. package/dist/workflow/workflows/evolve/README.md +66 -0
  377. package/dist/workflow/workflows/evolve/scripts/LICENSE +201 -0
  378. package/dist/workflow/workflows/evolve/scripts/README.md +314 -0
  379. package/dist/workflow/workflows/evolve/scripts/evolve-brief +16 -0
  380. package/dist/workflow/workflows/evolve/scripts/evolve-cognition +16 -0
  381. package/dist/workflow/workflows/evolve/scripts/evolve-db +16 -0
  382. package/dist/workflow/workflows/evolve/scripts/evolve-eval +16 -0
  383. package/dist/workflow/workflows/evolve/scripts/evolve-files +16 -0
  384. package/dist/workflow/workflows/evolve/scripts/evolve-summary +16 -0
  385. package/dist/workflow/workflows/evolve/scripts/evolve_core/__init__.py +14 -0
  386. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/__init__.py +17 -0
  387. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/base.py +21 -0
  388. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/factory.py +90 -0
  389. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/greedy.py +17 -0
  390. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/island.py +316 -0
  391. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/random.py +18 -0
  392. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/ucb1.py +55 -0
  393. package/dist/workflow/workflows/evolve/scripts/evolve_core/best_snapshot.py +62 -0
  394. package/dist/workflow/workflows/evolve/scripts/evolve_core/cli.py +752 -0
  395. package/dist/workflow/workflows/evolve/scripts/evolve_core/cognition.py +127 -0
  396. package/dist/workflow/workflows/evolve/scripts/evolve_core/database.py +218 -0
  397. package/dist/workflow/workflows/evolve/scripts/evolve_core/diff.py +57 -0
  398. package/dist/workflow/workflows/evolve/scripts/evolve_core/embedding.py +84 -0
  399. package/dist/workflow/workflows/evolve/scripts/evolve_core/file_lock.py +45 -0
  400. package/dist/workflow/workflows/evolve/scripts/evolve_core/run_state.py +343 -0
  401. package/dist/workflow/workflows/evolve/scripts/evolve_core/sampling_config.py +173 -0
  402. package/dist/workflow/workflows/evolve/scripts/evolve_core/structures.py +93 -0
  403. package/dist/workflow/workflows/evolve/scripts/evolve_core/vector_index.py +191 -0
  404. package/dist/workflow/workflows/evolve/scripts/evolve_result.py +1503 -0
  405. package/dist/workflow/workflows/evolve/scripts/requirements.txt +2 -0
  406. package/dist/workflow/workflows/evolve/workflow.yaml +646 -0
  407. package/dist/workflow/workflows/test-email-summary/workflow.yaml +1 -0
  408. package/dist/workflow/workflows/vuln-discovery/README.md +54 -0
  409. package/dist/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +6 -1
  410. package/dist/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +1 -0
  411. package/dist/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +4 -0
  412. package/dist/workflow/workflows/vuln-discovery/workflow.yaml +13 -8
  413. package/docker/Dockerfile.base +22 -0
  414. package/docker/Dockerfile.base.arm64 +18 -0
  415. package/docker/Dockerfile.claude-code +3 -1
  416. package/docker/Dockerfile.codex +17 -0
  417. package/docker/Dockerfile.goose +3 -1
  418. package/docker/entrypoint-claude-code.sh +28 -45
  419. package/docker/entrypoint-codex.sh +42 -0
  420. package/docker/entrypoint-goose.sh +5 -24
  421. package/docker/entrypoint-uid-remap.sh +93 -0
  422. package/package.json +39 -30
  423. package/src/workflow/workflows/design-and-code/README.md +50 -0
  424. package/src/workflow/workflows/deterministic-eval-smoke/scripts/format_report.js +29 -0
  425. package/src/workflow/workflows/deterministic-eval-smoke/scripts/package.json +5 -0
  426. package/src/workflow/workflows/deterministic-eval-smoke/scripts/requirements.txt +1 -0
  427. package/src/workflow/workflows/deterministic-eval-smoke/scripts/run_eval.py +41 -0
  428. package/src/workflow/workflows/deterministic-eval-smoke/workflow.yaml +57 -0
  429. package/src/workflow/workflows/deterministic-verdict-smoke/scripts/classify.py +18 -0
  430. package/src/workflow/workflows/deterministic-verdict-smoke/workflow.yaml +51 -0
  431. package/src/workflow/workflows/evolve/README.md +66 -0
  432. package/src/workflow/workflows/evolve/scripts/LICENSE +201 -0
  433. package/src/workflow/workflows/evolve/scripts/README.md +314 -0
  434. package/src/workflow/workflows/evolve/scripts/evolve-brief +16 -0
  435. package/src/workflow/workflows/evolve/scripts/evolve-cognition +16 -0
  436. package/src/workflow/workflows/evolve/scripts/evolve-db +16 -0
  437. package/src/workflow/workflows/evolve/scripts/evolve-eval +16 -0
  438. package/src/workflow/workflows/evolve/scripts/evolve-files +16 -0
  439. package/src/workflow/workflows/evolve/scripts/evolve-summary +16 -0
  440. package/src/workflow/workflows/evolve/scripts/evolve_core/__init__.py +14 -0
  441. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/__init__.py +17 -0
  442. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/base.py +21 -0
  443. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/factory.py +90 -0
  444. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/greedy.py +17 -0
  445. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/island.py +316 -0
  446. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/random.py +18 -0
  447. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/ucb1.py +55 -0
  448. package/src/workflow/workflows/evolve/scripts/evolve_core/best_snapshot.py +62 -0
  449. package/src/workflow/workflows/evolve/scripts/evolve_core/cli.py +752 -0
  450. package/src/workflow/workflows/evolve/scripts/evolve_core/cognition.py +127 -0
  451. package/src/workflow/workflows/evolve/scripts/evolve_core/database.py +218 -0
  452. package/src/workflow/workflows/evolve/scripts/evolve_core/diff.py +57 -0
  453. package/src/workflow/workflows/evolve/scripts/evolve_core/embedding.py +84 -0
  454. package/src/workflow/workflows/evolve/scripts/evolve_core/file_lock.py +45 -0
  455. package/src/workflow/workflows/evolve/scripts/evolve_core/run_state.py +343 -0
  456. package/src/workflow/workflows/evolve/scripts/evolve_core/sampling_config.py +173 -0
  457. package/src/workflow/workflows/evolve/scripts/evolve_core/structures.py +93 -0
  458. package/src/workflow/workflows/evolve/scripts/evolve_core/vector_index.py +191 -0
  459. package/src/workflow/workflows/evolve/scripts/evolve_result.py +1503 -0
  460. package/src/workflow/workflows/evolve/scripts/requirements.txt +2 -0
  461. package/src/workflow/workflows/evolve/workflow.yaml +646 -0
  462. package/src/workflow/workflows/test-email-summary/workflow.yaml +1 -0
  463. package/src/workflow/workflows/vuln-discovery/README.md +54 -0
  464. package/src/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +6 -1
  465. package/src/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +1 -0
  466. package/src/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +4 -0
  467. package/src/workflow/workflows/vuln-discovery/workflow.yaml +13 -8
  468. package/dist/mux/pty-bridge.js.map +0 -1
  469. package/dist/mux/trusted-input.js.map +0 -1
  470. package/dist/web-ui-static/assets/index-BFO5z1js.js +0 -76
  471. package/dist/web-ui-static/assets/index-CCUwrkIL.css +0 -1
  472. package/packages/web-ui/README.md +0 -113
@@ -0,0 +1,343 @@
1
+ """Run-spec persistence, preflight gating, and path guards."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ import json
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+ from typing import Any, Dict, Iterable, List, Optional
10
+
11
+ import yaml
12
+
13
+ from .sampling_config import (
14
+ DEFAULT_ISLAND_FEATURE_BINS,
15
+ DEFAULT_ISLAND_FEATURE_DIMENSIONS,
16
+ sampling_summary_lines,
17
+ validate_custom_sampler_for_workspace as validate_sampling_custom_sampler_for_workspace,
18
+ )
19
+
20
+
21
+ DEFAULT_RUN_SPEC: Dict[str, Any] = {
22
+ "objective": "",
23
+ "evaluation": {
24
+ "core_score": "",
25
+ "secondary_metrics": [],
26
+ "command": "",
27
+ "script_path": "",
28
+ "timeout_secs": 0,
29
+ "success_criteria": [],
30
+ },
31
+ "budget": {
32
+ "max_rounds": 0,
33
+ "patience": 0,
34
+ },
35
+ "stop_conditions": [],
36
+ "mutation_scope": {
37
+ "writable_paths": [],
38
+ "primary_targets": [],
39
+ },
40
+ "sampling": {
41
+ "algorithm": "ucb1",
42
+ "sample_n": 3,
43
+ "feature_dimensions": list(DEFAULT_ISLAND_FEATURE_DIMENSIONS),
44
+ "feature_bins": DEFAULT_ISLAND_FEATURE_BINS,
45
+ "custom_sampler_path": "",
46
+ "custom_sampler_class": "",
47
+ },
48
+ "cognition": {
49
+ "source_mode": "",
50
+ "seed_files": [],
51
+ "seed_notes": [],
52
+ },
53
+ "approval": {
54
+ "confirmed": False,
55
+ },
56
+ }
57
+
58
+ REQUIRED_FIELD_CHECKS = {
59
+ "objective": lambda spec: bool(str(spec.get("objective", "")).strip()),
60
+ "evaluation.core_score": lambda spec: bool(
61
+ str(spec.get("evaluation", {}).get("core_score", "")).strip()
62
+ ),
63
+ "evaluation.command_or_script": lambda spec: bool(
64
+ str(spec.get("evaluation", {}).get("command", "")).strip()
65
+ or str(spec.get("evaluation", {}).get("script_path", "")).strip()
66
+ ),
67
+ "evaluation.timeout_secs": lambda spec: int(
68
+ spec.get("evaluation", {}).get("timeout_secs", 0) or 0
69
+ )
70
+ > 0,
71
+ "evaluation.success_criteria": lambda spec: bool(
72
+ spec.get("evaluation", {}).get("success_criteria")
73
+ ),
74
+ "budget.max_rounds": lambda spec: int(spec.get("budget", {}).get("max_rounds", 0) or 0)
75
+ > 0,
76
+ "budget.patience": lambda spec: int(spec.get("budget", {}).get("patience", 0) or 0) >= 0,
77
+ "stop_conditions": lambda spec: bool(spec.get("stop_conditions")),
78
+ "mutation_scope.writable_paths": lambda spec: bool(
79
+ spec.get("mutation_scope", {}).get("writable_paths")
80
+ ),
81
+ "mutation_scope.primary_targets": lambda spec: bool(
82
+ spec.get("mutation_scope", {}).get("primary_targets")
83
+ ),
84
+ "sampling.algorithm": lambda spec: bool(
85
+ str(spec.get("sampling", {}).get("algorithm", "")).strip()
86
+ ),
87
+ "sampling.sample_n": lambda spec: int(spec.get("sampling", {}).get("sample_n", 0) or 0) > 0,
88
+ "sampling.custom_sampler": lambda spec: (
89
+ str(spec.get("sampling", {}).get("algorithm", "")).strip() != "custom"
90
+ or (
91
+ bool(str(spec.get("sampling", {}).get("custom_sampler_path", "")).strip())
92
+ and bool(str(spec.get("sampling", {}).get("custom_sampler_class", "")).strip())
93
+ )
94
+ ),
95
+ "cognition.source_mode": lambda spec: bool(
96
+ str(spec.get("cognition", {}).get("source_mode", "")).strip()
97
+ ),
98
+ }
99
+
100
+
101
+ def default_run_spec() -> Dict[str, Any]:
102
+ return copy.deepcopy(DEFAULT_RUN_SPEC)
103
+
104
+
105
+ def deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
106
+ merged = copy.deepcopy(base)
107
+ for key, value in override.items():
108
+ if isinstance(value, dict) and isinstance(merged.get(key), dict):
109
+ merged[key] = deep_merge(merged[key], value)
110
+ else:
111
+ merged[key] = copy.deepcopy(value)
112
+ return merged
113
+
114
+
115
+ def build_run_dir(workspace_root: Path, run_name: str) -> Path:
116
+ return Path(workspace_root).resolve() / ".evolve_runs" / run_name
117
+
118
+
119
+ def ensure_run_layout(run_dir: Path) -> Dict[str, Path]:
120
+ run_dir = Path(run_dir).resolve()
121
+ layout = {
122
+ "run_dir": run_dir,
123
+ "best": run_dir / "best",
124
+ "cognition_data": run_dir / "cognition_data",
125
+ "database_data": run_dir / "database_data",
126
+ "steps": run_dir / "steps",
127
+ }
128
+ run_dir.mkdir(parents=True, exist_ok=True)
129
+ for path in layout.values():
130
+ path.mkdir(parents=True, exist_ok=True)
131
+ round_log = run_dir / "round_log.jsonl"
132
+ if not round_log.exists():
133
+ round_log.write_text("", encoding="utf-8")
134
+ return layout
135
+
136
+
137
+ def workspace_root_for_run(run_dir: Path) -> Path:
138
+ run_dir = Path(run_dir).resolve()
139
+ return run_dir.parent.parent
140
+
141
+
142
+ def spec_path(run_dir: Path) -> Path:
143
+ return Path(run_dir) / "run_spec.yaml"
144
+
145
+
146
+ def load_run_spec(run_dir: Path) -> Dict[str, Any]:
147
+ path = spec_path(run_dir)
148
+ if not path.exists():
149
+ return default_run_spec()
150
+ with open(path, "r", encoding="utf-8") as handle:
151
+ loaded = yaml.safe_load(handle) or {}
152
+ return deep_merge(default_run_spec(), loaded)
153
+
154
+
155
+ def save_run_spec(run_dir: Path, spec: Dict[str, Any]) -> Path:
156
+ path = spec_path(run_dir)
157
+ with open(path, "w", encoding="utf-8") as handle:
158
+ yaml.safe_dump(spec, handle, allow_unicode=True, sort_keys=False)
159
+ return path
160
+
161
+
162
+ def normalize_spec_path(workspace_root: Path, raw_path: str) -> str:
163
+ path = Path(raw_path)
164
+ if not path.is_absolute():
165
+ return raw_path.replace("\\", "/")
166
+
167
+ resolved = path.resolve()
168
+ workspace_root = Path(workspace_root).resolve()
169
+ try:
170
+ return resolved.relative_to(workspace_root).as_posix()
171
+ except ValueError:
172
+ return str(resolved)
173
+
174
+
175
+ def resolve_path(workspace_root: Path, raw_path: str) -> Path:
176
+ path = Path(raw_path)
177
+ if path.is_absolute():
178
+ return path.resolve()
179
+ return (Path(workspace_root).resolve() / path).resolve()
180
+
181
+
182
+ def compute_missing_fields(spec: Dict[str, Any]) -> List[str]:
183
+ return compute_missing_fields_for_workspace(spec)
184
+
185
+
186
+ def compute_missing_fields_for_workspace(
187
+ spec: Dict[str, Any],
188
+ workspace_root: Optional[Path] = None,
189
+ ) -> List[str]:
190
+ missing = []
191
+ for field, check in REQUIRED_FIELD_CHECKS.items():
192
+ if not check(spec):
193
+ missing.append(field)
194
+ custom_sampler_error = validate_custom_sampler_for_workspace(spec, workspace_root)
195
+ if custom_sampler_error:
196
+ missing.append("sampling.custom_sampler_valid")
197
+ return missing
198
+
199
+
200
+ def validate_custom_sampler_for_workspace(
201
+ spec: Dict[str, Any],
202
+ workspace_root: Optional[Path] = None,
203
+ ) -> str:
204
+ return validate_sampling_custom_sampler_for_workspace(spec, workspace_root)
205
+
206
+
207
+ def write_preflight_summary(run_dir: Path, spec: Dict[str, Any]) -> Path:
208
+ workspace_root = workspace_root_for_run(run_dir)
209
+ missing = compute_missing_fields_for_workspace(spec, workspace_root)
210
+ confirmed = bool(spec.get("approval", {}).get("confirmed", False))
211
+ status = "READY" if confirmed and not missing else "PENDING"
212
+ lines = [
213
+ "# Preflight Summary",
214
+ "",
215
+ f"- Status: `{status}`",
216
+ f"- Objective: {spec.get('objective', '') or '(missing)'}",
217
+ f"- Core score: {spec.get('evaluation', {}).get('core_score', '') or '(missing)'}",
218
+ f"- Secondary metrics: {', '.join(spec.get('evaluation', {}).get('secondary_metrics', [])) or '(none)'}",
219
+ f"- Evaluation command: {spec.get('evaluation', {}).get('command', '') or '(missing)'}",
220
+ f"- Evaluation script: {spec.get('evaluation', {}).get('script_path', '') or '(missing)'}",
221
+ f"- Evaluation timeout (s): {spec.get('evaluation', {}).get('timeout_secs', 0) or '(missing)'}",
222
+ f"- Success criteria: {', '.join(spec.get('evaluation', {}).get('success_criteria', [])) or '(missing)'}",
223
+ f"- Budget: max_rounds={spec.get('budget', {}).get('max_rounds', 0)}, patience={spec.get('budget', {}).get('patience', 0)}",
224
+ f"- Stop conditions: {', '.join(spec.get('stop_conditions', [])) or '(missing)'}",
225
+ f"- Writable paths: {', '.join(spec.get('mutation_scope', {}).get('writable_paths', [])) or '(missing)'}",
226
+ f"- Primary targets: {', '.join(spec.get('mutation_scope', {}).get('primary_targets', [])) or '(missing)'}",
227
+ *sampling_summary_lines(spec, workspace_root),
228
+ f"- Cognition source mode: {spec.get('cognition', {}).get('source_mode', '') or '(missing)'}",
229
+ f"- Cognition seed files: {', '.join(spec.get('cognition', {}).get('seed_files', [])) or '(none)'}",
230
+ f"- Cognition seed notes: {', '.join(spec.get('cognition', {}).get('seed_notes', [])) or '(none)'}",
231
+ f"- Approval confirmed: {confirmed}",
232
+ ]
233
+ lines.extend(
234
+ [
235
+ "",
236
+ "## Missing fields",
237
+ ]
238
+ )
239
+ if missing:
240
+ lines.extend([f"- {field}" for field in missing])
241
+ else:
242
+ lines.append("- none")
243
+
244
+ path = Path(run_dir) / "preflight_summary.md"
245
+ path.write_text("\n".join(lines) + "\n", encoding="utf-8")
246
+ return path
247
+
248
+
249
+ def initialize_cognition_seed_file(run_dir: Path, spec: Dict[str, Any]) -> Path:
250
+ path = Path(run_dir) / "cognition_seed.md"
251
+ if path.exists():
252
+ return path
253
+
254
+ notes = spec.get("cognition", {}).get("seed_notes", [])
255
+ lines = [
256
+ "# Cognition Seed Draft",
257
+ "",
258
+ f"- source_mode: {spec.get('cognition', {}).get('source_mode', '') or 'pending'}",
259
+ "- Fill this file during preflight and keep the JSON blocks machine-readable.",
260
+ "",
261
+ "## Notes",
262
+ ]
263
+ if notes:
264
+ lines.extend([f"- {note}" for note in notes])
265
+ else:
266
+ lines.append("- Add user-provided or approved research notes here.")
267
+ lines.extend(
268
+ [
269
+ "",
270
+ "## JSON seeds",
271
+ "",
272
+ "```json",
273
+ "[",
274
+ ' {',
275
+ ' "content": "Replace this with a reusable heuristic or observation.",',
276
+ ' "source": "user",',
277
+ ' "metadata": {"kind": "heuristic"}',
278
+ " }",
279
+ "]",
280
+ "```",
281
+ "",
282
+ ]
283
+ )
284
+ path.write_text("\n".join(lines), encoding="utf-8")
285
+ return path
286
+
287
+
288
+ def require_evolve_ready(run_dir: Path) -> Dict[str, Any]:
289
+ spec = load_run_spec(run_dir)
290
+ missing = compute_missing_fields_for_workspace(spec, workspace_root_for_run(run_dir))
291
+ if missing:
292
+ raise ValueError(
293
+ "Preflight is incomplete. Missing fields: " + ", ".join(missing)
294
+ )
295
+ if not spec.get("approval", {}).get("confirmed", False):
296
+ raise PermissionError("Preflight is not confirmed yet.")
297
+ return spec
298
+
299
+
300
+ def ensure_path_allowed(run_dir: Path, target_path: Path) -> Path:
301
+ spec = load_run_spec(run_dir)
302
+ run_dir = Path(run_dir).resolve()
303
+ target_path = Path(target_path).resolve()
304
+
305
+ if target_path.is_relative_to(run_dir):
306
+ return target_path
307
+
308
+ workspace_root = workspace_root_for_run(run_dir)
309
+ allowed_paths = spec.get("mutation_scope", {}).get("writable_paths", [])
310
+ resolved_roots = [resolve_path(workspace_root, raw_path) for raw_path in allowed_paths]
311
+
312
+ for allowed_root in resolved_roots:
313
+ if target_path.is_relative_to(allowed_root):
314
+ return target_path
315
+
316
+ raise PermissionError(
317
+ f"Path is outside the approved mutation scope: {target_path}"
318
+ )
319
+
320
+
321
+ def append_round_log(run_dir: Path, event: str, payload: Dict[str, Any]) -> Path:
322
+ entry = {
323
+ "timestamp": datetime.now().isoformat(),
324
+ "event": event,
325
+ "payload": payload,
326
+ }
327
+ path = Path(run_dir) / "round_log.jsonl"
328
+ with open(path, "a", encoding="utf-8") as handle:
329
+ handle.write(json.dumps(entry, ensure_ascii=False) + "\n")
330
+ return path
331
+
332
+
333
+ def load_structured_file(path: Path) -> Dict[str, Any]:
334
+ path = Path(path)
335
+ if path.suffix.lower() == ".json":
336
+ return json.loads(path.read_text(encoding="utf-8"))
337
+ return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
338
+
339
+
340
+ def flatten_list(values: Iterable[str] | None) -> List[str]:
341
+ if not values:
342
+ return []
343
+ return [value for value in values if value]
@@ -0,0 +1,173 @@
1
+ """Shared helpers for run-level sampling configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any, Dict, List, Optional, Tuple
8
+
9
+ from .algorithms.factory import load_custom_sampler_class
10
+
11
+
12
+ DEFAULT_SAMPLING_ALGORITHM = "ucb1"
13
+ DEFAULT_SAMPLE_N = 3
14
+ DEFAULT_ISLAND_FEATURE_DIMENSIONS = ["complexity", "diversity"]
15
+ DEFAULT_ISLAND_FEATURE_BINS = 10
16
+ SAMPLING_CONFIG_IMMUTABLE_ERROR = (
17
+ "Sampling configuration is run-level and cannot change after nodes exist. "
18
+ "Start a new run if you want a different algorithm or island feature setup."
19
+ )
20
+
21
+
22
+ def _sampling_section(spec: Dict[str, Any]) -> Dict[str, Any]:
23
+ return spec.get("sampling", {})
24
+
25
+
26
+ def _sampling_algorithm_value(spec: Dict[str, Any]) -> str:
27
+ return str(_sampling_section(spec).get("algorithm", "") or "").strip()
28
+
29
+
30
+ def configured_sampling_algorithm(spec: Dict[str, Any]) -> str:
31
+ return _sampling_algorithm_value(spec) or DEFAULT_SAMPLING_ALGORITHM
32
+
33
+
34
+ def configured_sample_n(spec: Dict[str, Any]) -> int:
35
+ return int(_sampling_section(spec).get("sample_n", DEFAULT_SAMPLE_N) or DEFAULT_SAMPLE_N)
36
+
37
+
38
+ def sampling_config_fingerprint(spec: Dict[str, Any]) -> Dict[str, Any]:
39
+ sampling = _sampling_section(spec)
40
+ return {
41
+ "algorithm": sampling.get("algorithm", DEFAULT_SAMPLING_ALGORITHM),
42
+ "feature_dimensions": list(
43
+ sampling.get("feature_dimensions", []) or DEFAULT_ISLAND_FEATURE_DIMENSIONS
44
+ ),
45
+ "feature_bins": int(sampling.get("feature_bins", DEFAULT_ISLAND_FEATURE_BINS) or DEFAULT_ISLAND_FEATURE_BINS),
46
+ "custom_sampler_path": str(sampling.get("custom_sampler_path", "") or ""),
47
+ "custom_sampler_class": str(sampling.get("custom_sampler_class", "") or ""),
48
+ }
49
+
50
+
51
+ def run_has_recorded_nodes(run_dir: Path) -> bool:
52
+ data_file = Path(run_dir) / "database_data" / "nodes.json"
53
+ if not data_file.exists():
54
+ return False
55
+ try:
56
+ payload = json.loads(data_file.read_text(encoding="utf-8"))
57
+ except json.JSONDecodeError:
58
+ return True
59
+ return bool(payload.get("nodes", {}))
60
+
61
+
62
+ def resolve_sampling_path(workspace_root: Path, raw_path: str) -> Path:
63
+ path = Path(raw_path)
64
+ if path.is_absolute():
65
+ return path.resolve()
66
+ return (Path(workspace_root).resolve() / path).resolve()
67
+
68
+
69
+ def custom_sampler_runtime_config(
70
+ spec: Dict[str, Any],
71
+ workspace_root: Optional[Path] = None,
72
+ ) -> Dict[str, Any]:
73
+ sampling = _sampling_section(spec)
74
+ custom_path = str(sampling.get("custom_sampler_path", "") or "").strip()
75
+ custom_class = str(sampling.get("custom_sampler_class", "") or "").strip()
76
+ if not custom_path:
77
+ return {}
78
+
79
+ resolved_path = (
80
+ resolve_sampling_path(Path(workspace_root), custom_path)
81
+ if workspace_root is not None
82
+ else Path(custom_path).resolve()
83
+ )
84
+ search_paths = [str(resolved_path.parent)]
85
+ if workspace_root is not None:
86
+ search_paths.append(str(Path(workspace_root).resolve()))
87
+ runtime_config: Dict[str, Any] = {
88
+ "custom_sampler_path": str(resolved_path),
89
+ "custom_sampler_search_paths": search_paths,
90
+ }
91
+ if custom_class:
92
+ runtime_config["custom_sampler_class"] = custom_class
93
+ return runtime_config
94
+
95
+
96
+ def build_database_sampling_config(
97
+ spec: Dict[str, Any],
98
+ workspace_root: Path,
99
+ ) -> Tuple[str, Dict[str, Any]]:
100
+ algorithm = configured_sampling_algorithm(spec)
101
+ if algorithm == "island":
102
+ return (
103
+ algorithm,
104
+ {
105
+ "feature_dimensions": list(
106
+ _sampling_section(spec).get("feature_dimensions")
107
+ or DEFAULT_ISLAND_FEATURE_DIMENSIONS
108
+ ),
109
+ "feature_bins": int(
110
+ _sampling_section(spec).get("feature_bins", DEFAULT_ISLAND_FEATURE_BINS)
111
+ or DEFAULT_ISLAND_FEATURE_BINS
112
+ ),
113
+ },
114
+ )
115
+ if algorithm == "custom":
116
+ return algorithm, custom_sampler_runtime_config(spec, workspace_root)
117
+ return algorithm, {}
118
+
119
+
120
+ def validate_custom_sampler_for_workspace(
121
+ spec: Dict[str, Any],
122
+ workspace_root: Optional[Path] = None,
123
+ ) -> str:
124
+ if configured_sampling_algorithm(spec) != "custom":
125
+ return ""
126
+
127
+ runtime_config = custom_sampler_runtime_config(spec, workspace_root)
128
+ custom_path = str(_sampling_section(spec).get("custom_sampler_path", "") or "").strip()
129
+ custom_class = str(_sampling_section(spec).get("custom_sampler_class", "") or "").strip()
130
+ if not custom_path or not custom_class:
131
+ return ""
132
+
133
+ try:
134
+ load_custom_sampler_class(
135
+ runtime_config["custom_sampler_path"],
136
+ custom_class,
137
+ search_paths=runtime_config.get("custom_sampler_search_paths"),
138
+ )
139
+ except Exception as exc: # pragma: no cover - surfaced validation path
140
+ return str(exc)
141
+ return ""
142
+
143
+
144
+ def sampling_summary_lines(
145
+ spec: Dict[str, Any],
146
+ workspace_root: Optional[Path] = None,
147
+ ) -> List[str]:
148
+ sampling = _sampling_section(spec)
149
+ sampling_algorithm = _sampling_algorithm_value(spec) or "(missing)"
150
+ lines = [
151
+ f"- Sampling algorithm: {sampling_algorithm}",
152
+ f"- Sample count: {sampling.get('sample_n', 0)}",
153
+ ]
154
+ if sampling_algorithm == "island":
155
+ feature_dimensions = sampling.get("feature_dimensions", []) or DEFAULT_ISLAND_FEATURE_DIMENSIONS
156
+ lines.extend(
157
+ [
158
+ f"- Island feature dimensions: {', '.join(feature_dimensions)}",
159
+ f"- Island feature bins: {sampling.get('feature_bins', DEFAULT_ISLAND_FEATURE_BINS)}",
160
+ "- Island built-ins: complexity=len(code), diversity=code-difference heuristic",
161
+ ]
162
+ )
163
+ elif sampling_algorithm == "custom":
164
+ lines.extend(
165
+ [
166
+ f"- Custom sampler path: {sampling.get('custom_sampler_path', '') or '(missing)'}",
167
+ f"- Custom sampler class: {sampling.get('custom_sampler_class', '') or '(missing)'}",
168
+ ]
169
+ )
170
+ custom_sampler_error = validate_custom_sampler_for_workspace(spec, workspace_root)
171
+ if custom_sampler_error:
172
+ lines.append(f"- Custom sampler validation error: {custom_sampler_error}")
173
+ return lines
@@ -0,0 +1,93 @@
1
+ """Core data structures for the Evolve skill runtime."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from datetime import datetime
7
+ from typing import Any, Dict, List, Optional
8
+
9
+
10
+ @dataclass
11
+ class Node:
12
+ """One recorded evolution node."""
13
+
14
+ name: str = ""
15
+ created_at: str = ""
16
+ parent: List[int] = field(default_factory=list)
17
+ motivation: str = ""
18
+ code: str = ""
19
+ results: Dict[str, Any] = field(default_factory=dict)
20
+ analysis: str = ""
21
+ meta_info: Dict[str, Any] = field(default_factory=dict)
22
+ id: Optional[int] = None
23
+ visit_count: int = 0
24
+ score: float = 0.0
25
+
26
+ def __post_init__(self) -> None:
27
+ if not self.created_at:
28
+ self.created_at = datetime.now().isoformat()
29
+
30
+ def to_dict(self) -> Dict[str, Any]:
31
+ return {
32
+ "id": self.id,
33
+ "name": self.name,
34
+ "created_at": self.created_at,
35
+ "parent": self.parent,
36
+ "motivation": self.motivation,
37
+ "code": self.code,
38
+ "results": self.results,
39
+ "analysis": self.analysis,
40
+ "meta_info": self.meta_info,
41
+ "visit_count": self.visit_count,
42
+ "score": self.score,
43
+ }
44
+
45
+ @classmethod
46
+ def from_dict(cls, data: Dict[str, Any]) -> "Node":
47
+ return cls(
48
+ id=data.get("id"),
49
+ name=data.get("name", ""),
50
+ created_at=data.get("created_at", ""),
51
+ parent=data.get("parent", []),
52
+ motivation=data.get("motivation", ""),
53
+ code=data.get("code", ""),
54
+ results=data.get("results", {}),
55
+ analysis=data.get("analysis", ""),
56
+ meta_info=data.get("meta_info", {}),
57
+ visit_count=data.get("visit_count", 0),
58
+ score=data.get("score", 0.0),
59
+ )
60
+
61
+ def get_context_text(self) -> str:
62
+ return " ".join(
63
+ value
64
+ for value in [self.name, self.motivation, self.analysis]
65
+ if value
66
+ )
67
+
68
+
69
+ @dataclass
70
+ class CognitionItem:
71
+ """One cognition item stored for semantic retrieval."""
72
+
73
+ content: str
74
+ source: str = ""
75
+ metadata: Dict[str, Any] = field(default_factory=dict)
76
+ id: Optional[str] = None
77
+
78
+ def to_dict(self) -> Dict[str, Any]:
79
+ return {
80
+ "id": self.id,
81
+ "content": self.content,
82
+ "source": self.source,
83
+ "metadata": self.metadata,
84
+ }
85
+
86
+ @classmethod
87
+ def from_dict(cls, data: Dict[str, Any]) -> "CognitionItem":
88
+ return cls(
89
+ id=data.get("id"),
90
+ content=data.get("content", ""),
91
+ source=data.get("source", ""),
92
+ metadata=data.get("metadata", {}),
93
+ )