vgxness 1.20.4 → 1.20.6

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 (375) hide show
  1. package/dist/adapters/claude/agent-renderer.js +82 -0
  2. package/dist/{mcp → adapters/claude/install}/claude-code-agent-config.js +64 -9
  3. package/dist/{mcp → adapters/claude/install}/claude-code-config.js +28 -6
  4. package/dist/{mcp → adapters/claude/install}/claude-code-project-memory.js +35 -5
  5. package/dist/{mcp → adapters/claude/install}/claude-code-scope.js +12 -3
  6. package/dist/{mcp → adapters/claude/install}/claude-code-user-config.js +26 -5
  7. package/dist/{mcp → adapters/claude/install}/claude-code-user-memory.js +47 -7
  8. package/dist/{mcp → adapters/claude/install}/client-install-claude-code-contract.js +45 -8
  9. package/dist/{mcp → adapters/claude/install}/client-install-claude-code.js +98 -14
  10. package/dist/adapters/json/agent-renderer.js +104 -0
  11. package/dist/adapters/opencode/agent-renderer.js +113 -0
  12. package/dist/{mcp → adapters/opencode/install}/client-install-opencode-contract.js +2 -2
  13. package/dist/{mcp → adapters/opencode/install}/client-install-opencode.js +1 -1
  14. package/dist/{mcp → adapters/opencode/install}/opencode-default-agent-config.js +2 -2
  15. package/dist/{mcp → adapters/opencode/install}/opencode-handoff-preview.js +60 -7
  16. package/dist/{mcp → adapters/opencode/install}/opencode-visibility.js +1 -1
  17. package/dist/adapters/provider-renderer.js +6 -0
  18. package/dist/agents/agent-activation-service.js +1 -263
  19. package/dist/agents/agent-lookup-contexts.js +1 -28
  20. package/dist/agents/agent-registry-service.js +1 -81
  21. package/dist/agents/agent-resolver.js +1 -287
  22. package/dist/agents/agent-seed-service.js +1 -157
  23. package/dist/agents/agent-seed-upgrade-service.js +1 -231
  24. package/dist/agents/agent-selector-resolver.js +1 -28
  25. package/dist/agents/boot-upgrade.js +1 -59
  26. package/dist/agents/canonical-agent-manifest.js +1 -245
  27. package/dist/agents/canonical-agent-projection.js +1 -236
  28. package/dist/agents/manager-profile-overlay-service.js +1 -60
  29. package/dist/agents/profile-model-routing.js +1 -30
  30. package/dist/agents/renderers/claude-renderer.js +1 -82
  31. package/dist/agents/renderers/index.js +1 -14
  32. package/dist/agents/renderers/json-renderer.js +1 -104
  33. package/dist/agents/renderers/opencode-renderer.js +1 -113
  34. package/dist/agents/renderers/provider-adapter.js +1 -6
  35. package/dist/agents/repositories/agent-seed-history.js +1 -128
  36. package/dist/agents/repositories/agents.js +1 -200
  37. package/dist/agents/repositories/manager-profile-overlays.js +1 -90
  38. package/dist/agents/schema.js +1 -1
  39. package/dist/application/agents/agent-activation-service.js +261 -0
  40. package/dist/application/agents/agent-lookup-contexts.js +28 -0
  41. package/dist/application/agents/agent-registry-service.js +81 -0
  42. package/dist/application/agents/agent-resolver.js +287 -0
  43. package/dist/application/agents/agent-seed-service.js +157 -0
  44. package/dist/application/agents/agent-seed-upgrade-service.js +231 -0
  45. package/dist/application/agents/agent-selector-resolver.js +28 -0
  46. package/dist/application/agents/boot-upgrade.js +59 -0
  47. package/dist/application/agents/canonical-agent-projection.js +236 -0
  48. package/dist/application/agents/manager-profile-overlay-service.js +68 -0
  49. package/dist/application/agents/profile-model-routing.js +30 -0
  50. package/dist/application/agents/renderers/claude-renderer.js +1 -0
  51. package/dist/application/agents/renderers/index.js +14 -0
  52. package/dist/application/agents/renderers/json-renderer.js +1 -0
  53. package/dist/application/agents/renderers/opencode-renderer.js +1 -0
  54. package/dist/application/agents/renderers/provider-adapter.js +1 -0
  55. package/dist/application/memory/active-work-preview.js +75 -0
  56. package/dist/application/memory/agent-memory-capture-service.js +498 -0
  57. package/dist/application/memory/import/dry-run-planner.js +58 -0
  58. package/dist/application/memory/import/index.js +3 -0
  59. package/dist/application/memory/import/observation-writer.js +226 -0
  60. package/dist/application/memory/import/package.js +179 -0
  61. package/dist/application/memory/memory-service.js +202 -0
  62. package/dist/application/memory/search.js +11 -0
  63. package/dist/{mcp → application/provider-setup}/provider-change-plan.js +74 -13
  64. package/dist/{mcp → application/provider-setup}/provider-doctor.js +201 -31
  65. package/dist/{mcp → application/provider-setup}/provider-health-types.js +1 -1
  66. package/dist/{mcp → application/provider-setup}/provider-status.js +170 -33
  67. package/dist/application/runs/execution-planning.js +180 -0
  68. package/dist/application/runs/operation-execution.js +1 -0
  69. package/dist/application/runs/operation-retry.js +129 -0
  70. package/dist/application/runs/resume-after-approval-result.js +88 -0
  71. package/dist/application/runs/run-insights.js +270 -0
  72. package/dist/application/runs/run-service.js +1480 -0
  73. package/dist/application/runs/run-snapshot-export-service.js +31 -0
  74. package/dist/application/runs/sandbox-process-execution.js +244 -0
  75. package/dist/application/runs/sandbox-worktree-planning.js +59 -0
  76. package/dist/application/runs/task-scoped-command-grant-service.js +224 -0
  77. package/dist/application/sdd/artifact-portability-service.js +137 -0
  78. package/dist/application/sdd/cockpit-read-model.js +195 -0
  79. package/dist/application/sdd/sdd-continuation-plan.js +265 -0
  80. package/dist/application/sdd/sdd-workflow-service.js +892 -0
  81. package/dist/application/skills/boot-seed.js +42 -0
  82. package/dist/application/skills/personal-skills.js +41 -0
  83. package/dist/application/skills/skill-export-service.js +34 -0
  84. package/dist/application/skills/skill-index-service.js +126 -0
  85. package/dist/application/skills/skill-payload.js +186 -0
  86. package/dist/application/skills/skill-registry-service.js +648 -0
  87. package/dist/application/skills/skill-resolver.js +368 -0
  88. package/dist/application/skills/skill-seed-service.js +242 -0
  89. package/dist/application/skills/skill-status-service.js +147 -0
  90. package/dist/cli/bun-bin.js +0 -0
  91. package/dist/cli/cli-flags.js +1 -387
  92. package/dist/cli/cli-help.js +1 -173
  93. package/dist/cli/cli-helpers.js +1 -77
  94. package/dist/cli/cli-types.js +1 -1
  95. package/dist/cli/commands/agent-skill-dispatcher.js +1 -700
  96. package/dist/cli/commands/index.js +1 -9
  97. package/dist/cli/commands/interactive-entrypoint-dispatcher.js +1 -14
  98. package/dist/cli/commands/mcp-dispatcher.js +1 -232
  99. package/dist/cli/commands/memory-sdd-dispatcher.js +1 -367
  100. package/dist/cli/commands/run-permission-dispatcher.js +1 -455
  101. package/dist/cli/commands/setup-dispatcher.js +1 -496
  102. package/dist/cli/commands/status-dispatcher.js +1 -130
  103. package/dist/cli/commands/verification-dispatcher.js +1 -47
  104. package/dist/cli/commands/workflow-dispatcher.js +1 -566
  105. package/dist/cli/dispatcher.js +1 -247
  106. package/dist/cli/doctor-renderer.js +1 -26
  107. package/dist/cli/home-tui-app.js +1 -411
  108. package/dist/cli/home-tui-controller.js +1 -314
  109. package/dist/cli/mcp-start-path.js +1 -21
  110. package/dist/cli/product-resume-renderer.js +1 -32
  111. package/dist/cli/product-status-renderer.js +1 -81
  112. package/dist/cli/sdd-renderer.js +1 -247
  113. package/dist/cli/setup-plan-renderer.js +1 -79
  114. package/dist/cli/setup-status-renderer.js +1 -50
  115. package/dist/cli/setup-tui-app.js +1 -130
  116. package/dist/cli/setup-tui-controller.js +1 -89
  117. package/dist/cli/tui/focus-reducer.js +1 -0
  118. package/dist/cli/tui/focus-types.js +1 -0
  119. package/dist/cli/tui/ink/app-shell.js +1 -0
  120. package/dist/cli/tui/ink/components.js +1 -38
  121. package/dist/cli/tui/ink/help-overlay.js +1 -0
  122. package/dist/cli/tui/ink/state-components.js +1 -0
  123. package/dist/cli/tui/ink/theme.js +1 -36
  124. package/dist/cli/tui/key-intents.js +1 -0
  125. package/dist/cli/tui/keymap.js +1 -20
  126. package/dist/cli/tui/navigation.js +1 -10
  127. package/dist/cli/tui/screen-registry.js +1 -0
  128. package/dist/cli/tui/terminal-capabilities.js +1 -12
  129. package/dist/cli/tui/tui-types.js +1 -1
  130. package/dist/cli/tui/visual/badges.js +1 -19
  131. package/dist/cli/tui/visual/footer.js +1 -27
  132. package/dist/cli/tui/visual/index.js +1 -3
  133. package/dist/cli/tui/visual/viewport.js +1 -11
  134. package/dist/cli/tui-render-helpers.js +1 -200
  135. package/dist/cli/verification-plan-renderer.js +1 -25
  136. package/dist/cli/verification-report-renderer.js +1 -19
  137. package/dist/domain/agents/canonical-agent-manifest.js +355 -0
  138. package/dist/domain/agents/schema.js +1 -0
  139. package/dist/domain/memory/active-work-topics.js +64 -0
  140. package/dist/domain/memory/memory-capture-schema.js +1 -0
  141. package/dist/domain/memory/schema.js +1 -0
  142. package/dist/domain/runs/schema.js +5 -0
  143. package/dist/domain/sdd/cockpit-types.js +1 -0
  144. package/dist/domain/sdd/schema.js +111 -0
  145. package/dist/domain/skills/schema.js +1 -0
  146. package/dist/governance/risk-classifier.js +2 -0
  147. package/dist/interfaces/cli/bun-bin.js +46 -0
  148. package/dist/interfaces/cli/cli-flags.js +391 -0
  149. package/dist/interfaces/cli/cli-help.js +173 -0
  150. package/dist/interfaces/cli/cli-helpers.js +77 -0
  151. package/dist/interfaces/cli/cli-types.js +1 -0
  152. package/dist/interfaces/cli/commands/agent-skill-dispatcher.js +700 -0
  153. package/dist/interfaces/cli/commands/index.js +9 -0
  154. package/dist/interfaces/cli/commands/interactive-entrypoint-dispatcher.js +14 -0
  155. package/dist/interfaces/cli/commands/mcp-dispatcher.js +252 -0
  156. package/dist/interfaces/cli/commands/memory-sdd-dispatcher.js +367 -0
  157. package/dist/interfaces/cli/commands/run-permission-dispatcher.js +460 -0
  158. package/dist/interfaces/cli/commands/setup-dispatcher.js +496 -0
  159. package/dist/interfaces/cli/commands/status-dispatcher.js +130 -0
  160. package/dist/interfaces/cli/commands/verification-dispatcher.js +47 -0
  161. package/dist/interfaces/cli/commands/workflow-dispatcher.js +566 -0
  162. package/dist/interfaces/cli/dispatcher.js +247 -0
  163. package/dist/interfaces/cli/doctor-renderer.js +26 -0
  164. package/dist/interfaces/cli/home-tui-app.js +462 -0
  165. package/dist/interfaces/cli/home-tui-controller.js +341 -0
  166. package/dist/interfaces/cli/index.js +27 -0
  167. package/dist/interfaces/cli/mcp-start-path.js +21 -0
  168. package/dist/interfaces/cli/product-resume-renderer.js +32 -0
  169. package/dist/interfaces/cli/product-status-renderer.js +81 -0
  170. package/dist/interfaces/cli/sdd-renderer.js +247 -0
  171. package/dist/interfaces/cli/setup-plan-renderer.js +79 -0
  172. package/dist/interfaces/cli/setup-status-renderer.js +50 -0
  173. package/dist/interfaces/cli/setup-tui-app.js +135 -0
  174. package/dist/interfaces/cli/setup-tui-controller.js +89 -0
  175. package/dist/interfaces/cli/tui/focus-reducer.js +60 -0
  176. package/dist/interfaces/cli/tui/focus-types.js +10 -0
  177. package/dist/interfaces/cli/tui/ink/app-shell.js +16 -0
  178. package/dist/interfaces/cli/tui/ink/components.js +38 -0
  179. package/dist/interfaces/cli/tui/ink/help-overlay.js +6 -0
  180. package/dist/interfaces/cli/tui/ink/state-components.js +22 -0
  181. package/dist/interfaces/cli/tui/ink/theme.js +36 -0
  182. package/dist/interfaces/cli/tui/key-intents.js +33 -0
  183. package/dist/interfaces/cli/tui/keymap.js +20 -0
  184. package/dist/interfaces/cli/tui/navigation.js +10 -0
  185. package/dist/interfaces/cli/tui/screen-registry.js +43 -0
  186. package/dist/interfaces/cli/tui/terminal-capabilities.js +12 -0
  187. package/dist/interfaces/cli/tui/tui-types.js +1 -0
  188. package/dist/interfaces/cli/tui/visual/badges.js +19 -0
  189. package/dist/interfaces/cli/tui/visual/footer.js +27 -0
  190. package/dist/interfaces/cli/tui/visual/index.js +3 -0
  191. package/dist/interfaces/cli/tui/visual/viewport.js +11 -0
  192. package/dist/interfaces/cli/tui-render-helpers.js +200 -0
  193. package/dist/interfaces/cli/verification-plan-renderer.js +25 -0
  194. package/dist/interfaces/cli/verification-report-renderer.js +19 -0
  195. package/dist/interfaces/mcp/contracts/agents.js +1 -0
  196. package/dist/interfaces/mcp/contracts/context.js +1 -0
  197. package/dist/interfaces/mcp/contracts/governance.js +1 -0
  198. package/dist/interfaces/mcp/contracts/index.js +1 -0
  199. package/dist/interfaces/mcp/contracts/memory.js +1 -0
  200. package/dist/interfaces/mcp/contracts/providers.js +1 -0
  201. package/dist/interfaces/mcp/contracts/runs.js +1 -0
  202. package/dist/interfaces/mcp/contracts/sdd.js +1 -0
  203. package/dist/interfaces/mcp/contracts/sessions.js +1 -0
  204. package/dist/interfaces/mcp/contracts/skills.js +1 -0
  205. package/dist/interfaces/mcp/contracts/verification.js +1 -0
  206. package/dist/interfaces/mcp/control-plane/handlers/agents.js +38 -0
  207. package/dist/interfaces/mcp/control-plane/handlers/context.js +12 -0
  208. package/dist/interfaces/mcp/control-plane/handlers/memory.js +95 -0
  209. package/dist/interfaces/mcp/control-plane/handlers/providers.js +19 -0
  210. package/dist/interfaces/mcp/control-plane/handlers/runs.js +134 -0
  211. package/dist/interfaces/mcp/control-plane/handlers/sdd.js +225 -0
  212. package/dist/interfaces/mcp/control-plane/handlers/sessions.js +39 -0
  213. package/dist/interfaces/mcp/control-plane/handlers/skills.js +82 -0
  214. package/dist/interfaces/mcp/control-plane/handlers/verification.js +11 -0
  215. package/dist/interfaces/mcp/control-plane/types.js +1 -0
  216. package/dist/interfaces/mcp/control-plane.js +235 -0
  217. package/dist/interfaces/mcp/schema.js +174 -0
  218. package/dist/interfaces/mcp/schemas/common.js +121 -0
  219. package/dist/interfaces/mcp/schemas/inputs/agents.js +69 -0
  220. package/dist/interfaces/mcp/schemas/inputs/context.js +32 -0
  221. package/dist/interfaces/mcp/schemas/inputs/governance.js +23 -0
  222. package/dist/interfaces/mcp/schemas/inputs/index.js +10 -0
  223. package/dist/interfaces/mcp/schemas/inputs/memory.js +50 -0
  224. package/dist/interfaces/mcp/schemas/inputs/providers.js +35 -0
  225. package/dist/interfaces/mcp/schemas/inputs/runs.js +146 -0
  226. package/dist/interfaces/mcp/schemas/inputs/sdd.js +102 -0
  227. package/dist/interfaces/mcp/schemas/inputs/sessions.js +32 -0
  228. package/dist/interfaces/mcp/schemas/inputs/skills.js +231 -0
  229. package/dist/interfaces/mcp/schemas/inputs/verification.js +9 -0
  230. package/dist/interfaces/mcp/schemas/outputs/index.js +2 -0
  231. package/dist/interfaces/mcp/schemas/outputs/providers.js +28 -0
  232. package/dist/interfaces/mcp/schemas/outputs/sdd.js +166 -0
  233. package/dist/interfaces/mcp/stdio-server.js +116 -0
  234. package/dist/interfaces/mcp/validation/agents.js +189 -0
  235. package/dist/interfaces/mcp/validation/common.js +415 -0
  236. package/dist/interfaces/mcp/validation/governance.js +50 -0
  237. package/dist/interfaces/mcp/validation/memory.js +133 -0
  238. package/dist/interfaces/mcp/validation/providers.js +94 -0
  239. package/dist/interfaces/mcp/validation/runs.js +514 -0
  240. package/dist/interfaces/mcp/validation/sdd.js +247 -0
  241. package/dist/interfaces/mcp/validation/sessions.js +51 -0
  242. package/dist/interfaces/mcp/validation/skills.js +685 -0
  243. package/dist/interfaces/mcp/validation/verification.js +24 -0
  244. package/dist/interfaces/mcp/validation.js +149 -0
  245. package/dist/mcp/control-plane-snapshot-service.js +65 -2
  246. package/dist/mcp/control-plane.js +1 -646
  247. package/dist/mcp/doctor.js +1 -1
  248. package/dist/mcp/index.js +17 -17
  249. package/dist/mcp/schema.js +1 -1072
  250. package/dist/mcp/stdio-server.js +1 -116
  251. package/dist/mcp/validation.js +1 -2239
  252. package/dist/memory/active-work-preview.js +1 -75
  253. package/dist/memory/active-work-topics.js +1 -64
  254. package/dist/memory/agent-memory-capture-service.js +1 -497
  255. package/dist/memory/import/dry-run-planner.js +1 -58
  256. package/dist/memory/import/index.js +1 -3
  257. package/dist/memory/import/observation-writer.js +1 -226
  258. package/dist/memory/import/package.js +1 -179
  259. package/dist/memory/memory-capture-schema.js +1 -1
  260. package/dist/memory/memory-service.js +1 -201
  261. package/dist/memory/repositories/artifacts.js +1 -67
  262. package/dist/memory/repositories/observations.js +1 -217
  263. package/dist/memory/repositories/sessions.js +1 -125
  264. package/dist/memory/repositories/traces.js +1 -78
  265. package/dist/memory/schema.js +1 -1
  266. package/dist/memory/search.js +1 -11
  267. package/dist/memory/sqlite/database.js +1 -228
  268. package/dist/memory/storage-paths.js +1 -72
  269. package/dist/payload/context-budget-policy.js +10 -0
  270. package/dist/payload/context-budget-service.js +26 -0
  271. package/dist/payload/payload-diagnostics.js +50 -0
  272. package/dist/permissions/explicit-request-authorization.js +126 -0
  273. package/dist/permissions/policy-evaluator.js +54 -14
  274. package/dist/runs/execution-planning.js +1 -178
  275. package/dist/runs/operation-execution.js +1 -1
  276. package/dist/runs/operation-retry.js +1 -129
  277. package/dist/runs/repositories/runs.js +1 -676
  278. package/dist/runs/repositories/task-scoped-command-grants.js +1 -462
  279. package/dist/runs/resume-after-approval-result.js +1 -84
  280. package/dist/runs/run-insights.js +1 -270
  281. package/dist/runs/run-service.js +1 -1439
  282. package/dist/runs/run-snapshot-export-service.js +1 -31
  283. package/dist/runs/sandbox-process-execution.js +1 -240
  284. package/dist/runs/sandbox-worktree-planning.js +1 -59
  285. package/dist/runs/schema.js +1 -5
  286. package/dist/runs/task-scoped-command-grant-service.js +1 -216
  287. package/dist/sdd/artifact-portability-service.js +1 -137
  288. package/dist/sdd/cockpit-read-model.js +1 -195
  289. package/dist/sdd/cockpit-types.js +1 -1
  290. package/dist/sdd/schema.js +1 -111
  291. package/dist/sdd/sdd-continuation-plan.js +1 -265
  292. package/dist/sdd/sdd-workflow-service.js +1 -822
  293. package/dist/setup/providers/claude-setup-adapter.js +11 -4
  294. package/dist/setup/providers/opencode-setup-adapter.js +10 -7
  295. package/dist/setup/setup-plan.js +20 -7
  296. package/dist/skills/boot-seed.js +1 -42
  297. package/dist/skills/personal-skills.js +1 -41
  298. package/dist/skills/repositories/skill-evaluation-requests.js +1 -190
  299. package/dist/skills/repositories/skill-evaluation-scenarios.js +1 -305
  300. package/dist/skills/repositories/skill-improvement-proposals.js +1 -355
  301. package/dist/skills/repositories/skills.js +1 -1077
  302. package/dist/skills/schema.js +1 -1
  303. package/dist/skills/skill-export-service.js +1 -34
  304. package/dist/skills/skill-index-service.js +1 -126
  305. package/dist/skills/skill-payload.js +1 -186
  306. package/dist/skills/skill-registry-service.js +1 -644
  307. package/dist/skills/skill-resolver.js +1 -368
  308. package/dist/skills/skill-seed-service.js +1 -242
  309. package/dist/skills/skill-status-service.js +1 -147
  310. package/dist/storage/agents/repositories/agent-seed-history.js +128 -0
  311. package/dist/storage/agents/repositories/agents.js +200 -0
  312. package/dist/storage/agents/repositories/manager-profile-overlays.js +90 -0
  313. package/dist/storage/memory/repositories/artifacts.js +67 -0
  314. package/dist/storage/memory/repositories/observations.js +217 -0
  315. package/dist/storage/memory/repositories/sessions.js +125 -0
  316. package/dist/storage/memory/repositories/traces.js +78 -0
  317. package/dist/storage/memory/sqlite/database.js +228 -0
  318. package/dist/storage/memory/storage-paths.js +72 -0
  319. package/dist/storage/runs/repositories/runs.js +676 -0
  320. package/dist/storage/runs/repositories/task-scoped-command-grants.js +464 -0
  321. package/dist/storage/skills/repositories/skill-evaluation-requests.js +190 -0
  322. package/dist/storage/skills/repositories/skill-evaluation-scenarios.js +305 -0
  323. package/dist/storage/skills/repositories/skill-improvement-proposals.js +355 -0
  324. package/dist/storage/skills/repositories/skills.js +1084 -0
  325. package/docs/architecture.md +2 -2
  326. package/docs/glossary.md +1 -1
  327. package/docs/mcp.md +1 -1
  328. package/docs/module-boundaries.md +114 -0
  329. package/docs/prd.md +1 -1
  330. package/docs/project-health-audit-v1.10.x.md +1 -1
  331. package/docs/providers.md +2 -2
  332. package/docs/safety.md +3 -3
  333. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/apply-progress.md +122 -0
  334. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/archive-report.md +61 -0
  335. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/design.md +66 -0
  336. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/proposal.md +79 -0
  337. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/spec.md +67 -0
  338. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/tasks.md +63 -0
  339. package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/verify-report.md +71 -0
  340. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/apply-progress.md +68 -0
  341. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/archive-report.md +61 -0
  342. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/design.md +43 -0
  343. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/proposal.md +61 -0
  344. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/spec.md +31 -0
  345. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/tasks.md +27 -0
  346. package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/verify-report.md +58 -0
  347. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/apply-progress.md +65 -0
  348. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/archive-report.md +53 -0
  349. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/design.md +64 -0
  350. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/proposal.md +62 -0
  351. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/spec.md +51 -0
  352. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/tasks.md +50 -0
  353. package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/verify-report.md +66 -0
  354. package/docs/storage.md +2 -2
  355. package/package.json +2 -2
  356. /package/dist/{mcp → adapters/claude/install}/claude-code-cli.js +0 -0
  357. /package/dist/{memory → storage/memory}/sqlite/migrations/001_initial.sql +0 -0
  358. /package/dist/{memory → storage/memory}/sqlite/migrations/002_observation_revisions.sql +0 -0
  359. /package/dist/{memory → storage/memory}/sqlite/migrations/003_agent_registry.sql +0 -0
  360. /package/dist/{memory → storage/memory}/sqlite/migrations/004_run_runtime.sql +0 -0
  361. /package/dist/{memory → storage/memory}/sqlite/migrations/005_run_approvals.sql +0 -0
  362. /package/dist/{memory → storage/memory}/sqlite/migrations/006_run_operation_attempts.sql +0 -0
  363. /package/dist/{memory → storage/memory}/sqlite/migrations/007_abandoned_operation_attempts.sql +0 -0
  364. /package/dist/{memory → storage/memory}/sqlite/migrations/008_run_execution_plan_events.sql +0 -0
  365. /package/dist/{memory → storage/memory}/sqlite/migrations/009_multiple_operation_attempts.sql +0 -0
  366. /package/dist/{memory → storage/memory}/sqlite/migrations/010_skill_registry.sql +0 -0
  367. /package/dist/{memory → storage/memory}/sqlite/migrations/011_skill_usage_resolution_outcomes.sql +0 -0
  368. /package/dist/{memory → storage/memory}/sqlite/migrations/012_skill_improvement_proposals.sql +0 -0
  369. /package/dist/{memory → storage/memory}/sqlite/migrations/013_skill_evaluation_scenarios.sql +0 -0
  370. /package/dist/{memory → storage/memory}/sqlite/migrations/014_manager_profile_overlays.sql +0 -0
  371. /package/dist/{memory → storage/memory}/sqlite/migrations/015_artifact_metadata.sql +0 -0
  372. /package/dist/{memory → storage/memory}/sqlite/migrations/016_agent_seed_history.sql +0 -0
  373. /package/dist/{memory → storage/memory}/sqlite/migrations/017_intent_signal_skill_targets.sql +0 -0
  374. /package/dist/{memory → storage/memory}/sqlite/migrations/018_skill_system_v2.sql +0 -0
  375. /package/dist/{memory → storage/memory}/sqlite/migrations/019_task_scoped_command_grants.sql +0 -0
@@ -1,1439 +1 @@
1
- import { createHash } from 'node:crypto';
2
- import { evaluatePermission } from '../permissions/policy-evaluator.js';
3
- import { isRiskyPermissionCategory } from '../permissions/schema.js';
4
- import { normalizeSddPhaseInput } from '../sdd/schema.js';
5
- import { planExecutionIsolation, recommendWorkspaceStrategyForExecution } from './execution-planning.js';
6
- import { evaluateOperationRetry as evaluateOperationRetryPolicy } from './operation-retry.js';
7
- import { AllowlistedApplyProgressCommandExecutor } from '../workflows/command-allowlist-adapter.js';
8
- import { RunRepository, } from './repositories/runs.js';
9
- import { buildRunInsights, buildRunOperatorResumePlan } from './run-insights.js';
10
- import { buildResumeAfterApprovalResult } from './resume-after-approval-result.js';
11
- import { grantEvaluationPayload, TaskScopedCommandGrantService } from './task-scoped-command-grant-service.js';
12
- const preflightSafety = {
13
- operationExecuted: false,
14
- executorInvoked: false,
15
- executesProvider: false,
16
- writesProviderConfig: false,
17
- createsSandbox: false,
18
- createsWorktree: false,
19
- };
20
- const resumeGateSafety = {
21
- readOnly: true,
22
- preflightExecuted: false,
23
- retryAdmitted: false,
24
- executorInvoked: false,
25
- operationExecuted: false,
26
- writesProviderConfig: false,
27
- createsSandbox: false,
28
- createsWorktree: false,
29
- };
30
- export class RunService {
31
- runs;
32
- taskScopedCommandGrants;
33
- constructor(database) {
34
- this.runs = new RunRepository(database);
35
- this.taskScopedCommandGrants = new TaskScopedCommandGrantService(database);
36
- }
37
- createRun(input) {
38
- return this.runs.create({ ...input, phase: canonicalRunPhase(input.workflow, input.phase) ?? input.phase });
39
- }
40
- getRun(id) {
41
- return this.runs.getDetails(id);
42
- }
43
- getRunInsights(id) {
44
- const details = this.runs.getDetails(id);
45
- return details.ok ? { ok: true, value: buildRunInsights(details.value) } : details;
46
- }
47
- getRunOperatorResumePlan(id) {
48
- const details = this.runs.getDetails(id);
49
- return details.ok ? { ok: true, value: buildRunOperatorResumePlan(details.value) } : details;
50
- }
51
- listRuns(filters = {}) {
52
- return this.runs.list(filters);
53
- }
54
- getSddOperationalEvidence(input) {
55
- const runs = this.runs.list({ project: input.project, limit: input.limit ?? 50 });
56
- if (!runs.ok)
57
- return runs;
58
- const evidenceByPhase = {};
59
- for (const run of runs.value) {
60
- if (!isSddWorkflow(run.workflow))
61
- continue;
62
- const phase = normalizeSddPhaseInput(run.phase);
63
- if (phase === undefined || evidenceByPhase[phase] !== undefined)
64
- continue;
65
- const details = this.runs.getDetails(run.id);
66
- if (!details.ok)
67
- return details;
68
- const matchingCheckpoints = details.value.checkpoints.filter((checkpoint) => checkpointHasChangeId(checkpoint.state, input.change));
69
- if (matchingCheckpoints.length === 0)
70
- continue;
71
- const latestMatchingCheckpoint = matchingCheckpoints.at(-1);
72
- evidenceByPhase[phase] = {
73
- latestRun: {
74
- id: details.value.id,
75
- status: details.value.status,
76
- workflow: details.value.workflow,
77
- phase: details.value.phase,
78
- ...(details.value.outcome === undefined ? {} : { outcome: details.value.outcome }),
79
- createdAt: details.value.createdAt,
80
- updatedAt: details.value.updatedAt,
81
- ...(details.value.completedAt === undefined ? {} : { completedAt: details.value.completedAt }),
82
- },
83
- approvalCounts: countByStatus(details.value.approvals.map((approval) => approval.status)),
84
- attemptCounts: countByStatus(details.value.operationAttempts.map((attempt) => attempt.status)),
85
- ...(latestMatchingCheckpoint === undefined
86
- ? {}
87
- : {
88
- latestCheckpoint: {
89
- id: latestMatchingCheckpoint.id,
90
- label: latestMatchingCheckpoint.label,
91
- sequence: latestMatchingCheckpoint.sequence,
92
- createdAt: latestMatchingCheckpoint.createdAt,
93
- },
94
- }),
95
- };
96
- }
97
- return { ok: true, value: evidenceByPhase };
98
- }
99
- listRecentInterruptedRuns(input) {
100
- const runs = this.runs.list({ project: input.project, statuses: ['failed', 'blocked', 'needs-human'], limit: input.limit ?? 5 });
101
- if (!runs.ok)
102
- return runs;
103
- const candidates = [];
104
- for (const run of runs.value) {
105
- const details = this.runs.getDetails(run.id);
106
- if (!details.ok)
107
- return details;
108
- const latestCheckpoint = details.value.checkpoints.at(-1);
109
- const userIntent = details.value.userIntent.trim();
110
- candidates.push({
111
- runId: details.value.id,
112
- status: details.value.status,
113
- workflow: details.value.workflow,
114
- phase: details.value.phase,
115
- ...(userIntent.length === 0 ? {} : { userIntent }),
116
- ...(latestCheckpoint === undefined ? {} : { latestCheckpointLabel: latestCheckpoint.label }),
117
- });
118
- }
119
- return { ok: true, value: candidates };
120
- }
121
- findRelatedInterruptedSddRun(input) {
122
- const runs = this.runs.list({ project: input.project, statuses: ['failed', 'blocked', 'needs-human'], limit: input.limit ?? 25 });
123
- if (!runs.ok)
124
- return runs;
125
- for (const run of runs.value) {
126
- const details = this.runs.getDetails(run.id);
127
- if (!details.ok)
128
- return details;
129
- const hasMatchingCheckpoint = details.value.checkpoints.some((checkpoint) => checkpointHasChangeId(checkpoint.state, input.change));
130
- if (!hasMatchingCheckpoint)
131
- continue;
132
- const latestCheckpoint = details.value.checkpoints.at(-1);
133
- return {
134
- ok: true,
135
- value: {
136
- runId: details.value.id,
137
- status: details.value.status,
138
- workflow: details.value.workflow,
139
- phase: details.value.phase,
140
- ...(latestCheckpoint === undefined ? {} : { latestCheckpointLabel: latestCheckpoint.label }),
141
- },
142
- };
143
- }
144
- return { ok: true, value: undefined };
145
- }
146
- appendEvent(input) {
147
- return this.runs.appendEvent(input);
148
- }
149
- appendEvidence(input) {
150
- return this.runs.appendEvent({ ...input, kind: 'evidence' });
151
- }
152
- appendCheckpoint(input) {
153
- return this.runs.appendCheckpoint(input);
154
- }
155
- updateFinalStatus(input) {
156
- return this.runs.updateFinalStatus(input);
157
- }
158
- listApprovals(runId) {
159
- return this.runs.listApprovals(runId);
160
- }
161
- listOperationAttempts(runId) {
162
- return this.runs.listOperationAttempts(runId);
163
- }
164
- getApproval(id) {
165
- return this.runs.getApproval(id);
166
- }
167
- resolveApproval(input) {
168
- return this.runs.resolveApproval(input);
169
- }
170
- taskScopedCommandGrantService() {
171
- return this.taskScopedCommandGrants;
172
- }
173
- abandonReservedOperationAttempt(input) {
174
- return this.runs.abandonOperationAttempt(input);
175
- }
176
- evaluateOperationRetry(input) {
177
- const approval = this.runs.getApproval(input.approvalId);
178
- if (!approval.ok)
179
- return { ok: false, error: approval.error };
180
- const details = this.runs.getDetails(approval.value.runId);
181
- if (!details.ok)
182
- return { ok: false, error: details.error };
183
- const attempts = details.value.operationAttempts.filter((attempt) => attempt.approvalId === input.approvalId);
184
- return {
185
- ok: true,
186
- value: evaluateOperationRetryPolicy(input.policy === undefined ? { attempts } : { attempts, policy: input.policy }),
187
- };
188
- }
189
- getRunResumeOrchestrationPlan(input) {
190
- const approval = this.runs.getApproval(input.approvalId);
191
- if (!approval.ok)
192
- return approval;
193
- const details = this.runs.getDetails(approval.value.runId);
194
- if (!details.ok)
195
- return details;
196
- const blockers = [];
197
- if (approval.value.status !== 'approved') {
198
- blockers.push({
199
- code: 'approval-not-approved',
200
- message: `Approval must be approved before manual continuation guidance is available: ${approval.value.status}`,
201
- relatedId: approval.value.id,
202
- });
203
- }
204
- const permissionEvent = details.value.events.find((event) => event.id === approval.value.decisionEventId);
205
- if (permissionEvent === undefined || !isAskPermissionEvent(permissionEvent)) {
206
- blockers.push({
207
- code: 'missing-permission-event',
208
- message: 'Approval permission-decision event is missing or is not an ask decision',
209
- relatedId: approval.value.decisionEventId,
210
- });
211
- }
212
- const pendingExecutionEvent = details.value.events.find((event) => isPendingExecutionEventForApproval(event, approval.value.id));
213
- let operation;
214
- if (pendingExecutionEvent === undefined) {
215
- blockers.push({
216
- code: 'missing-pending-operation',
217
- message: 'Approval has no pending operation-execution event to reconstruct',
218
- relatedId: approval.value.id,
219
- });
220
- }
221
- else {
222
- operation = operationFromPendingExecution(pendingExecutionEvent.payload);
223
- if (operation === undefined) {
224
- blockers.push({
225
- code: 'operation-metadata-incomplete',
226
- message: 'Pending operation metadata is incomplete and cannot be planned',
227
- relatedId: pendingExecutionEvent.id,
228
- });
229
- }
230
- }
231
- const retryDecision = operation === undefined
232
- ? null
233
- : evaluateOperationRetryPolicy(input.policy === undefined
234
- ? { attempts: details.value.operationAttempts.filter((attempt) => attempt.approvalId === approval.value.id) }
235
- : { attempts: details.value.operationAttempts.filter((attempt) => attempt.approvalId === approval.value.id), policy: input.policy });
236
- if (retryDecision !== null && !retryDecision.allowed) {
237
- const relatedId = retryDecision.latestAttempt?.id ?? retryDecision.activeAttempt?.id;
238
- blockers.push({
239
- code: 'retry-blocked',
240
- message: retryDecision.reason,
241
- ...(relatedId === undefined ? {} : { relatedId }),
242
- });
243
- }
244
- return {
245
- ok: true,
246
- value: {
247
- kind: 'run-resume-orchestration-plan',
248
- version: 1,
249
- run: {
250
- id: details.value.id,
251
- project: details.value.project,
252
- status: details.value.status,
253
- workflow: details.value.workflow,
254
- phase: details.value.phase,
255
- },
256
- approval: {
257
- id: approval.value.id,
258
- runId: approval.value.runId,
259
- status: approval.value.status,
260
- decisionEventId: approval.value.decisionEventId,
261
- },
262
- operation: operation === undefined ? null : summarizeOperation(operation),
263
- retryDecision,
264
- blockers,
265
- nextAction: resumeGateNextAction(approval.value, details.value, blockers),
266
- manualNextCommands: resumeGateManualNextCommands(approval.value, details.value, operation),
267
- safety: resumeGateSafety,
268
- },
269
- };
270
- }
271
- admitOperationRetryAttempt(input) {
272
- const approval = this.runs.getApproval(input.approvalId);
273
- if (!approval.ok)
274
- return approval;
275
- if (approval.value.status !== 'approved')
276
- return validationFailure(`Only approved approvals can admit retry attempts: ${approval.value.status}`);
277
- const details = this.runs.getDetails(approval.value.runId);
278
- if (!details.ok)
279
- return details;
280
- const permissionEvent = details.value.events.find((event) => event.id === approval.value.decisionEventId);
281
- if (permissionEvent === undefined)
282
- return validationFailure('Approval permission-decision event is missing');
283
- if (!isAskPermissionEvent(permissionEvent))
284
- return validationFailure('Approval is not linked to an ask permission decision');
285
- const pendingExecutionEvent = details.value.events.find((event) => isPendingExecutionEventForApproval(event, approval.value.id));
286
- if (pendingExecutionEvent === undefined)
287
- return validationFailure('Approved approval has no retryable pending operation event');
288
- const operation = operationFromPendingExecution(pendingExecutionEvent.payload);
289
- if (operation === undefined)
290
- return validationFailure('Pending operation metadata is incomplete and cannot be retried');
291
- const replayGuard = replayGuardForApprovedOperation(approval.value, permissionEvent, pendingExecutionEvent, operation);
292
- const attempts = details.value.operationAttempts.filter((attempt) => attempt.approvalId === approval.value.id);
293
- const retryDecision = evaluateOperationRetryPolicy(input.policy === undefined ? { attempts } : { attempts, policy: input.policy });
294
- if (!retryDecision.allowed || retryDecision.reasonCode !== 'status_allowed_by_policy')
295
- return validationFailure(retryDecision.reason);
296
- const reserved = this.runs.reserveOperationAttempt({
297
- runId: approval.value.runId,
298
- approvalId: approval.value.id,
299
- decisionEventId: permissionEvent.id,
300
- pendingExecutionEventId: pendingExecutionEvent.id,
301
- category: operation.category,
302
- operation: operation.operation,
303
- operationMetadata: operationMetadataWithReplayGuard(operation, replayGuard),
304
- executorName: input.executorName ?? 'retry-admission',
305
- });
306
- if (!reserved.ok)
307
- return reserved;
308
- const admissionEvent = this.runs.appendEvent({
309
- runId: approval.value.runId,
310
- kind: 'operation-execution',
311
- title: `Retry attempt admitted: ${operation.category} ${operation.operation}`,
312
- payload: executionPayload(operation, reserved.value.executorName, 'pending-approval', {
313
- admissionStatus: 'reserved',
314
- retryAdmission: true,
315
- attemptId: reserved.value.id,
316
- attemptSequence: reserved.value.attemptSequence,
317
- approvalId: approval.value.id,
318
- decisionEventId: permissionEvent.id,
319
- originalPendingExecutionEventId: pendingExecutionEvent.id,
320
- retryPolicy: retryDecision.policy,
321
- retryReasonCode: retryDecision.reasonCode,
322
- retryReason: retryDecision.reason,
323
- evaluatedAttemptCount: retryDecision.evaluatedAttemptCount,
324
- retryableStatuses: [...retryDecision.retryableStatuses],
325
- replayGuard,
326
- operationFingerprint: replayGuard.operationFingerprint,
327
- executorInvoked: false,
328
- operationExecuted: false,
329
- }),
330
- relatedType: 'operation-attempt',
331
- relatedId: reserved.value.id,
332
- });
333
- if (!admissionEvent.ok)
334
- return { ok: false, error: admissionEvent.error };
335
- return {
336
- ok: true,
337
- value: { approval: approval.value, retryDecision, permissionEvent, pendingExecutionEvent, attempt: reserved.value, admissionEvent: admissionEvent.value },
338
- };
339
- }
340
- planOperationExecution(input) {
341
- const resolved = this.buildPermissionContextForRun(input);
342
- if (!resolved.ok)
343
- return resolved;
344
- const permission = this.evaluatePermissionForRun(resolved.value);
345
- if (!permission.ok)
346
- return permission;
347
- const plan = planExecutionIsolation({
348
- operation: resolved.value,
349
- decision: permission.value.decision,
350
- ...(resolved.value.gitBoundaryInspector === undefined ? {} : { gitBoundaryInspector: resolved.value.gitBoundaryInspector }),
351
- });
352
- const workspaceStrategy = recommendWorkspaceStrategyForExecution({
353
- operation: resolved.value,
354
- decision: permission.value.decision,
355
- ...(resolved.value.gitBoundaryInspector === undefined ? {} : { gitBoundaryInspector: resolved.value.gitBoundaryInspector }),
356
- });
357
- const sandboxDecision = sandboxDecisionSummary(plan.sandbox);
358
- const planEvent = this.runs.appendEvent({
359
- runId: resolved.value.runId,
360
- kind: 'execution-plan',
361
- title: `Execution plan: ${resolved.value.category} ${resolved.value.operation}`,
362
- payload: {
363
- runId: resolved.value.runId,
364
- requestedOperation: operationMetadata(resolved.value),
365
- decisionEventId: permission.value.event.id,
366
- approvalId: permission.value.approval?.id ?? null,
367
- plan: plan,
368
- workspaceStrategy: workspaceStrategy,
369
- ...(sandboxDecision === undefined ? {} : { sandboxDecision: sandboxDecision }),
370
- operationExecuted: false,
371
- executorInvoked: false,
372
- executesProvider: false,
373
- writesProviderConfig: false,
374
- createsSandbox: false,
375
- createsWorktree: false,
376
- timestamp: new Date().toISOString(),
377
- },
378
- relatedType: 'operation',
379
- relatedId: resolved.value.operation,
380
- });
381
- if (!planEvent.ok)
382
- return { ok: false, error: planEvent.error };
383
- return { ok: true, value: { ...permission.value, plan, workspaceStrategy, planEvent: planEvent.value } };
384
- }
385
- preflightOperation(input) {
386
- const resolved = this.buildPermissionContextForRun(input);
387
- if (!resolved.ok)
388
- return resolved;
389
- const metadataValidation = this.validateVgxManagedPreflightMetadata(resolved.value);
390
- if (!metadataValidation.ok)
391
- return metadataValidation;
392
- const planned = this.planOperationExecution(resolved.value);
393
- if (!planned.ok)
394
- return planned;
395
- const { decision, event, approval, plan, workspaceStrategy, planEvent } = planned.value;
396
- const audit = { permissionEventId: event.id, planEventId: planEvent.id };
397
- if (approval !== undefined)
398
- audit.approvalId = approval.id;
399
- const sandbox = plan.sandbox;
400
- const sandboxRejected = sandbox?.decision === 'rejected';
401
- const sandboxReason = sandboxRejected ? [{ code: sandbox.reason ?? 'sandbox_boundary', message: sandbox.audit.validationSummary }] : [];
402
- const outcome = sandboxRejected ? 'blocked' : preflightOutcome(decision);
403
- this.appendPreflightAuditEvent(resolved.value, outcome, {
404
- permissionEventId: event.id,
405
- planEventId: planEvent.id,
406
- ...(approval === undefined ? {} : { approvalId: approval.id }),
407
- });
408
- return {
409
- ok: true,
410
- value: {
411
- outcome,
412
- decision,
413
- reasons: [...sandboxReason, { code: decision.reason, message: decision.message }],
414
- permissionEvent: event,
415
- ...(approval === undefined ? {} : { approval }),
416
- plan,
417
- workspaceStrategy,
418
- planEvent,
419
- audit,
420
- eligibleForFutureExecution: plan.executable && !sandboxRejected,
421
- safety: preflightSafety,
422
- },
423
- };
424
- }
425
- resumeApprovedOperation(input) {
426
- const approval = this.runs.getApproval(input.approvalId);
427
- if (!approval.ok)
428
- return approval;
429
- if (approval.value.status !== 'approved')
430
- return validationFailure(`Only approved approvals can be resumed: ${approval.value.status}`);
431
- const details = this.runs.getDetails(approval.value.runId);
432
- if (!details.ok)
433
- return details;
434
- const pendingExecutionEvent = details.value.events.find((event) => isPendingExecutionEventForApproval(event, approval.value.id));
435
- if (pendingExecutionEvent === undefined)
436
- return validationFailure('Approved approval has no resumable pending operation event');
437
- const permissionEvent = permissionEventForPendingExecution(details.value, approval.value, pendingExecutionEvent);
438
- if (permissionEvent === undefined)
439
- return validationFailure('Approval permission-decision event is missing');
440
- if (!isAskPermissionEvent(permissionEvent))
441
- return validationFailure('Approval is not linked to an ask permission decision');
442
- const operation = operationFromPendingExecution(pendingExecutionEvent.payload);
443
- if (operation === undefined)
444
- return validationFailure('Pending operation metadata is incomplete and cannot be resumed');
445
- const replayGuard = replayGuardForApprovedOperation(approval.value, permissionEvent, pendingExecutionEvent, operation);
446
- const replayValidation = validateReplayGuard(pendingExecutionEvent, replayGuard, input.expectedOperationFingerprint);
447
- if (!replayValidation.ok)
448
- return replayValidation;
449
- const retry = this.evaluateOperationRetry({ approvalId: approval.value.id });
450
- if (!retry.ok)
451
- return retry;
452
- if (!retry.value.allowed)
453
- return validationFailure(retry.value.reason);
454
- const reserved = this.runs.reserveOperationAttempt({
455
- runId: approval.value.runId,
456
- approvalId: approval.value.id,
457
- decisionEventId: permissionEvent.id,
458
- pendingExecutionEventId: pendingExecutionEvent.id,
459
- category: operation.category,
460
- operation: operation.operation,
461
- operationMetadata: operationMetadataWithReplayGuard(operation, replayGuard),
462
- executorName: input.executor.name,
463
- });
464
- if (!reserved.ok)
465
- return reserved;
466
- const executed = input.executor.execute({ runId: approval.value.runId, operation });
467
- if (!executed.ok) {
468
- const error = { code: executed.error.code, message: executed.error.message };
469
- const result = buildResumeAfterApprovalResult({
470
- runId: approval.value.runId,
471
- approvalId: approval.value.id,
472
- attemptId: reserved.value.id,
473
- permissionEventId: permissionEvent.id,
474
- pendingExecutionEventId: pendingExecutionEvent.id,
475
- operationFingerprint: replayGuard.operationFingerprint,
476
- executorName: input.executor.name,
477
- operation,
478
- status: 'failed',
479
- error,
480
- });
481
- const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'failed', output: result, error });
482
- if (!attempt.ok)
483
- return attempt;
484
- const executionEvent = this.runs.appendEvent({
485
- runId: approval.value.runId,
486
- kind: 'operation-execution',
487
- title: `Approved operation failed: ${operation.category} ${operation.operation}`,
488
- payload: executionPayload(operation, input.executor.name, 'failed', {
489
- attemptId: attempt.value.id,
490
- decisionEventId: permissionEvent.id,
491
- approvalId: approval.value.id,
492
- originalPendingExecutionEventId: pendingExecutionEvent.id,
493
- originalDecision: 'ask',
494
- approvalStatus: 'approved',
495
- policyReevaluated: false,
496
- replayGuard,
497
- operationFingerprint: replayGuard.operationFingerprint,
498
- resumedFromApprovalId: approval.value.id,
499
- executorInvoked: true,
500
- result,
501
- error,
502
- }),
503
- relatedType: 'approval',
504
- relatedId: approval.value.id,
505
- });
506
- if (!executionEvent.ok)
507
- return { ok: false, error: executionEvent.error };
508
- const linkedAttempt = this.runs.attachAttemptResultEvent(attempt.value.id, executionEvent.value.id);
509
- const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, result);
510
- if (!evidence.ok)
511
- return { ok: false, error: evidence.error };
512
- return {
513
- ok: true,
514
- value: {
515
- approval: approval.value,
516
- permissionEvent,
517
- pendingExecutionEvent,
518
- attempt: linkedAttempt.ok ? linkedAttempt.value : attempt.value,
519
- executionEvent: executionEvent.value,
520
- status: 'failed',
521
- output: result,
522
- ...(evidence.value === undefined ? {} : evidence.value),
523
- },
524
- };
525
- }
526
- const output = executed.value.output;
527
- const result = buildResumeAfterApprovalResult({
528
- runId: approval.value.runId,
529
- approvalId: approval.value.id,
530
- attemptId: reserved.value.id,
531
- permissionEventId: permissionEvent.id,
532
- pendingExecutionEventId: pendingExecutionEvent.id,
533
- operationFingerprint: replayGuard.operationFingerprint,
534
- executorName: input.executor.name,
535
- operation,
536
- status: 'succeeded',
537
- ...(output === undefined ? {} : { executorOutput: output }),
538
- });
539
- const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'succeeded', output: result });
540
- if (!attempt.ok)
541
- return attempt;
542
- const executionEvent = this.runs.appendEvent({
543
- runId: approval.value.runId,
544
- kind: 'operation-execution',
545
- title: `Approved operation executed: ${operation.category} ${operation.operation}`,
546
- payload: executionPayload(operation, input.executor.name, 'succeeded', {
547
- attemptId: attempt.value.id,
548
- decisionEventId: permissionEvent.id,
549
- approvalId: approval.value.id,
550
- originalPendingExecutionEventId: pendingExecutionEvent.id,
551
- originalDecision: 'ask',
552
- approvalStatus: 'approved',
553
- policyReevaluated: false,
554
- replayGuard,
555
- operationFingerprint: replayGuard.operationFingerprint,
556
- resumedFromApprovalId: approval.value.id,
557
- executorInvoked: true,
558
- result,
559
- }),
560
- relatedType: 'approval',
561
- relatedId: approval.value.id,
562
- });
563
- if (!executionEvent.ok)
564
- return { ok: false, error: executionEvent.error };
565
- const linkedAttempt = this.runs.attachAttemptResultEvent(attempt.value.id, executionEvent.value.id);
566
- const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, result);
567
- if (!evidence.ok)
568
- return { ok: false, error: evidence.error };
569
- return {
570
- ok: true,
571
- value: {
572
- approval: approval.value,
573
- permissionEvent,
574
- pendingExecutionEvent,
575
- attempt: linkedAttempt.ok ? linkedAttempt.value : attempt.value,
576
- executionEvent: executionEvent.value,
577
- status: 'succeeded',
578
- output: result,
579
- ...(evidence.value === undefined ? {} : evidence.value),
580
- },
581
- };
582
- }
583
- resumeApprovedAllowlistedApplyProgressCommand(input) {
584
- return this.resumeApprovedOperation({
585
- approvalId: input.approvalId,
586
- executor: new AllowlistedApplyProgressCommandExecutor(input.executorOptions),
587
- ...(input.expectedOperationFingerprint === undefined ? {} : { expectedOperationFingerprint: input.expectedOperationFingerprint }),
588
- });
589
- }
590
- executeOperation(input) {
591
- const permission = this.evaluatePermissionForRun({ runId: input.runId, ...input.operation, reusePendingApproval: true });
592
- if (!permission.ok)
593
- return permission;
594
- const preflightGate = this.evaluateVgxManagedExecutionPreflightGate(input);
595
- if (!preflightGate.ok)
596
- return preflightGate;
597
- if (preflightGate.value.blocked) {
598
- const blockedDecision = {
599
- ...permission.value.decision,
600
- decision: 'deny',
601
- reason: 'sdd_phase_policy',
602
- message: preflightGate.value.message,
603
- requiresPreflight: true,
604
- };
605
- this.appendPreflightGateAuditEvent(input.runId, input.operation, preflightGate.value.status, preflightGate.value.message);
606
- const executionEvent = this.runs.appendEvent({
607
- runId: input.runId,
608
- kind: 'operation-execution',
609
- title: `Operation blocked by preflight gate: ${input.operation.category} ${input.operation.operation}`,
610
- payload: executionPayload(input.operation, input.executor.name, 'blocked', {
611
- decisionEventId: permission.value.event.id,
612
- decision: 'deny',
613
- reason: blockedDecision.reason,
614
- message: blockedDecision.message,
615
- preflightRequired: true,
616
- preflightStatus: preflightGate.value.status,
617
- executorInvoked: false,
618
- operationExecuted: false,
619
- }),
620
- relatedType: 'operation',
621
- relatedId: input.operation.operation,
622
- });
623
- return executionEvent.ok
624
- ? { ok: true, value: { decision: blockedDecision, permissionEvent: permission.value.event, executionEvent: executionEvent.value, status: 'blocked' } }
625
- : { ok: false, error: executionEvent.error };
626
- }
627
- if (permission.value.decision.decision === 'deny') {
628
- const executionEvent = this.runs.appendEvent({
629
- runId: input.runId,
630
- kind: 'operation-execution',
631
- title: `Operation blocked: ${input.operation.category} ${input.operation.operation}`,
632
- payload: executionPayload(input.operation, input.executor.name, 'blocked', {
633
- decisionEventId: permission.value.event.id,
634
- decision: 'deny',
635
- reason: permission.value.decision.reason,
636
- message: permission.value.decision.message,
637
- executorInvoked: false,
638
- }),
639
- relatedType: 'operation',
640
- relatedId: input.operation.operation,
641
- });
642
- return executionEvent.ok
643
- ? {
644
- ok: true,
645
- value: { decision: permission.value.decision, permissionEvent: permission.value.event, executionEvent: executionEvent.value, status: 'blocked' },
646
- }
647
- : { ok: false, error: executionEvent.error };
648
- }
649
- if (permission.value.decision.decision === 'ask') {
650
- const replayGuard = permission.value.approval === undefined ? undefined : replayGuardForApprovedOperation(permission.value.approval, permission.value.event, undefined, input.operation);
651
- const executionEvent = this.runs.appendEvent({
652
- runId: input.runId,
653
- kind: 'operation-execution',
654
- title: `Operation pending approval: ${input.operation.category} ${input.operation.operation}`,
655
- payload: executionPayload(input.operation, input.executor.name, 'pending-approval', {
656
- decisionEventId: permission.value.event.id,
657
- approvalId: permission.value.approval?.id ?? null,
658
- decision: 'ask',
659
- reason: permission.value.decision.reason,
660
- message: permission.value.decision.message,
661
- ...(replayGuard === undefined ? {} : { replayGuard, operationFingerprint: replayGuard.operationFingerprint }),
662
- executorInvoked: false,
663
- operationExecuted: false,
664
- }),
665
- relatedType: 'operation',
666
- relatedId: input.operation.operation,
667
- });
668
- return executionEvent.ok
669
- ? {
670
- ok: true,
671
- value: {
672
- decision: permission.value.decision,
673
- permissionEvent: permission.value.event,
674
- executionEvent: executionEvent.value,
675
- status: 'pending-approval',
676
- ...(permission.value.approval === undefined ? {} : { approval: permission.value.approval }),
677
- },
678
- }
679
- : { ok: false, error: executionEvent.error };
680
- }
681
- const executed = input.executor.execute({ runId: input.runId, operation: input.operation });
682
- if (!executed.ok) {
683
- const executionEvent = this.runs.appendEvent({
684
- runId: input.runId,
685
- kind: 'operation-execution',
686
- title: `Operation failed: ${input.operation.category} ${input.operation.operation}`,
687
- payload: executionPayload(input.operation, input.executor.name, 'failed', {
688
- decisionEventId: permission.value.event.id,
689
- decision: 'allow',
690
- executorInvoked: true,
691
- error: { code: executed.error.code, message: executed.error.message },
692
- }),
693
- relatedType: 'operation',
694
- relatedId: input.operation.operation,
695
- });
696
- return executionEvent.ok
697
- ? {
698
- ok: true,
699
- value: { decision: permission.value.decision, permissionEvent: permission.value.event, executionEvent: executionEvent.value, status: 'failed' },
700
- }
701
- : { ok: false, error: executionEvent.error };
702
- }
703
- const output = executed.value.output;
704
- const executionEvent = this.runs.appendEvent({
705
- runId: input.runId,
706
- kind: 'operation-execution',
707
- title: `Operation executed: ${input.operation.category} ${input.operation.operation}`,
708
- payload: executionPayload(input.operation, input.executor.name, 'succeeded', {
709
- decisionEventId: permission.value.event.id,
710
- decision: 'allow',
711
- executorInvoked: true,
712
- output: output ?? null,
713
- }),
714
- relatedType: 'operation',
715
- relatedId: input.operation.operation,
716
- });
717
- return executionEvent.ok
718
- ? {
719
- ok: true,
720
- value: {
721
- decision: permission.value.decision,
722
- permissionEvent: permission.value.event,
723
- executionEvent: executionEvent.value,
724
- status: 'succeeded',
725
- ...(output === undefined ? {} : { output }),
726
- },
727
- }
728
- : { ok: false, error: executionEvent.error };
729
- }
730
- evaluatePermissionForRun(input) {
731
- const resolved = this.buildPermissionContextForRun(input);
732
- if (!resolved.ok)
733
- return resolved;
734
- const inputWithRunContext = resolved.value;
735
- const run = this.runs.getById(inputWithRunContext.runId);
736
- if (!run.ok)
737
- return { ok: false, error: run.error };
738
- const contextConflict = workflowConflictDecision(inputWithRunContext, run.value.workflow);
739
- const decision = contextConflict ?? evaluatePermission(inputWithRunContext);
740
- const timestamp = new Date().toISOString();
741
- const agent = inputWithRunContext.agent === undefined ? { id: run.value.selectedAgentId } : { id: inputWithRunContext.agent.id, name: inputWithRunContext.agent.name, mode: inputWithRunContext.agent.mode };
742
- if (decision.decision === 'ask') {
743
- const prior = this.findMatchingApproval(inputWithRunContext, agent, inputWithRunContext.reusePendingApproval === true);
744
- if (!prior.ok)
745
- return prior;
746
- if (prior.value !== undefined) {
747
- const reusedDecision = prior.value.approval.status === 'pending'
748
- ? decision
749
- : prior.value.approval.status === 'approved'
750
- ? { ...decision, decision: 'allow', message: `Previously approved approval ${prior.value.approval.id} authorizes this exact operation.` }
751
- : {
752
- ...decision,
753
- decision: 'deny',
754
- reason: 'default_policy',
755
- message: `Previously ${prior.value.approval.status} approval ${prior.value.approval.id} denies this exact operation.`,
756
- };
757
- const event = this.runs.appendEvent({
758
- runId: inputWithRunContext.runId,
759
- kind: 'permission-decision',
760
- title: `Permission ${reusedDecision.decision}: ${inputWithRunContext.category} ${inputWithRunContext.operation}`,
761
- payload: {
762
- runId: inputWithRunContext.runId,
763
- category: inputWithRunContext.category,
764
- operation: inputWithRunContext.operation,
765
- workflow: inputWithRunContext.workflow ?? null,
766
- phase: inputWithRunContext.phase ?? null,
767
- requestedOperation: operationMetadata(inputWithRunContext),
768
- agent,
769
- decision: reusedDecision.decision,
770
- reasons: [{ code: reusedDecision.reason, message: reusedDecision.message }],
771
- riskTier: reusedDecision.riskTier ?? null,
772
- riskReasonCodes: reusedDecision.riskReasonCodes ?? [],
773
- boundary: (reusedDecision.boundary ?? null),
774
- auditEvidence: reusedDecision.auditEvidence ?? [],
775
- requiresHumanApproval: reusedDecision.decision === 'ask',
776
- approvalStatus: prior.value.approval.status,
777
- reusedApprovalId: prior.value.approval.id,
778
- originalDecisionEventId: prior.value.event.id,
779
- approvalMatched: true,
780
- timestamp,
781
- },
782
- relatedType: 'approval',
783
- relatedId: prior.value.approval.id,
784
- });
785
- return event.ok
786
- ? { ok: true, value: { decision: reusedDecision, event: event.value, approval: prior.value.approval } }
787
- : { ok: false, error: event.error };
788
- }
789
- }
790
- const grantAuthorization = decision.decision === 'ask' ? this.taskScopedCommandGrants.tryAuthorizeAsk({ run: run.value, request: inputWithRunContext, baseDecision: decision }) : undefined;
791
- if (grantAuthorization !== undefined) {
792
- if (!grantAuthorization.ok)
793
- return grantAuthorization;
794
- if (grantAuthorization.value.authorized) {
795
- const grantedDecision = grantAuthorization.value.decision;
796
- const event = this.runs.appendEvent({
797
- runId: inputWithRunContext.runId,
798
- kind: 'permission-decision',
799
- title: `Permission ${grantedDecision.decision}: ${inputWithRunContext.category} ${inputWithRunContext.operation}`,
800
- payload: {
801
- runId: inputWithRunContext.runId,
802
- category: inputWithRunContext.category,
803
- operation: inputWithRunContext.operation,
804
- workflow: inputWithRunContext.workflow ?? null,
805
- phase: inputWithRunContext.phase ?? null,
806
- requestedOperation: operationMetadata(inputWithRunContext),
807
- agent,
808
- decision: grantedDecision.decision,
809
- reasons: [{ code: grantedDecision.reason, message: grantedDecision.message }],
810
- riskTier: grantedDecision.riskTier ?? null,
811
- riskReasonCodes: grantedDecision.riskReasonCodes ?? [],
812
- boundary: (grantedDecision.boundary ?? null),
813
- auditEvidence: grantedDecision.auditEvidence ?? [],
814
- requiresHumanApproval: false,
815
- approvalStatus: 'not-required',
816
- grantEvaluation: grantEvaluationPayload(grantAuthorization.value.evaluation),
817
- grantUseEventId: grantAuthorization.value.event.id,
818
- timestamp,
819
- },
820
- relatedType: 'task-scoped-command-grant',
821
- relatedId: grantAuthorization.value.grant.id,
822
- });
823
- return event.ok ? { ok: true, value: { decision: grantedDecision, event: event.value } } : { ok: false, error: event.error };
824
- }
825
- }
826
- const event = this.runs.appendEvent({
827
- runId: inputWithRunContext.runId,
828
- kind: 'permission-decision',
829
- title: `Permission ${decision.decision}: ${inputWithRunContext.category} ${inputWithRunContext.operation}`,
830
- payload: {
831
- runId: inputWithRunContext.runId,
832
- category: inputWithRunContext.category,
833
- operation: inputWithRunContext.operation,
834
- workflow: inputWithRunContext.workflow ?? null,
835
- phase: inputWithRunContext.phase ?? null,
836
- requestedOperation: operationMetadata(inputWithRunContext),
837
- agent,
838
- decision: decision.decision,
839
- reasons: [{ code: decision.reason, message: decision.message }],
840
- riskTier: decision.riskTier ?? null,
841
- riskReasonCodes: decision.riskReasonCodes ?? [],
842
- boundary: (decision.boundary ?? null),
843
- auditEvidence: decision.auditEvidence ?? [],
844
- requiresHumanApproval: decision.decision === 'ask',
845
- approvalStatus: decision.decision === 'ask' ? 'pending' : 'not-required',
846
- ...(grantAuthorization === undefined ? {} : { grantEvaluation: grantEvaluationPayload(grantAuthorization.value.evaluation) }),
847
- timestamp,
848
- },
849
- relatedType: 'permission',
850
- relatedId: inputWithRunContext.category,
851
- });
852
- if (!event.ok)
853
- return { ok: false, error: event.error };
854
- if (decision.decision !== 'ask')
855
- return { ok: true, value: { decision, event: event.value } };
856
- const approval = this.runs.createApproval({ runId: inputWithRunContext.runId, decisionEventId: event.value.id });
857
- return approval.ok ? { ok: true, value: { decision, event: event.value, approval: approval.value } } : { ok: false, error: approval.error };
858
- }
859
- validateVgxManagedPreflightMetadata(input) {
860
- const run = this.runs.getById(input.runId);
861
- if (!run.ok)
862
- return { ok: false, error: run.error };
863
- if (!isVgxManagedWorkflow(run.value.workflow) || !isRiskyPermissionCategory(input.category))
864
- return { ok: true, value: undefined };
865
- const missing = [];
866
- if (input.phase === undefined || input.phase.trim().length === 0)
867
- missing.push('phase');
868
- const agentId = input.agentId ?? input.agent?.id;
869
- if (agentId === undefined || agentId.trim().length === 0)
870
- missing.push('agentId');
871
- if (missing.length > 0) {
872
- this.runs.appendEvent({
873
- runId: input.runId,
874
- kind: 'timeline',
875
- title: 'Audit: preflight-missing',
876
- payload: {
877
- eventType: 'preflight-missing',
878
- runId: input.runId,
879
- category: input.category,
880
- operation: input.operation,
881
- missing,
882
- requestedOperation: operationMetadata(input),
883
- executorInvoked: false,
884
- operationExecuted: false,
885
- timestamp: new Date().toISOString(),
886
- },
887
- relatedType: 'preflight',
888
- relatedId: input.category,
889
- });
890
- return validationFailure(`VGX-managed preflight for risky category ${input.category} requires metadata: ${missing.join(', ')}`);
891
- }
892
- return { ok: true, value: undefined };
893
- }
894
- buildPermissionContextForRun(input) {
895
- const run = this.runs.getById(input.runId);
896
- if (!run.ok)
897
- return { ok: false, error: run.error };
898
- const workflow = input.workflow ?? run.value.workflow;
899
- const phase = canonicalRunPhase(workflow, input.phase) ?? canonicalRunPhase(run.value.workflow, run.value.phase);
900
- const merged = {
901
- ...input,
902
- workflow,
903
- ...(phase === undefined ? {} : { phase }),
904
- agentId: input.agentId ?? input.agent?.id ?? run.value.selectedAgentId,
905
- };
906
- return { ok: true, value: merged };
907
- }
908
- appendPreflightAuditEvent(input, outcome, audit) {
909
- const run = this.runs.getById(input.runId);
910
- if (!run.ok || !isVgxManagedWorkflow(run.value.workflow) || !isRiskyPermissionCategory(input.category))
911
- return;
912
- this.runs.appendEvent({
913
- runId: input.runId,
914
- kind: 'timeline',
915
- title: 'Audit: preflight-required',
916
- payload: {
917
- eventType: 'preflight-required',
918
- runId: input.runId,
919
- category: input.category,
920
- operation: input.operation,
921
- phase: input.phase ?? null,
922
- agentId: input.agentId ?? input.agent?.id ?? null,
923
- outcome,
924
- permissionEventId: audit.permissionEventId,
925
- planEventId: audit.planEventId,
926
- approvalId: audit.approvalId ?? null,
927
- executorInvoked: false,
928
- operationExecuted: false,
929
- timestamp: new Date().toISOString(),
930
- },
931
- relatedType: 'preflight',
932
- relatedId: input.category,
933
- });
934
- }
935
- appendPreflightGateAuditEvent(runId, operation, status, message) {
936
- this.runs.appendEvent({
937
- runId,
938
- kind: 'timeline',
939
- title: `Audit: preflight-${status}`,
940
- payload: {
941
- eventType: status === 'missing' ? 'preflight-missing' : 'preflight-blocked',
942
- runId,
943
- category: operation.category,
944
- operation: operation.operation,
945
- preflightStatus: status,
946
- message,
947
- requestedOperation: operationMetadata(operation),
948
- executorInvoked: false,
949
- operationExecuted: false,
950
- timestamp: new Date().toISOString(),
951
- },
952
- relatedType: 'preflight',
953
- relatedId: operation.category,
954
- });
955
- }
956
- evaluateVgxManagedExecutionPreflightGate(input) {
957
- const details = this.runs.getDetails(input.runId);
958
- if (!details.ok)
959
- return details;
960
- if (!isVgxManagedWorkflow(details.value.workflow) || !isRiskyPermissionCategory(input.operation.category))
961
- return { ok: true, value: { blocked: false } };
962
- const matchingPreflight = [...details.value.events].reverse().find((event) => isMatchingPreflightPlanEvent(event, input.operation));
963
- if (matchingPreflight === undefined) {
964
- return {
965
- ok: true,
966
- value: {
967
- blocked: true,
968
- status: 'missing',
969
- message: `VGX-managed risky operation ${input.operation.category} ${input.operation.operation} requires a valid preflight before executor invocation.`,
970
- },
971
- };
972
- }
973
- const status = preflightPlanStatus(matchingPreflight);
974
- if (status === 'blocked') {
975
- return {
976
- ok: true,
977
- value: {
978
- blocked: true,
979
- status,
980
- message: `VGX-managed risky operation ${input.operation.category} ${input.operation.operation} was blocked by its latest preflight.`,
981
- },
982
- };
983
- }
984
- return { ok: true, value: { blocked: false } };
985
- }
986
- findMatchingApproval(input, agent, includePending) {
987
- const details = this.runs.getDetails(input.runId);
988
- if (!details.ok)
989
- return details;
990
- const requestedOperation = operationMetadata(input);
991
- const resolved = details.value.approvals
992
- .filter((approval) => approval.status === 'approved' ||
993
- approval.status === 'rejected' ||
994
- approval.status === 'cancelled' ||
995
- (includePending && approval.status === 'pending'))
996
- .map((approval) => ({ approval, event: details.value.events.find((event) => event.id === approval.decisionEventId) }))
997
- .filter((entry) => entry.event !== undefined && isAskPermissionEvent(entry.event))
998
- .filter((entry) => approvalEventMatches(entry.event, input, requestedOperation, agent))
999
- .sort((left, right) => (right.approval.resolvedAt ?? right.approval.requestedAt).localeCompare(left.approval.resolvedAt ?? left.approval.requestedAt));
1000
- return { ok: true, value: resolved[0] };
1001
- }
1002
- }
1003
- export function calculateStableOperationFingerprint(input) {
1004
- const canonical = {
1005
- runId: input.runId,
1006
- approvalId: input.approvalId,
1007
- category: input.category,
1008
- operation: input.operation,
1009
- };
1010
- if (input.phase !== undefined)
1011
- canonical.phase = input.phase;
1012
- if (input.agentId !== undefined)
1013
- canonical.agentId = input.agentId;
1014
- if (input.workspaceRoot !== undefined)
1015
- canonical.workspaceRoot = input.workspaceRoot;
1016
- if (input.targetPath !== undefined)
1017
- canonical.targetPath = input.targetPath;
1018
- if (input.input !== undefined)
1019
- canonical.input = input.input;
1020
- return `sha256:${createHash('sha256').update(stableJson(canonical)).digest('hex')}`;
1021
- }
1022
- function checkpointHasChangeId(state, change) {
1023
- return typeof state === 'object' && state !== null && !Array.isArray(state) && (state.changeId === change || state.change === change);
1024
- }
1025
- function countByStatus(statuses) {
1026
- const counts = { total: statuses.length };
1027
- for (const status of statuses) {
1028
- if (status === 'pending')
1029
- counts.pending = (counts.pending ?? 0) + 1;
1030
- else if (status === 'approved')
1031
- counts.approved = (counts.approved ?? 0) + 1;
1032
- else if (status === 'rejected')
1033
- counts.rejected = (counts.rejected ?? 0) + 1;
1034
- else if (status === 'cancelled')
1035
- counts.cancelled = (counts.cancelled ?? 0) + 1;
1036
- else if (status === 'reserved')
1037
- counts.reserved = (counts.reserved ?? 0) + 1;
1038
- else if (status === 'succeeded')
1039
- counts.succeeded = (counts.succeeded ?? 0) + 1;
1040
- else if (status === 'failed')
1041
- counts.failed = (counts.failed ?? 0) + 1;
1042
- else if (status === 'abandoned')
1043
- counts.abandoned = (counts.abandoned ?? 0) + 1;
1044
- }
1045
- return counts;
1046
- }
1047
- function preflightOutcome(decision) {
1048
- if (decision.decision === 'allow')
1049
- return 'allowed';
1050
- if (decision.decision === 'deny')
1051
- return 'blocked';
1052
- return 'approval-needed';
1053
- }
1054
- function isVgxManagedWorkflow(workflow) {
1055
- const normalized = workflow.toLowerCase();
1056
- return normalized === 'sdd' || normalized.startsWith('sdd-') || normalized.includes('sdd') || normalized.includes('vgx');
1057
- }
1058
- function workflowConflictDecision(input, runWorkflow) {
1059
- if (input.workflow === undefined || input.workflow === runWorkflow)
1060
- return undefined;
1061
- const eitherSdd = input.workflow === 'sdd' || runWorkflow === 'sdd' || input.workflow.includes('sdd') || runWorkflow.includes('sdd');
1062
- if (!eitherSdd)
1063
- return undefined;
1064
- return {
1065
- decision: 'ask',
1066
- category: input.category,
1067
- operation: input.operation,
1068
- reason: 'workflow_context',
1069
- message: `Explicit workflow ${input.workflow} conflicts with run workflow ${runWorkflow}; human validation is required before crossing SDD/non-SDD context.`,
1070
- workflow: input.workflow,
1071
- warnings: [`workflow-conflict:${runWorkflow}->${input.workflow}`],
1072
- auditEvidence: [`runWorkflow:${runWorkflow}`, `explicitWorkflow:${input.workflow}`],
1073
- };
1074
- }
1075
- function appendApplyProgressAllowlistEvidenceIfNeeded(runs, approvalId, permissionEvent, pendingExecutionEvent, attempt, executionEvent, operationFingerprint, executorName, operation, result) {
1076
- if (!isApplyProgressAllowlistedCommandOperation(operation))
1077
- return { ok: true, value: undefined };
1078
- const base = {
1079
- ...result,
1080
- executionEventId: executionEvent.id,
1081
- audit: {
1082
- metadataOnly: true,
1083
- operationFingerprint,
1084
- executor: executorName,
1085
- approvalId,
1086
- pendingExecutionEventId: pendingExecutionEvent.id,
1087
- permissionEventId: permissionEvent.id,
1088
- attemptId: attempt.id,
1089
- },
1090
- };
1091
- const evidence = runs.appendEvent({
1092
- runId: attempt.runId,
1093
- kind: 'evidence',
1094
- title: `Apply-progress allowlisted command ${attempt.status}: ${operation.operation}`,
1095
- payload: base,
1096
- relatedType: 'operation-attempt',
1097
- relatedId: attempt.id,
1098
- });
1099
- if (!evidence.ok)
1100
- return { ok: false, error: evidence.error };
1101
- const checkpoint = runs.appendCheckpoint({
1102
- runId: attempt.runId,
1103
- label: 'apply-progress-allowlisted-command-executed',
1104
- state: { ...base, evidenceEventId: evidence.value.id },
1105
- });
1106
- if (!checkpoint.ok)
1107
- return { ok: false, error: checkpoint.error };
1108
- return { ok: true, value: { checkpoint: checkpoint.value, evidenceEvent: evidence.value } };
1109
- }
1110
- function isApplyProgressAllowlistedCommandOperation(operation) {
1111
- if (operation.input === undefined)
1112
- return false;
1113
- if (!isObject(operation.input))
1114
- return false;
1115
- return (operation.phase === 'apply-progress' &&
1116
- operation.input.kind === 'apply-progress-operation' &&
1117
- operation.input.operationKind === 'allowlisted-command' &&
1118
- /^command-allowlist:[A-Za-z0-9._/-]+$/u.test(operation.operation));
1119
- }
1120
- function executionPayload(operation, executorName, status, extra) {
1121
- return {
1122
- status,
1123
- executorName,
1124
- requestedOperation: operationMetadata(operation),
1125
- input: operation.input ?? null,
1126
- timestamp: new Date().toISOString(),
1127
- ...extra,
1128
- };
1129
- }
1130
- function operationMetadataWithReplayGuard(operation, replayGuard) {
1131
- const metadata = operationMetadata(operation);
1132
- if (!isObject(metadata))
1133
- return metadata;
1134
- return { ...metadata, replayGuard };
1135
- }
1136
- function replayGuardForApprovedOperation(approval, permissionEvent, pendingExecutionEvent, operation) {
1137
- const fingerprintInput = fingerprintInputForApprovedOperation(approval, permissionEvent, operation);
1138
- const operationFingerprint = calculateStableOperationFingerprint(fingerprintInput);
1139
- return {
1140
- version: 1,
1141
- operationFingerprint,
1142
- fingerprintAlgorithm: 'sha256:stable-json:v1',
1143
- expectedPendingExecutionEventId: pendingExecutionEvent?.id ?? null,
1144
- associated: fingerprintInput,
1145
- };
1146
- }
1147
- function fingerprintInputForApprovedOperation(approval, permissionEvent, operation) {
1148
- const permissionPayload = isObject(permissionEvent.payload) ? permissionEvent.payload : {};
1149
- const requestedOperation = permissionPayload.requestedOperation !== undefined && isObject(permissionPayload.requestedOperation) ? permissionPayload.requestedOperation : {};
1150
- const agent = permissionPayload.agent !== undefined && isObject(permissionPayload.agent) ? permissionPayload.agent : undefined;
1151
- const phase = stringField(operation.phase) ?? stringField(requestedOperation.phase) ?? stringField(permissionPayload.phase);
1152
- const agentId = stringField(operation.agentId) ?? stringField(requestedOperation.agentId) ?? stringField(agent?.id);
1153
- const workspaceRoot = stringField(operation.workspaceRoot) ?? stringField(requestedOperation.workspaceRoot);
1154
- const targetPath = stringField(operation.targetPath) ?? stringField(requestedOperation.targetPath);
1155
- const fingerprintInput = {
1156
- runId: approval.runId,
1157
- approvalId: approval.id,
1158
- category: operation.category,
1159
- operation: operation.operation,
1160
- };
1161
- if (phase !== undefined)
1162
- fingerprintInput.phase = phase;
1163
- if (agentId !== undefined)
1164
- fingerprintInput.agentId = agentId;
1165
- if (workspaceRoot !== undefined)
1166
- fingerprintInput.workspaceRoot = workspaceRoot;
1167
- if (targetPath !== undefined)
1168
- fingerprintInput.targetPath = targetPath;
1169
- if (operation.input !== undefined)
1170
- fingerprintInput.input = operation.input;
1171
- return fingerprintInput;
1172
- }
1173
- function validateReplayGuard(pendingExecutionEvent, replayGuard, expectedOperationFingerprint) {
1174
- const actualFingerprint = replayGuard.operationFingerprint;
1175
- if (expectedOperationFingerprint !== undefined && expectedOperationFingerprint !== actualFingerprint) {
1176
- return validationFailure(`Operation fingerprint mismatch: expected ${expectedOperationFingerprint}, calculated ${actualFingerprint}`);
1177
- }
1178
- if (isObject(pendingExecutionEvent.payload)) {
1179
- const stored = typeof pendingExecutionEvent.payload.operationFingerprint === 'string' ? pendingExecutionEvent.payload.operationFingerprint : undefined;
1180
- const storedReplayGuard = pendingExecutionEvent.payload.replayGuard !== undefined && isObject(pendingExecutionEvent.payload.replayGuard) ? pendingExecutionEvent.payload.replayGuard : undefined;
1181
- const storedReplayFingerprint = typeof storedReplayGuard?.operationFingerprint === 'string' ? storedReplayGuard.operationFingerprint : undefined;
1182
- const storedFingerprint = stored ?? storedReplayFingerprint;
1183
- if (storedFingerprint !== undefined && storedFingerprint !== actualFingerprint) {
1184
- return validationFailure(`Stored operation fingerprint mismatch: stored ${storedFingerprint}, calculated ${actualFingerprint}`);
1185
- }
1186
- }
1187
- return { ok: true, value: undefined };
1188
- }
1189
- function summarizeOperation(operation) {
1190
- return {
1191
- category: operation.category,
1192
- operation: operation.operation,
1193
- ...(operation.input === undefined ? {} : { input: operation.input }),
1194
- };
1195
- }
1196
- function resumeGateNextAction(approval, details, blockers) {
1197
- const approvalBlocker = blockers.find((blocker) => blocker.code === 'approval-not-approved');
1198
- if (approvalBlocker !== undefined) {
1199
- return {
1200
- type: 'resolve-approval',
1201
- command: `runs approve --approval ${approval.id}`,
1202
- reason: approvalBlocker.message,
1203
- };
1204
- }
1205
- const missingContext = blockers.find((blocker) => blocker.code === 'missing-permission-event' || blocker.code === 'missing-pending-operation' || blocker.code === 'operation-metadata-incomplete');
1206
- if (missingContext !== undefined) {
1207
- return {
1208
- type: 'inspect-run',
1209
- command: `runs resume-inspect --id ${details.id}`,
1210
- reason: missingContext.message,
1211
- };
1212
- }
1213
- const retryBlocker = blockers.find((blocker) => blocker.code === 'retry-blocked');
1214
- if (retryBlocker !== undefined) {
1215
- return {
1216
- type: 'retry-check',
1217
- command: `runs retry-check --approval ${approval.id}`,
1218
- reason: retryBlocker.message,
1219
- };
1220
- }
1221
- return {
1222
- type: 'manual-recovery',
1223
- command: `runs retry-check --approval ${approval.id}`,
1224
- reason: 'The operator may manually continue after reviewing retry-check guidance; no execution is performed by this plan.',
1225
- };
1226
- }
1227
- function resumeGateManualNextCommands(approval, details, operation) {
1228
- const commands = [`runs resume-inspect --id ${details.id}`, `runs retry-check --approval ${approval.id}`];
1229
- if (approval.status !== 'approved')
1230
- commands.unshift(`runs approve --approval ${approval.id}`);
1231
- if (operation !== undefined)
1232
- commands.push(`Review operation manually: ${operation.category} ${operation.operation}`);
1233
- return commands;
1234
- }
1235
- function canonicalRunPhase(workflow, phase) {
1236
- if (phase === undefined || phase.trim().length === 0)
1237
- return undefined;
1238
- if (!isSddWorkflow(workflow))
1239
- return phase;
1240
- return normalizeSddPhaseInput(phase) ?? phase;
1241
- }
1242
- function isSddWorkflow(workflow) {
1243
- return workflow?.trim().toLowerCase() === 'sdd';
1244
- }
1245
- function operationMetadata(input) {
1246
- const metadata = { category: input.category, name: input.operation };
1247
- if (input.workspaceRoot !== undefined)
1248
- metadata.workspaceRoot = input.workspaceRoot;
1249
- if (input.targetPath !== undefined)
1250
- metadata.targetPath = input.targetPath;
1251
- if (input.providerToolName !== undefined)
1252
- metadata.providerToolName = input.providerToolName;
1253
- if (input.sandboxStrategy !== undefined)
1254
- metadata.sandboxStrategy = input.sandboxStrategy;
1255
- if (input.workflow !== undefined)
1256
- metadata.workflow = input.workflow;
1257
- if (input.phase !== undefined)
1258
- metadata.phase = input.phase;
1259
- if (input.agentId !== undefined)
1260
- metadata.agentId = input.agentId;
1261
- if (input.taskFingerprint !== undefined)
1262
- metadata.taskFingerprint = input.taskFingerprint;
1263
- if (input.commandId !== undefined)
1264
- metadata.commandId = input.commandId;
1265
- if (input.cwd !== undefined)
1266
- metadata.cwd = input.cwd;
1267
- if (input.targetPaths !== undefined)
1268
- metadata.targetPaths = input.targetPaths;
1269
- if (input.destructive !== undefined)
1270
- metadata.destructive = input.destructive;
1271
- if (input.external !== undefined)
1272
- metadata.external = input.external;
1273
- if (input.privileged !== undefined)
1274
- metadata.privileged = input.privileged;
1275
- if (input.ambiguous !== undefined)
1276
- metadata.ambiguous = input.ambiguous;
1277
- if (input.input !== undefined)
1278
- metadata.input = input.input;
1279
- return metadata;
1280
- }
1281
- function approvalEventMatches(event, input, requestedOperation, agent) {
1282
- if (!isObject(event.payload))
1283
- return false;
1284
- if (event.payload.runId !== input.runId)
1285
- return false;
1286
- if (event.payload.category !== input.category || event.payload.operation !== input.operation)
1287
- return false;
1288
- if (!operationMetadataCompatible(event.payload.requestedOperation, requestedOperation))
1289
- return false;
1290
- if (!jsonEqual(event.payload.agent, agent))
1291
- return false;
1292
- return true;
1293
- }
1294
- function isMatchingPreflightPlanEvent(event, operation) {
1295
- if (event.kind !== 'execution-plan' || !isObject(event.payload))
1296
- return false;
1297
- const requestedOperation = event.payload.requestedOperation;
1298
- return requestedOperation !== undefined && operationMetadataCompatible(requestedOperation, operationMetadata(operation));
1299
- }
1300
- function operationMetadataCompatible(preflightOperation, requestedOperation) {
1301
- if (preflightOperation === undefined || requestedOperation === undefined)
1302
- return jsonEqual(preflightOperation, requestedOperation);
1303
- if (!isObject(preflightOperation) || !isObject(requestedOperation))
1304
- return jsonEqual(preflightOperation, requestedOperation);
1305
- if (preflightOperation.category !== requestedOperation.category || preflightOperation.name !== requestedOperation.name)
1306
- return false;
1307
- const strictKeys = ['workspaceRoot', 'targetPath', 'providerToolName', 'sandboxStrategy', 'taskFingerprint', 'commandId', 'cwd', 'targetPaths', 'destructive', 'external', 'privileged', 'ambiguous'];
1308
- for (const key of strictKeys) {
1309
- if (key in preflightOperation && key in requestedOperation && !jsonEqual(preflightOperation[key], requestedOperation[key]))
1310
- return false;
1311
- }
1312
- if ('input' in preflightOperation && 'input' in requestedOperation && !jsonEqual(preflightOperation.input, requestedOperation.input))
1313
- return false;
1314
- return true;
1315
- }
1316
- function preflightPlanStatus(event) {
1317
- if (!isObject(event.payload))
1318
- return 'blocked';
1319
- const sandboxDecision = event.payload.sandboxDecision;
1320
- if (sandboxDecision !== undefined && isObject(sandboxDecision) && sandboxDecision.decision === 'rejected')
1321
- return 'blocked';
1322
- const plan = event.payload.plan;
1323
- if (plan !== undefined && isObject(plan) && plan.executable === true)
1324
- return 'allowed';
1325
- if (typeof event.payload.approvalId === 'string' && event.payload.approvalId.length > 0)
1326
- return 'approval-needed';
1327
- return 'blocked';
1328
- }
1329
- function jsonEqual(left, right) {
1330
- return stableJson(left ?? null) === stableJson(right ?? null);
1331
- }
1332
- function stableJson(value) {
1333
- if (Array.isArray(value))
1334
- return `[${value.map(stableJson).join(',')}]`;
1335
- if (isObject(value))
1336
- return `{${Object.keys(value)
1337
- .sort()
1338
- .map((key) => `${JSON.stringify(key)}:${stableJson(value[key] ?? null)}`)
1339
- .join(',')}}`;
1340
- return JSON.stringify(value);
1341
- }
1342
- function sandboxDecisionSummary(sandbox) {
1343
- if (sandbox === undefined)
1344
- return undefined;
1345
- return {
1346
- strategy: sandbox.strategy,
1347
- decision: sandbox.decision,
1348
- workspaceRoot: sandbox.workspaceRoot,
1349
- targetPath: sandbox.targetPath ?? null,
1350
- reason: sandbox.reason ?? null,
1351
- validationSummary: sandbox.audit.validationSummary,
1352
- gitBoundary: sandbox.gitBoundary,
1353
- providerConfigMutation: sandbox.providerConfigMutation,
1354
- createsWorktree: sandbox.createsWorktree,
1355
- executesProvider: sandbox.executesProvider,
1356
- };
1357
- }
1358
- function isAskPermissionEvent(event) {
1359
- return event.kind === 'permission-decision' && isObject(event.payload) && event.payload.decision === 'ask';
1360
- }
1361
- function isPendingExecutionEventForApproval(event, approvalId) {
1362
- return (event.kind === 'operation-execution' && isObject(event.payload) && event.payload.status === 'pending-approval' && event.payload.approvalId === approvalId);
1363
- }
1364
- function permissionEventForPendingExecution(details, approval, pendingExecutionEvent) {
1365
- const decisionEventId = isObject(pendingExecutionEvent.payload) && typeof pendingExecutionEvent.payload.decisionEventId === 'string'
1366
- ? pendingExecutionEvent.payload.decisionEventId
1367
- : approval.decisionEventId;
1368
- return details.events.find((event) => event.id === decisionEventId) ?? details.events.find((event) => event.id === approval.decisionEventId);
1369
- }
1370
- function operationFromPendingExecution(payload) {
1371
- if (!isObject(payload))
1372
- return undefined;
1373
- const requestedOperation = payload.requestedOperation;
1374
- if (requestedOperation === undefined || !isObject(requestedOperation))
1375
- return undefined;
1376
- const requested = requestedOperation;
1377
- if (!isPermissionCategory(requested.category) || typeof requested.name !== 'string')
1378
- return undefined;
1379
- const operation = { category: requested.category, operation: requested.name };
1380
- if (typeof requested.workspaceRoot === 'string')
1381
- operation.workspaceRoot = requested.workspaceRoot;
1382
- if (typeof requested.targetPath === 'string')
1383
- operation.targetPath = requested.targetPath;
1384
- if (typeof requested.providerToolName === 'string')
1385
- operation.providerToolName = requested.providerToolName;
1386
- if (typeof requested.phase === 'string')
1387
- operation.phase = requested.phase;
1388
- if (typeof requested.agentId === 'string')
1389
- operation.agentId = requested.agentId;
1390
- if (typeof requested.taskFingerprint === 'string')
1391
- operation.taskFingerprint = requested.taskFingerprint;
1392
- if (typeof requested.commandId === 'string')
1393
- operation.commandId = requested.commandId;
1394
- if (typeof requested.cwd === 'string')
1395
- operation.cwd = requested.cwd;
1396
- if (Array.isArray(requested.targetPaths) && requested.targetPaths.every((item) => typeof item === 'string'))
1397
- operation.targetPaths = requested.targetPaths;
1398
- if (typeof requested.destructive === 'boolean')
1399
- operation.destructive = requested.destructive;
1400
- if (typeof requested.external === 'boolean')
1401
- operation.external = requested.external;
1402
- if (typeof requested.privileged === 'boolean')
1403
- operation.privileged = requested.privileged;
1404
- if (typeof requested.ambiguous === 'boolean')
1405
- operation.ambiguous = requested.ambiguous;
1406
- if ('input' in requested)
1407
- operation.input = requested.input;
1408
- if ('input' in payload && payload.input !== null)
1409
- operation.input = payload.input;
1410
- return operation;
1411
- }
1412
- function stringField(value) {
1413
- return typeof value === 'string' && value.length > 0 ? value : undefined;
1414
- }
1415
- function isObject(value) {
1416
- return typeof value === 'object' && value !== null && !Array.isArray(value);
1417
- }
1418
- function isPermissionCategory(value) {
1419
- return (value === 'read' ||
1420
- value === 'edit' ||
1421
- value === 'implementation-edit' ||
1422
- value === 'spec-write' ||
1423
- value === 'design-write' ||
1424
- value === 'task-write' ||
1425
- value === 'shell' ||
1426
- value === 'test-run' ||
1427
- value === 'install' ||
1428
- value === 'network' ||
1429
- value === 'git' ||
1430
- value === 'git-write' ||
1431
- value === 'memory' ||
1432
- value === 'memory-write' ||
1433
- value === 'external-directory' ||
1434
- value === 'provider-tool' ||
1435
- value === 'secrets');
1436
- }
1437
- function validationFailure(message) {
1438
- return { ok: false, error: { code: 'validation_failed', message } };
1439
- }
1
+ export * from '../application/runs/run-service.js';