oxe-cc 1.0.0 → 1.3.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 (322) hide show
  1. package/.cursor/commands/oxe-ask.md +3 -3
  2. package/.cursor/commands/oxe-capabilities.md +3 -3
  3. package/.cursor/commands/oxe-checkpoint.md +3 -3
  4. package/.cursor/commands/oxe-compact.md +3 -3
  5. package/.cursor/commands/oxe-dashboard.md +3 -3
  6. package/.cursor/commands/oxe-debug.md +3 -3
  7. package/.cursor/commands/oxe-discuss.md +3 -3
  8. package/.cursor/commands/oxe-execute.md +7 -4
  9. package/.cursor/commands/oxe-forensics.md +3 -3
  10. package/.cursor/commands/oxe-help.md +3 -3
  11. package/.cursor/commands/oxe-loop.md +3 -3
  12. package/.cursor/commands/oxe-milestone.md +3 -3
  13. package/.cursor/commands/oxe-next.md +3 -3
  14. package/.cursor/commands/oxe-obs.md +3 -3
  15. package/.cursor/commands/oxe-plan-agent.md +3 -3
  16. package/.cursor/commands/oxe-plan.md +3 -3
  17. package/.cursor/commands/oxe-project.md +3 -3
  18. package/.cursor/commands/oxe-quick.md +3 -3
  19. package/.cursor/commands/oxe-research.md +3 -3
  20. package/.cursor/commands/oxe-retro.md +3 -3
  21. package/.cursor/commands/oxe-review-pr.md +3 -3
  22. package/.cursor/commands/oxe-route.md +3 -3
  23. package/.cursor/commands/oxe-scan.md +3 -3
  24. package/.cursor/commands/oxe-security.md +3 -3
  25. package/.cursor/commands/oxe-session.md +4 -4
  26. package/.cursor/commands/oxe-ship.md +45 -0
  27. package/.cursor/commands/oxe-skill.md +3 -3
  28. package/.cursor/commands/oxe-spec.md +3 -3
  29. package/.cursor/commands/oxe-ui-review.md +3 -3
  30. package/.cursor/commands/oxe-ui-spec.md +3 -3
  31. package/.cursor/commands/oxe-update.md +3 -3
  32. package/.cursor/commands/oxe-validate-gaps.md +3 -3
  33. package/.cursor/commands/oxe-verify.md +6 -3
  34. package/.cursor/commands/oxe-workstream.md +3 -3
  35. package/.cursor/commands/oxe.md +6 -6
  36. package/.github/copilot-instructions.md +94 -4
  37. package/.github/prompts/oxe-ask.prompt.md +3 -3
  38. package/.github/prompts/oxe-capabilities.prompt.md +3 -3
  39. package/.github/prompts/oxe-checkpoint.prompt.md +3 -3
  40. package/.github/prompts/oxe-compact.prompt.md +3 -3
  41. package/.github/prompts/oxe-dashboard.prompt.md +3 -3
  42. package/.github/prompts/oxe-debug.prompt.md +3 -3
  43. package/.github/prompts/oxe-discuss.prompt.md +3 -3
  44. package/.github/prompts/oxe-execute.prompt.md +7 -4
  45. package/.github/prompts/oxe-forensics.prompt.md +3 -3
  46. package/.github/prompts/oxe-help.prompt.md +3 -3
  47. package/.github/prompts/oxe-loop.prompt.md +3 -3
  48. package/.github/prompts/oxe-milestone.prompt.md +3 -3
  49. package/.github/prompts/oxe-next.prompt.md +3 -3
  50. package/.github/prompts/oxe-obs.prompt.md +3 -3
  51. package/.github/prompts/oxe-plan-agent.prompt.md +3 -3
  52. package/.github/prompts/oxe-plan.prompt.md +3 -3
  53. package/.github/prompts/oxe-project.prompt.md +3 -3
  54. package/.github/prompts/oxe-quick.prompt.md +3 -3
  55. package/.github/prompts/oxe-research.prompt.md +3 -3
  56. package/.github/prompts/oxe-retro.prompt.md +3 -3
  57. package/.github/prompts/oxe-review-pr.prompt.md +3 -3
  58. package/.github/prompts/oxe-route.prompt.md +3 -3
  59. package/.github/prompts/oxe-scan.prompt.md +3 -3
  60. package/.github/prompts/oxe-security.prompt.md +3 -3
  61. package/.github/prompts/oxe-session.prompt.md +4 -4
  62. package/.github/prompts/oxe-ship.prompt.md +45 -0
  63. package/.github/prompts/oxe-skill.prompt.md +3 -3
  64. package/.github/prompts/oxe-spec.prompt.md +3 -3
  65. package/.github/prompts/oxe-ui-review.prompt.md +3 -3
  66. package/.github/prompts/oxe-ui-spec.prompt.md +3 -3
  67. package/.github/prompts/oxe-update.prompt.md +3 -3
  68. package/.github/prompts/oxe-validate-gaps.prompt.md +3 -3
  69. package/.github/prompts/oxe-verify.prompt.md +6 -3
  70. package/.github/prompts/oxe-workstream.prompt.md +3 -3
  71. package/.github/prompts/oxe.prompt.md +5 -5
  72. package/AGENTS.md +43 -28
  73. package/CHANGELOG.md +193 -0
  74. package/README.md +610 -529
  75. package/bin/banner.txt +1 -1
  76. package/bin/lib/oxe-agent-install.cjs +69 -69
  77. package/bin/lib/oxe-azure.cjs +1445 -1445
  78. package/bin/lib/oxe-context-engine.cjs +867 -867
  79. package/bin/lib/oxe-dashboard.cjs +76 -28
  80. package/bin/lib/oxe-operational.cjs +2144 -1340
  81. package/bin/lib/oxe-project-health.cjs +483 -1
  82. package/bin/lib/oxe-runtime-semantics.cjs +12 -0
  83. package/bin/oxe-cc.js +554 -152
  84. package/commands/oxe/ask.md +7 -3
  85. package/commands/oxe/capabilities.md +2 -2
  86. package/commands/oxe/checkpoint.md +3 -3
  87. package/commands/oxe/compact.md +3 -3
  88. package/commands/oxe/dashboard.md +2 -2
  89. package/commands/oxe/debug.md +3 -3
  90. package/commands/oxe/discuss.md +2 -2
  91. package/commands/oxe/execute.md +7 -4
  92. package/commands/oxe/forensics.md +3 -3
  93. package/commands/oxe/help.md +2 -2
  94. package/commands/oxe/loop.md +3 -3
  95. package/commands/oxe/milestone.md +3 -3
  96. package/commands/oxe/next.md +3 -3
  97. package/commands/oxe/obs.md +3 -3
  98. package/commands/oxe/oxe.md +5 -5
  99. package/commands/oxe/plan-agent.md +2 -2
  100. package/commands/oxe/plan.md +2 -2
  101. package/commands/oxe/project.md +3 -3
  102. package/commands/oxe/quick.md +2 -2
  103. package/commands/oxe/research.md +3 -3
  104. package/commands/oxe/retro.md +3 -3
  105. package/commands/oxe/review-pr.md +3 -3
  106. package/commands/oxe/route.md +3 -3
  107. package/commands/oxe/scan.md +3 -3
  108. package/commands/oxe/security.md +3 -3
  109. package/commands/oxe/session.md +4 -4
  110. package/commands/oxe/ship.md +49 -0
  111. package/commands/oxe/skill.md +2 -2
  112. package/commands/oxe/spec.md +4 -4
  113. package/commands/oxe/ui-review.md +3 -3
  114. package/commands/oxe/ui-spec.md +3 -3
  115. package/commands/oxe/update.md +2 -2
  116. package/commands/oxe/validate-gaps.md +3 -3
  117. package/commands/oxe/verify.md +7 -4
  118. package/commands/oxe/workstream.md +3 -3
  119. package/lib/runtime/audit/audit-trail.d.ts +71 -0
  120. package/lib/runtime/audit/audit-trail.js +154 -0
  121. package/lib/runtime/audit/index.d.ts +2 -0
  122. package/lib/runtime/audit/index.js +18 -0
  123. package/lib/runtime/audit/policy-pack.d.ts +15 -0
  124. package/lib/runtime/audit/policy-pack.js +57 -0
  125. package/lib/runtime/context/context-pack-builder.d.ts +15 -0
  126. package/lib/runtime/context/context-pack-builder.js +42 -0
  127. package/lib/runtime/context/context-pack-store.d.ts +38 -0
  128. package/lib/runtime/context/context-pack-store.js +142 -0
  129. package/lib/runtime/context/context-profiles.d.ts +11 -0
  130. package/lib/runtime/context/context-profiles.js +51 -0
  131. package/lib/runtime/context/index.d.ts +2 -0
  132. package/lib/runtime/context/index.js +2 -0
  133. package/lib/runtime/decision/decision-engine.d.ts +43 -0
  134. package/lib/runtime/decision/decision-engine.js +127 -0
  135. package/lib/runtime/decision/decision-memo.d.ts +53 -0
  136. package/lib/runtime/decision/decision-memo.js +173 -0
  137. package/lib/runtime/decision/index.d.ts +2 -0
  138. package/lib/runtime/decision/index.js +18 -0
  139. package/lib/runtime/delivery/branch-manager.d.ts +1 -0
  140. package/lib/runtime/delivery/branch-manager.js +7 -0
  141. package/lib/runtime/delivery/ci-checks.js +34 -1
  142. package/lib/runtime/delivery/delivery-records.d.ts +34 -0
  143. package/lib/runtime/delivery/delivery-records.js +48 -0
  144. package/lib/runtime/delivery/index.d.ts +2 -0
  145. package/lib/runtime/delivery/index.js +2 -0
  146. package/lib/runtime/delivery/promotion-pipeline.d.ts +63 -0
  147. package/lib/runtime/delivery/promotion-pipeline.js +224 -0
  148. package/lib/runtime/gate/gate-manager.d.ts +41 -0
  149. package/lib/runtime/gate/gate-manager.js +108 -1
  150. package/lib/runtime/index.d.ts +5 -2
  151. package/lib/runtime/index.js +7 -1
  152. package/lib/runtime/models/gate-decision.d.ts +4 -1
  153. package/lib/runtime/models/workspace.d.ts +3 -0
  154. package/lib/runtime/plugins/capability-adapter.d.ts +12 -0
  155. package/lib/runtime/plugins/capability-adapter.js +204 -0
  156. package/lib/runtime/plugins/capability-matrix.d.ts +25 -0
  157. package/lib/runtime/plugins/capability-matrix.js +90 -0
  158. package/lib/runtime/plugins/index.d.ts +3 -0
  159. package/lib/runtime/plugins/index.js +3 -0
  160. package/lib/runtime/plugins/plugin-abi.d.ts +2 -0
  161. package/lib/runtime/plugins/plugin-manifest.d.ts +22 -0
  162. package/lib/runtime/plugins/plugin-manifest.js +95 -0
  163. package/lib/runtime/plugins/plugin-registry.d.ts +46 -0
  164. package/lib/runtime/plugins/plugin-registry.js +84 -2
  165. package/lib/runtime/policy/policy-engine.d.ts +47 -1
  166. package/lib/runtime/policy/policy-engine.js +172 -9
  167. package/lib/runtime/projection/projection-engine.d.ts +9 -1
  168. package/lib/runtime/projection/projection-engine.js +73 -3
  169. package/lib/runtime/reducers/run-state-reducer.d.ts +26 -0
  170. package/lib/runtime/reducers/run-state-reducer.js +117 -1
  171. package/lib/runtime/scheduler/agent-registry.d.ts +44 -0
  172. package/lib/runtime/scheduler/agent-registry.js +96 -0
  173. package/lib/runtime/scheduler/agent-roles.d.ts +54 -0
  174. package/lib/runtime/scheduler/agent-roles.js +62 -0
  175. package/lib/runtime/scheduler/index.d.ts +3 -0
  176. package/lib/runtime/scheduler/index.js +3 -0
  177. package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +45 -1
  178. package/lib/runtime/scheduler/multi-agent-coordinator.js +234 -35
  179. package/lib/runtime/scheduler/run-journal.d.ts +18 -0
  180. package/lib/runtime/scheduler/run-journal.js +54 -0
  181. package/lib/runtime/scheduler/scheduler.d.ts +29 -1
  182. package/lib/runtime/scheduler/scheduler.js +387 -14
  183. package/lib/runtime/verification/index.d.ts +1 -0
  184. package/lib/runtime/verification/index.js +1 -0
  185. package/lib/runtime/verification/verification-compiler.d.ts +43 -0
  186. package/lib/runtime/verification/verification-compiler.js +137 -0
  187. package/lib/runtime/verification/verification-manifest.d.ts +67 -0
  188. package/lib/runtime/verification/verification-manifest.js +179 -0
  189. package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +1 -0
  190. package/lib/runtime/workspace/strategies/ephemeral-container.js +4 -0
  191. package/lib/runtime/workspace/strategies/git-worktree.d.ts +1 -0
  192. package/lib/runtime/workspace/strategies/git-worktree.js +2 -0
  193. package/lib/runtime/workspace/strategies/inplace.d.ts +1 -0
  194. package/lib/runtime/workspace/strategies/inplace.js +2 -0
  195. package/lib/runtime/workspace/workspace-manager.d.ts +2 -1
  196. package/lib/sdk/README.md +9 -9
  197. package/lib/sdk/index.cjs +33 -24
  198. package/lib/sdk/index.d.ts +149 -14
  199. package/oxe/templates/ACTIVE-RUN.template.json +32 -32
  200. package/oxe/templates/CAPABILITIES.template.md +7 -7
  201. package/oxe/templates/CAPABILITY.template.md +45 -45
  202. package/oxe/templates/CHECKPOINTS.template.md +7 -7
  203. package/oxe/templates/EXECUTION-RUNTIME.template.md +68 -68
  204. package/oxe/templates/HYPOTHESES.template.md +33 -33
  205. package/oxe/templates/LESSONS-METRICS.template.json +13 -13
  206. package/oxe/templates/NOTES.template.md +16 -16
  207. package/oxe/templates/PLAN-REVIEW.template.md +31 -31
  208. package/oxe/templates/SESSION.template.md +34 -34
  209. package/oxe/templates/SKILL.template.md +26 -26
  210. package/oxe/templates/STATE.md +55 -55
  211. package/oxe/templates/WORKFLOW_AUTHORING.md +18 -18
  212. package/oxe/workflows/ask.md +96 -92
  213. package/oxe/workflows/capabilities.md +25 -25
  214. package/oxe/workflows/checkpoint.md +14 -10
  215. package/oxe/workflows/dashboard.md +33 -33
  216. package/oxe/workflows/debug.md +19 -15
  217. package/oxe/workflows/discuss.md +12 -12
  218. package/oxe/workflows/execute.md +44 -2
  219. package/oxe/workflows/forensics.md +13 -9
  220. package/oxe/workflows/help.md +352 -304
  221. package/oxe/workflows/loop.md +17 -13
  222. package/oxe/workflows/next.md +22 -22
  223. package/oxe/workflows/obs.md +4 -0
  224. package/oxe/workflows/oxe.md +64 -31
  225. package/oxe/workflows/plan-agent.md +9 -9
  226. package/oxe/workflows/project.md +6 -1
  227. package/oxe/workflows/quick.md +10 -10
  228. package/oxe/workflows/references/reasoning-discovery.md +28 -28
  229. package/oxe/workflows/references/reasoning-execution.md +29 -29
  230. package/oxe/workflows/references/reasoning-planning.md +32 -32
  231. package/oxe/workflows/references/reasoning-review.md +29 -29
  232. package/oxe/workflows/references/reasoning-status.md +24 -24
  233. package/oxe/workflows/references/robustness-elevation.md +295 -295
  234. package/oxe/workflows/references/workflow-runtime-contracts.json +952 -907
  235. package/oxe/workflows/research.md +32 -28
  236. package/oxe/workflows/retro.md +4 -0
  237. package/oxe/workflows/review-pr.md +15 -11
  238. package/oxe/workflows/route.md +16 -16
  239. package/oxe/workflows/scan.md +4 -0
  240. package/oxe/workflows/security.md +14 -10
  241. package/oxe/workflows/session.md +213 -197
  242. package/oxe/workflows/ship.md +142 -0
  243. package/oxe/workflows/skill.md +44 -44
  244. package/oxe/workflows/spec.md +15 -0
  245. package/oxe/workflows/ui-review.md +20 -16
  246. package/oxe/workflows/ui-spec.md +7 -3
  247. package/oxe/workflows/validate-gaps.md +13 -9
  248. package/oxe/workflows/verify-audit.md +73 -73
  249. package/oxe/workflows/verify.md +52 -3
  250. package/package.json +92 -92
  251. package/packages/runtime/package.json +17 -17
  252. package/packages/runtime/src/audit/audit-trail.ts +243 -0
  253. package/packages/runtime/src/audit/index.ts +2 -0
  254. package/packages/runtime/src/audit/policy-pack.ts +62 -0
  255. package/packages/runtime/src/compiler/graph-compiler.ts +245 -245
  256. package/packages/runtime/src/compiler/index.ts +1 -1
  257. package/packages/runtime/src/context/context-pack-builder.ts +259 -193
  258. package/packages/runtime/src/context/context-pack-store.ts +197 -0
  259. package/packages/runtime/src/context/context-profiles.ts +60 -0
  260. package/packages/runtime/src/context/index.ts +3 -1
  261. package/packages/runtime/src/decision/decision-engine.ts +174 -0
  262. package/packages/runtime/src/decision/decision-memo.ts +211 -0
  263. package/packages/runtime/src/decision/index.ts +2 -0
  264. package/packages/runtime/src/delivery/branch-manager.ts +91 -84
  265. package/packages/runtime/src/delivery/ci-checks.ts +285 -252
  266. package/packages/runtime/src/delivery/delivery-records.ts +75 -0
  267. package/packages/runtime/src/delivery/index.ts +5 -3
  268. package/packages/runtime/src/delivery/pr-manager.ts +112 -112
  269. package/packages/runtime/src/delivery/promotion-pipeline.ts +334 -0
  270. package/packages/runtime/src/events/bus.ts +92 -92
  271. package/packages/runtime/src/events/catalog.ts +29 -29
  272. package/packages/runtime/src/events/envelope.ts +14 -14
  273. package/packages/runtime/src/events/index.ts +3 -3
  274. package/packages/runtime/src/evidence/evidence-store.ts +130 -130
  275. package/packages/runtime/src/evidence/index.ts +1 -1
  276. package/packages/runtime/src/gate/gate-manager.ts +289 -137
  277. package/packages/runtime/src/gate/index.ts +1 -1
  278. package/packages/runtime/src/index.ts +41 -32
  279. package/packages/runtime/src/models/attempt.ts +19 -19
  280. package/packages/runtime/src/models/evidence.ts +21 -21
  281. package/packages/runtime/src/models/gate-decision.ts +25 -21
  282. package/packages/runtime/src/models/index.ts +8 -8
  283. package/packages/runtime/src/models/run.ts +24 -24
  284. package/packages/runtime/src/models/session.ts +11 -11
  285. package/packages/runtime/src/models/verification-result.ts +10 -10
  286. package/packages/runtime/src/models/work-item.ts +25 -25
  287. package/packages/runtime/src/models/workspace.ts +31 -28
  288. package/packages/runtime/src/plugins/capability-adapter.ts +206 -0
  289. package/packages/runtime/src/plugins/capability-matrix.ts +126 -0
  290. package/packages/runtime/src/plugins/index.ts +5 -2
  291. package/packages/runtime/src/plugins/plugin-abi.ts +97 -95
  292. package/packages/runtime/src/plugins/plugin-manifest.ts +118 -0
  293. package/packages/runtime/src/plugins/plugin-registry.ts +232 -119
  294. package/packages/runtime/src/policy/index.ts +1 -1
  295. package/packages/runtime/src/policy/policy-engine.ts +330 -113
  296. package/packages/runtime/src/projection/index.ts +1 -1
  297. package/packages/runtime/src/projection/projection-engine.ts +328 -249
  298. package/packages/runtime/src/reducers/debug-reducer.ts +36 -36
  299. package/packages/runtime/src/reducers/index.ts +2 -2
  300. package/packages/runtime/src/reducers/run-state-reducer.ts +269 -127
  301. package/packages/runtime/src/scheduler/agent-registry.ts +132 -0
  302. package/packages/runtime/src/scheduler/agent-roles.ts +109 -0
  303. package/packages/runtime/src/scheduler/index.ts +4 -1
  304. package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +521 -231
  305. package/packages/runtime/src/scheduler/run-journal.ts +62 -0
  306. package/packages/runtime/src/scheduler/scheduler.ts +722 -281
  307. package/packages/runtime/src/verification/index.ts +2 -1
  308. package/packages/runtime/src/verification/verification-compiler.ts +436 -225
  309. package/packages/runtime/src/verification/verification-manifest.ts +252 -0
  310. package/packages/runtime/src/workspace/index.ts +5 -5
  311. package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +126 -121
  312. package/packages/runtime/src/workspace/strategies/git-worktree.ts +79 -77
  313. package/packages/runtime/src/workspace/strategies/inplace.ts +38 -35
  314. package/packages/runtime/src/workspace/workspace-manager.ts +16 -15
  315. package/packages/runtime/tsconfig.json +17 -17
  316. package/vscode-extension/.vscodeignore +7 -7
  317. package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
  318. package/vscode-extension/package.json +185 -185
  319. package/vscode-extension/src/extension.js +310 -310
  320. package/vscode-extension/src/shared/contextLoader.js +137 -137
  321. package/vscode-extension/src/shared/contractBuilder.js +159 -159
  322. package/vscode-extension/src/shared/stateReader.js +101 -101
@@ -0,0 +1,252 @@
1
+ import crypto from 'crypto';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import type { VerificationStatus } from '../models/verification-result';
5
+ import type { CheckResult } from './verification-compiler';
6
+
7
+ export type VerificationProfile = 'quick' | 'standard' | 'critical';
8
+
9
+ export type FailureClass =
10
+ | 'deterministic'
11
+ | 'flaky'
12
+ | 'timeout'
13
+ | 'env_setup'
14
+ | 'policy_failure'
15
+ | 'evidence_missing';
16
+
17
+ export type VerificationGranularity = 'work_item' | 'wave' | 'run';
18
+
19
+ export interface ManifestCheck {
20
+ check_id: string;
21
+ acceptance_ref: string | null;
22
+ status: VerificationStatus;
23
+ failure_class: FailureClass | null;
24
+ evidence_refs: string[];
25
+ duration_ms: number;
26
+ }
27
+
28
+ export interface VerificationManifest {
29
+ manifest_id: string;
30
+ run_id: string;
31
+ work_item_id: string | null;
32
+ wave: number | null;
33
+ granularity: VerificationGranularity;
34
+ profile: VerificationProfile;
35
+ compiled_at: string;
36
+ checks: ManifestCheck[];
37
+ summary: {
38
+ total: number;
39
+ pass: number;
40
+ fail: number;
41
+ skip: number;
42
+ error: number;
43
+ all_passed: boolean;
44
+ };
45
+ }
46
+
47
+ export interface ResidualRisk {
48
+ risk_id: string;
49
+ work_item_id: string | null;
50
+ check_id: string | null;
51
+ failure_class: FailureClass;
52
+ description: string;
53
+ severity: 'low' | 'medium' | 'high' | 'critical';
54
+ mitigation: string | null;
55
+ }
56
+
57
+ export interface ResidualRiskLedger {
58
+ run_id: string;
59
+ generated_at: string;
60
+ risks: ResidualRisk[];
61
+ }
62
+
63
+ export interface EvidenceCoverageSummary {
64
+ total_checks: number;
65
+ checks_with_evidence: number;
66
+ total_evidence_refs: number;
67
+ coverage_percent: number;
68
+ }
69
+
70
+ function runDir(projectRoot: string, runId: string): string {
71
+ return path.join(projectRoot, '.oxe', 'runs', runId);
72
+ }
73
+
74
+ function manifestPath(projectRoot: string, runId: string): string {
75
+ return path.join(runDir(projectRoot, runId), 'verification-manifest.json');
76
+ }
77
+
78
+ function riskLedgerPath(projectRoot: string, runId: string): string {
79
+ return path.join(runDir(projectRoot, runId), 'residual-risk-ledger.json');
80
+ }
81
+
82
+ function legacyRiskLedgerPath(projectRoot: string, runId: string): string {
83
+ return path.join(runDir(projectRoot, runId), 'residual-risks.json');
84
+ }
85
+
86
+ function evidenceCoveragePath(projectRoot: string, runId: string): string {
87
+ return path.join(runDir(projectRoot, runId), 'evidence-coverage.json');
88
+ }
89
+
90
+ const PROFILE_REQUIRED_CHECKS: Record<VerificationProfile, FailureClass[]> = {
91
+ quick: ['deterministic'],
92
+ standard: ['deterministic', 'policy_failure'],
93
+ critical: ['deterministic', 'policy_failure', 'evidence_missing', 'flaky'],
94
+ };
95
+
96
+ export function classifyFailure(result: CheckResult): FailureClass | null {
97
+ if (result.status === 'pass' || result.status === 'skip') return null;
98
+ if (result.error && (result.error.toLowerCase().includes('timeout') || result.error.toLowerCase().includes('timed out'))) return 'timeout';
99
+ if (result.exit_code === null && result.error) return 'env_setup';
100
+ if (result.stderr.toLowerCase().includes('policy') || result.stderr.toLowerCase().includes('denied')) {
101
+ return 'policy_failure';
102
+ }
103
+ if (result.exit_code !== 0 && result.stderr === '' && result.stdout === '') return 'evidence_missing';
104
+ // Default: non-deterministic signals (no reliable exit code pattern)
105
+ return 'deterministic';
106
+ }
107
+
108
+ export function buildManifest(
109
+ runId: string,
110
+ results: CheckResult[],
111
+ options: {
112
+ workItemId?: string;
113
+ wave?: number;
114
+ granularity?: VerificationGranularity;
115
+ profile?: VerificationProfile;
116
+ evidenceRefs?: Map<string, string[]>;
117
+ } = {}
118
+ ): VerificationManifest {
119
+ const profile = options.profile ?? 'standard';
120
+ const granularity = options.granularity ?? 'run';
121
+ const evidenceRefs = options.evidenceRefs ?? new Map();
122
+
123
+ const checks: ManifestCheck[] = results.map((r) => ({
124
+ check_id: r.check_id,
125
+ acceptance_ref: r.acceptance_ref,
126
+ status: r.status,
127
+ failure_class: classifyFailure(r),
128
+ evidence_refs: evidenceRefs.get(r.check_id) ?? [],
129
+ duration_ms: r.duration_ms,
130
+ }));
131
+
132
+ const summary = {
133
+ total: checks.length,
134
+ pass: checks.filter((c) => c.status === 'pass').length,
135
+ fail: checks.filter((c) => c.status === 'fail').length,
136
+ skip: checks.filter((c) => c.status === 'skip').length,
137
+ error: checks.filter((c) => c.status === 'error').length,
138
+ all_passed: checks.every((c) => c.status === 'pass' || c.status === 'skip'),
139
+ };
140
+
141
+ return {
142
+ manifest_id: `vm-${crypto.randomBytes(4).toString('hex')}`,
143
+ run_id: runId,
144
+ work_item_id: options.workItemId ?? null,
145
+ wave: options.wave ?? null,
146
+ granularity,
147
+ profile,
148
+ compiled_at: new Date().toISOString(),
149
+ checks,
150
+ summary,
151
+ };
152
+ }
153
+
154
+ export function buildRiskLedger(
155
+ runId: string,
156
+ manifest: VerificationManifest
157
+ ): ResidualRiskLedger {
158
+ const risks: ResidualRisk[] = [];
159
+
160
+ for (const check of manifest.checks) {
161
+ if (check.status === 'pass' || check.status === 'skip') continue;
162
+ if (!check.failure_class) continue;
163
+
164
+ const required = PROFILE_REQUIRED_CHECKS[manifest.profile];
165
+ if (!required.includes(check.failure_class)) continue;
166
+
167
+ risks.push({
168
+ risk_id: `risk-${crypto.randomBytes(3).toString('hex')}`,
169
+ work_item_id: manifest.work_item_id,
170
+ check_id: check.check_id,
171
+ failure_class: check.failure_class,
172
+ description: `Check ${check.check_id} ${check.status}: ${check.failure_class}`,
173
+ severity: check.failure_class === 'policy_failure' || check.failure_class === 'deterministic'
174
+ ? 'high'
175
+ : check.failure_class === 'evidence_missing'
176
+ ? 'medium'
177
+ : 'low',
178
+ mitigation: null,
179
+ });
180
+ }
181
+
182
+ return {
183
+ run_id: runId,
184
+ generated_at: new Date().toISOString(),
185
+ risks,
186
+ };
187
+ }
188
+
189
+ export function summarizeEvidenceCoverage(manifest: VerificationManifest): EvidenceCoverageSummary {
190
+ const totalChecks = manifest.checks.length;
191
+ const checksWithEvidence = manifest.checks.filter((check) => check.evidence_refs.length > 0).length;
192
+ const totalEvidenceRefs = manifest.checks.reduce((sum, check) => sum + check.evidence_refs.length, 0);
193
+ const coveragePercent = totalChecks === 0 ? 100 : Math.round((checksWithEvidence / totalChecks) * 100);
194
+ return {
195
+ total_checks: totalChecks,
196
+ checks_with_evidence: checksWithEvidence,
197
+ total_evidence_refs: totalEvidenceRefs,
198
+ coverage_percent: coveragePercent,
199
+ };
200
+ }
201
+
202
+ export function saveManifest(projectRoot: string, runId: string, manifest: VerificationManifest): void {
203
+ const p = manifestPath(projectRoot, runId);
204
+ fs.mkdirSync(path.dirname(p), { recursive: true });
205
+ fs.writeFileSync(p, JSON.stringify(manifest, null, 2), 'utf8');
206
+ }
207
+
208
+ export function loadManifest(projectRoot: string, runId: string): VerificationManifest | null {
209
+ const p = manifestPath(projectRoot, runId);
210
+ if (!fs.existsSync(p)) return null;
211
+ try {
212
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as VerificationManifest;
213
+ } catch {
214
+ return null;
215
+ }
216
+ }
217
+
218
+ export function saveRiskLedger(projectRoot: string, runId: string, ledger: ResidualRiskLedger): void {
219
+ const canonical = riskLedgerPath(projectRoot, runId);
220
+ const legacy = legacyRiskLedgerPath(projectRoot, runId);
221
+ fs.mkdirSync(path.dirname(canonical), { recursive: true });
222
+ fs.writeFileSync(canonical, JSON.stringify(ledger, null, 2), 'utf8');
223
+ fs.writeFileSync(legacy, JSON.stringify(ledger, null, 2), 'utf8');
224
+ }
225
+
226
+ export function loadRiskLedger(projectRoot: string, runId: string): ResidualRiskLedger | null {
227
+ const canonical = riskLedgerPath(projectRoot, runId);
228
+ const legacy = legacyRiskLedgerPath(projectRoot, runId);
229
+ const p = fs.existsSync(canonical) ? canonical : legacy;
230
+ if (!fs.existsSync(p)) return null;
231
+ try {
232
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as ResidualRiskLedger;
233
+ } catch {
234
+ return null;
235
+ }
236
+ }
237
+
238
+ export function saveEvidenceCoverage(projectRoot: string, runId: string, coverage: EvidenceCoverageSummary): void {
239
+ const p = evidenceCoveragePath(projectRoot, runId);
240
+ fs.mkdirSync(path.dirname(p), { recursive: true });
241
+ fs.writeFileSync(p, JSON.stringify(coverage, null, 2), 'utf8');
242
+ }
243
+
244
+ export function loadEvidenceCoverage(projectRoot: string, runId: string): EvidenceCoverageSummary | null {
245
+ const p = evidenceCoveragePath(projectRoot, runId);
246
+ if (!fs.existsSync(p)) return null;
247
+ try {
248
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as EvidenceCoverageSummary;
249
+ } catch {
250
+ return null;
251
+ }
252
+ }
@@ -1,5 +1,5 @@
1
- export * from './workspace-manager';
2
- export { InplaceWorkspaceManager } from './strategies/inplace';
3
- export { GitWorktreeManager } from './strategies/git-worktree';
4
- export { EphemeralContainerManager } from './strategies/ephemeral-container';
5
- export type { ContainerOptions } from './strategies/ephemeral-container';
1
+ export * from './workspace-manager';
2
+ export { InplaceWorkspaceManager } from './strategies/inplace';
3
+ export { GitWorktreeManager } from './strategies/git-worktree';
4
+ export { EphemeralContainerManager } from './strategies/ephemeral-container';
5
+ export type { ContainerOptions } from './strategies/ephemeral-container';
@@ -1,121 +1,126 @@
1
- import { execFileSync, spawnSync } from 'child_process';
2
- import crypto from 'crypto';
3
- import type { WorkspaceManager, WorkspaceRequest } from '../workspace-manager';
4
- import type { WorkspaceLease, SnapshotRef } from '../../models/workspace';
5
- import { GitWorktreeManager } from './git-worktree';
6
-
7
- export interface ContainerOptions {
8
- image: string;
9
- mountPath: string;
10
- extraEnv?: Record<string, string>;
11
- /** Gracefully fall back to git_worktree if Docker is unavailable */
12
- fallback?: boolean;
13
- }
14
-
15
- function isDockerAvailable(): boolean {
16
- const result = spawnSync('docker', ['version', '--format', '{{.Server.Version}}'], {
17
- encoding: 'utf8',
18
- timeout: 5000,
19
- });
20
- return result.status === 0;
21
- }
22
-
23
- export class EphemeralContainerManager implements WorkspaceManager {
24
- private readonly fallbackManager: GitWorktreeManager;
25
- private containerIds = new Map<string, string>();
26
- private useFallback = false;
27
-
28
- constructor(
29
- private readonly projectRoot: string,
30
- private readonly opts: ContainerOptions = { image: 'node:20-alpine', mountPath: '/workspace', fallback: true }
31
- ) {
32
- this.fallbackManager = new GitWorktreeManager(projectRoot);
33
- if (!isDockerAvailable()) {
34
- if (opts.fallback !== false) {
35
- this.useFallback = true;
36
- } else {
37
- throw new Error('Docker is not available and fallback is disabled');
38
- }
39
- }
40
- }
41
-
42
- get usingFallback(): boolean { return this.useFallback; }
43
-
44
- async allocate(req: WorkspaceRequest): Promise<WorkspaceLease> {
45
- if (this.useFallback) return this.fallbackManager.allocate(req);
46
-
47
- const wsId = `ws-container-${req.work_item_id}-a${req.attempt_number}`;
48
- const envArgs = Object.entries(this.opts.extraEnv ?? {}).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
49
-
50
- const result = spawnSync('docker', [
51
- 'run', '-d',
52
- '-v', `${this.projectRoot}:${this.opts.mountPath}`,
53
- '-w', this.opts.mountPath,
54
- ...envArgs,
55
- this.opts.image,
56
- 'sleep', '3600',
57
- ], { encoding: 'utf8' });
58
-
59
- if (result.status !== 0) {
60
- if (this.opts.fallback !== false) {
61
- this.useFallback = true;
62
- return this.fallbackManager.allocate(req);
63
- }
64
- throw new Error(`docker run failed: ${result.stderr}`);
65
- }
66
-
67
- const containerId = result.stdout.trim().slice(0, 12);
68
- this.containerIds.set(wsId, containerId);
69
-
70
- return {
71
- workspace_id: wsId,
72
- strategy: 'ephemeral_container',
73
- branch: null,
74
- base_commit: null,
75
- root_path: `docker:${containerId}:${this.opts.mountPath}`,
76
- ttl_minutes: 60,
77
- };
78
- }
79
-
80
- async snapshot(id: string): Promise<SnapshotRef> {
81
- if (this.useFallback) return this.fallbackManager.snapshot(id);
82
- const containerId = this.containerIds.get(id);
83
- if (!containerId) throw new Error(`Container for workspace ${id} not found`);
84
-
85
- const tag = `oxe-snap-${crypto.randomBytes(4).toString('hex')}`;
86
- execFileSync('docker', ['commit', containerId, tag]);
87
-
88
- return {
89
- snapshot_id: tag,
90
- workspace_id: id,
91
- commit: tag,
92
- created_at: new Date().toISOString(),
93
- };
94
- }
95
-
96
- async reset(id: string, snapRef: SnapshotRef): Promise<void> {
97
- if (this.useFallback) return this.fallbackManager.reset(id, snapRef);
98
- const containerId = this.containerIds.get(id);
99
- if (!containerId) return;
100
- // Stop current container and start from snapshot
101
- spawnSync('docker', ['stop', containerId]);
102
- spawnSync('docker', ['rm', containerId]);
103
- const result = spawnSync('docker', [
104
- 'run', '-d',
105
- '-v', `${this.projectRoot}:${this.opts.mountPath}`,
106
- snapRef.commit,
107
- 'sleep', '3600',
108
- ], { encoding: 'utf8' });
109
- const newId = result.stdout.trim().slice(0, 12);
110
- this.containerIds.set(id, newId);
111
- }
112
-
113
- async dispose(id: string): Promise<void> {
114
- if (this.useFallback) return this.fallbackManager.dispose(id);
115
- const containerId = this.containerIds.get(id);
116
- if (!containerId) return;
117
- spawnSync('docker', ['stop', containerId], { encoding: 'utf8' });
118
- spawnSync('docker', ['rm', containerId], { encoding: 'utf8' });
119
- this.containerIds.delete(id);
120
- }
121
- }
1
+ import { execFileSync, spawnSync } from 'child_process';
2
+ import crypto from 'crypto';
3
+ import type { WorkspaceManager, WorkspaceRequest } from '../workspace-manager';
4
+ import type { WorkspaceLease, SnapshotRef } from '../../models/workspace';
5
+ import { GitWorktreeManager } from './git-worktree';
6
+
7
+ export interface ContainerOptions {
8
+ image: string;
9
+ mountPath: string;
10
+ extraEnv?: Record<string, string>;
11
+ /** Gracefully fall back to git_worktree if Docker is unavailable */
12
+ fallback?: boolean;
13
+ }
14
+
15
+ function isDockerAvailable(): boolean {
16
+ const result = spawnSync('docker', ['version', '--format', '{{.Server.Version}}'], {
17
+ encoding: 'utf8',
18
+ timeout: 5000,
19
+ });
20
+ return result.status === 0;
21
+ }
22
+
23
+ export class EphemeralContainerManager implements WorkspaceManager {
24
+ private readonly fallbackManager: GitWorktreeManager;
25
+ private containerIds = new Map<string, string>();
26
+ private useFallback = false;
27
+
28
+ constructor(
29
+ private readonly projectRoot: string,
30
+ private readonly opts: ContainerOptions = { image: 'node:20-alpine', mountPath: '/workspace', fallback: true }
31
+ ) {
32
+ this.fallbackManager = new GitWorktreeManager(projectRoot);
33
+ if (!isDockerAvailable()) {
34
+ if (opts.fallback !== false) {
35
+ this.useFallback = true;
36
+ } else {
37
+ throw new Error('Docker is not available and fallback is disabled');
38
+ }
39
+ }
40
+ }
41
+
42
+ get isolation_level(): 'shared' | 'isolated' {
43
+ return this.useFallback ? this.fallbackManager.isolation_level : 'isolated';
44
+ }
45
+
46
+ get usingFallback(): boolean { return this.useFallback; }
47
+
48
+ async allocate(req: WorkspaceRequest): Promise<WorkspaceLease> {
49
+ if (this.useFallback) return this.fallbackManager.allocate(req);
50
+
51
+ const wsId = `ws-container-${req.work_item_id}-a${req.attempt_number}`;
52
+ const envArgs = Object.entries(this.opts.extraEnv ?? {}).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
53
+
54
+ const result = spawnSync('docker', [
55
+ 'run', '-d',
56
+ '-v', `${this.projectRoot}:${this.opts.mountPath}`,
57
+ '-w', this.opts.mountPath,
58
+ ...envArgs,
59
+ this.opts.image,
60
+ 'sleep', '3600',
61
+ ], { encoding: 'utf8' });
62
+
63
+ if (result.status !== 0) {
64
+ if (this.opts.fallback !== false) {
65
+ this.useFallback = true;
66
+ return this.fallbackManager.allocate(req);
67
+ }
68
+ throw new Error(`docker run failed: ${result.stderr}`);
69
+ }
70
+
71
+ const containerId = result.stdout.trim().slice(0, 12);
72
+ this.containerIds.set(wsId, containerId);
73
+
74
+ return {
75
+ workspace_id: wsId,
76
+ strategy: 'ephemeral_container',
77
+ isolation_level: this.isolation_level,
78
+ branch: null,
79
+ base_commit: null,
80
+ root_path: `docker:${containerId}:${this.opts.mountPath}`,
81
+ ttl_minutes: 60,
82
+ };
83
+ }
84
+
85
+ async snapshot(id: string): Promise<SnapshotRef> {
86
+ if (this.useFallback) return this.fallbackManager.snapshot(id);
87
+ const containerId = this.containerIds.get(id);
88
+ if (!containerId) throw new Error(`Container for workspace ${id} not found`);
89
+
90
+ const tag = `oxe-snap-${crypto.randomBytes(4).toString('hex')}`;
91
+ execFileSync('docker', ['commit', containerId, tag]);
92
+
93
+ return {
94
+ snapshot_id: tag,
95
+ workspace_id: id,
96
+ commit: tag,
97
+ created_at: new Date().toISOString(),
98
+ };
99
+ }
100
+
101
+ async reset(id: string, snapRef: SnapshotRef): Promise<void> {
102
+ if (this.useFallback) return this.fallbackManager.reset(id, snapRef);
103
+ const containerId = this.containerIds.get(id);
104
+ if (!containerId) return;
105
+ // Stop current container and start from snapshot
106
+ spawnSync('docker', ['stop', containerId]);
107
+ spawnSync('docker', ['rm', containerId]);
108
+ const result = spawnSync('docker', [
109
+ 'run', '-d',
110
+ '-v', `${this.projectRoot}:${this.opts.mountPath}`,
111
+ snapRef.commit,
112
+ 'sleep', '3600',
113
+ ], { encoding: 'utf8' });
114
+ const newId = result.stdout.trim().slice(0, 12);
115
+ this.containerIds.set(id, newId);
116
+ }
117
+
118
+ async dispose(id: string): Promise<void> {
119
+ if (this.useFallback) return this.fallbackManager.dispose(id);
120
+ const containerId = this.containerIds.get(id);
121
+ if (!containerId) return;
122
+ spawnSync('docker', ['stop', containerId], { encoding: 'utf8' });
123
+ spawnSync('docker', ['rm', containerId], { encoding: 'utf8' });
124
+ this.containerIds.delete(id);
125
+ }
126
+ }