oxe-cc 1.2.1 → 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 (276) hide show
  1. package/.cursor/commands/oxe-ask.md +2 -2
  2. package/.cursor/commands/oxe-capabilities.md +2 -2
  3. package/.cursor/commands/oxe-checkpoint.md +2 -2
  4. package/.cursor/commands/oxe-compact.md +2 -2
  5. package/.cursor/commands/oxe-dashboard.md +2 -2
  6. package/.cursor/commands/oxe-debug.md +2 -2
  7. package/.cursor/commands/oxe-discuss.md +2 -2
  8. package/.cursor/commands/oxe-execute.md +5 -2
  9. package/.cursor/commands/oxe-forensics.md +2 -2
  10. package/.cursor/commands/oxe-help.md +2 -2
  11. package/.cursor/commands/oxe-loop.md +2 -2
  12. package/.cursor/commands/oxe-milestone.md +2 -2
  13. package/.cursor/commands/oxe-next.md +2 -2
  14. package/.cursor/commands/oxe-obs.md +2 -2
  15. package/.cursor/commands/oxe-plan-agent.md +2 -2
  16. package/.cursor/commands/oxe-plan.md +2 -2
  17. package/.cursor/commands/oxe-project.md +2 -2
  18. package/.cursor/commands/oxe-quick.md +2 -2
  19. package/.cursor/commands/oxe-research.md +2 -2
  20. package/.cursor/commands/oxe-retro.md +2 -2
  21. package/.cursor/commands/oxe-review-pr.md +2 -2
  22. package/.cursor/commands/oxe-route.md +2 -2
  23. package/.cursor/commands/oxe-scan.md +2 -2
  24. package/.cursor/commands/oxe-security.md +2 -2
  25. package/.cursor/commands/oxe-session.md +2 -2
  26. package/.cursor/commands/oxe-ship.md +2 -2
  27. package/.cursor/commands/oxe-skill.md +2 -2
  28. package/.cursor/commands/oxe-spec.md +2 -2
  29. package/.cursor/commands/oxe-ui-review.md +2 -2
  30. package/.cursor/commands/oxe-ui-spec.md +2 -2
  31. package/.cursor/commands/oxe-update.md +2 -2
  32. package/.cursor/commands/oxe-validate-gaps.md +2 -2
  33. package/.cursor/commands/oxe-verify.md +5 -2
  34. package/.cursor/commands/oxe-workstream.md +2 -2
  35. package/.cursor/commands/oxe.md +2 -2
  36. package/.github/copilot-instructions.md +13 -13
  37. package/.github/prompts/oxe-ask.prompt.md +2 -2
  38. package/.github/prompts/oxe-capabilities.prompt.md +2 -2
  39. package/.github/prompts/oxe-checkpoint.prompt.md +2 -2
  40. package/.github/prompts/oxe-compact.prompt.md +2 -2
  41. package/.github/prompts/oxe-dashboard.prompt.md +2 -2
  42. package/.github/prompts/oxe-debug.prompt.md +2 -2
  43. package/.github/prompts/oxe-discuss.prompt.md +2 -2
  44. package/.github/prompts/oxe-execute.prompt.md +5 -2
  45. package/.github/prompts/oxe-forensics.prompt.md +2 -2
  46. package/.github/prompts/oxe-help.prompt.md +2 -2
  47. package/.github/prompts/oxe-loop.prompt.md +2 -2
  48. package/.github/prompts/oxe-milestone.prompt.md +2 -2
  49. package/.github/prompts/oxe-next.prompt.md +2 -2
  50. package/.github/prompts/oxe-obs.prompt.md +2 -2
  51. package/.github/prompts/oxe-plan-agent.prompt.md +2 -2
  52. package/.github/prompts/oxe-plan.prompt.md +2 -2
  53. package/.github/prompts/oxe-project.prompt.md +2 -2
  54. package/.github/prompts/oxe-quick.prompt.md +2 -2
  55. package/.github/prompts/oxe-research.prompt.md +2 -2
  56. package/.github/prompts/oxe-retro.prompt.md +2 -2
  57. package/.github/prompts/oxe-review-pr.prompt.md +2 -2
  58. package/.github/prompts/oxe-route.prompt.md +2 -2
  59. package/.github/prompts/oxe-scan.prompt.md +2 -2
  60. package/.github/prompts/oxe-security.prompt.md +2 -2
  61. package/.github/prompts/oxe-session.prompt.md +2 -2
  62. package/.github/prompts/oxe-ship.prompt.md +2 -2
  63. package/.github/prompts/oxe-skill.prompt.md +2 -2
  64. package/.github/prompts/oxe-spec.prompt.md +2 -2
  65. package/.github/prompts/oxe-ui-review.prompt.md +2 -2
  66. package/.github/prompts/oxe-ui-spec.prompt.md +2 -2
  67. package/.github/prompts/oxe-update.prompt.md +2 -2
  68. package/.github/prompts/oxe-validate-gaps.prompt.md +2 -2
  69. package/.github/prompts/oxe-verify.prompt.md +5 -2
  70. package/.github/prompts/oxe-workstream.prompt.md +2 -2
  71. package/.github/prompts/oxe.prompt.md +2 -2
  72. package/CHANGELOG.md +52 -17
  73. package/README.md +610 -551
  74. package/bin/banner.txt +1 -1
  75. package/bin/lib/oxe-agent-install.cjs +69 -69
  76. package/bin/lib/oxe-azure.cjs +1445 -1445
  77. package/bin/lib/oxe-context-engine.cjs +867 -867
  78. package/bin/lib/oxe-dashboard.cjs +76 -28
  79. package/bin/lib/oxe-operational.cjs +2144 -1340
  80. package/bin/lib/oxe-project-health.cjs +483 -1
  81. package/bin/lib/oxe-runtime-semantics.cjs +12 -0
  82. package/bin/oxe-cc.js +554 -152
  83. package/commands/oxe/ask.md +2 -2
  84. package/commands/oxe/capabilities.md +2 -2
  85. package/commands/oxe/checkpoint.md +2 -2
  86. package/commands/oxe/compact.md +2 -2
  87. package/commands/oxe/dashboard.md +2 -2
  88. package/commands/oxe/debug.md +2 -2
  89. package/commands/oxe/discuss.md +2 -2
  90. package/commands/oxe/execute.md +5 -2
  91. package/commands/oxe/forensics.md +2 -2
  92. package/commands/oxe/help.md +2 -2
  93. package/commands/oxe/loop.md +2 -2
  94. package/commands/oxe/milestone.md +2 -2
  95. package/commands/oxe/next.md +2 -2
  96. package/commands/oxe/obs.md +2 -2
  97. package/commands/oxe/oxe.md +2 -2
  98. package/commands/oxe/plan-agent.md +2 -2
  99. package/commands/oxe/plan.md +2 -2
  100. package/commands/oxe/project.md +2 -2
  101. package/commands/oxe/quick.md +2 -2
  102. package/commands/oxe/research.md +2 -2
  103. package/commands/oxe/retro.md +2 -2
  104. package/commands/oxe/review-pr.md +2 -2
  105. package/commands/oxe/route.md +2 -2
  106. package/commands/oxe/scan.md +2 -2
  107. package/commands/oxe/security.md +2 -2
  108. package/commands/oxe/session.md +2 -2
  109. package/commands/oxe/ship.md +2 -2
  110. package/commands/oxe/skill.md +2 -2
  111. package/commands/oxe/spec.md +2 -2
  112. package/commands/oxe/ui-review.md +2 -2
  113. package/commands/oxe/ui-spec.md +2 -2
  114. package/commands/oxe/update.md +2 -2
  115. package/commands/oxe/validate-gaps.md +2 -2
  116. package/commands/oxe/verify.md +5 -2
  117. package/commands/oxe/workstream.md +2 -2
  118. package/lib/runtime/delivery/branch-manager.d.ts +1 -0
  119. package/lib/runtime/delivery/branch-manager.js +7 -0
  120. package/lib/runtime/delivery/ci-checks.js +34 -1
  121. package/lib/runtime/delivery/delivery-records.d.ts +34 -0
  122. package/lib/runtime/delivery/delivery-records.js +48 -0
  123. package/lib/runtime/delivery/index.d.ts +1 -0
  124. package/lib/runtime/delivery/index.js +1 -0
  125. package/lib/runtime/delivery/promotion-pipeline.d.ts +26 -2
  126. package/lib/runtime/delivery/promotion-pipeline.js +111 -14
  127. package/lib/runtime/gate/gate-manager.d.ts +41 -0
  128. package/lib/runtime/gate/gate-manager.js +108 -1
  129. package/lib/runtime/index.d.ts +2 -2
  130. package/lib/runtime/index.js +3 -1
  131. package/lib/runtime/models/gate-decision.d.ts +4 -1
  132. package/lib/runtime/models/workspace.d.ts +3 -0
  133. package/lib/runtime/plugins/capability-adapter.d.ts +12 -0
  134. package/lib/runtime/plugins/capability-adapter.js +204 -0
  135. package/lib/runtime/plugins/capability-matrix.d.ts +5 -0
  136. package/lib/runtime/plugins/capability-matrix.js +48 -17
  137. package/lib/runtime/plugins/index.d.ts +1 -0
  138. package/lib/runtime/plugins/index.js +1 -0
  139. package/lib/runtime/plugins/plugin-abi.d.ts +2 -0
  140. package/lib/runtime/plugins/plugin-manifest.d.ts +1 -1
  141. package/lib/runtime/plugins/plugin-manifest.js +6 -2
  142. package/lib/runtime/plugins/plugin-registry.d.ts +46 -0
  143. package/lib/runtime/plugins/plugin-registry.js +79 -2
  144. package/lib/runtime/policy/policy-engine.d.ts +19 -0
  145. package/lib/runtime/policy/policy-engine.js +76 -4
  146. package/lib/runtime/projection/projection-engine.d.ts +9 -1
  147. package/lib/runtime/projection/projection-engine.js +73 -3
  148. package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +43 -1
  149. package/lib/runtime/scheduler/multi-agent-coordinator.js +151 -39
  150. package/lib/runtime/scheduler/run-journal.d.ts +1 -1
  151. package/lib/runtime/scheduler/scheduler.d.ts +19 -1
  152. package/lib/runtime/scheduler/scheduler.js +258 -13
  153. package/lib/runtime/verification/verification-compiler.d.ts +43 -0
  154. package/lib/runtime/verification/verification-compiler.js +137 -0
  155. package/lib/runtime/verification/verification-manifest.d.ts +9 -0
  156. package/lib/runtime/verification/verification-manifest.js +56 -6
  157. package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +1 -0
  158. package/lib/runtime/workspace/strategies/ephemeral-container.js +4 -0
  159. package/lib/runtime/workspace/strategies/git-worktree.d.ts +1 -0
  160. package/lib/runtime/workspace/strategies/git-worktree.js +2 -0
  161. package/lib/runtime/workspace/strategies/inplace.d.ts +1 -0
  162. package/lib/runtime/workspace/strategies/inplace.js +2 -0
  163. package/lib/runtime/workspace/workspace-manager.d.ts +2 -1
  164. package/lib/sdk/README.md +9 -9
  165. package/lib/sdk/index.cjs +33 -24
  166. package/lib/sdk/index.d.ts +149 -14
  167. package/oxe/templates/ACTIVE-RUN.template.json +32 -32
  168. package/oxe/templates/CAPABILITIES.template.md +7 -7
  169. package/oxe/templates/CAPABILITY.template.md +45 -45
  170. package/oxe/templates/CHECKPOINTS.template.md +7 -7
  171. package/oxe/templates/EXECUTION-RUNTIME.template.md +68 -68
  172. package/oxe/templates/HYPOTHESES.template.md +33 -33
  173. package/oxe/templates/LESSONS-METRICS.template.json +13 -13
  174. package/oxe/templates/NOTES.template.md +16 -16
  175. package/oxe/templates/PLAN-REVIEW.template.md +31 -31
  176. package/oxe/templates/SESSION.template.md +34 -34
  177. package/oxe/templates/SKILL.template.md +26 -26
  178. package/oxe/templates/STATE.md +55 -55
  179. package/oxe/templates/WORKFLOW_AUTHORING.md +18 -18
  180. package/oxe/workflows/ask.md +96 -96
  181. package/oxe/workflows/capabilities.md +25 -25
  182. package/oxe/workflows/dashboard.md +33 -33
  183. package/oxe/workflows/discuss.md +12 -12
  184. package/oxe/workflows/execute.md +14 -0
  185. package/oxe/workflows/help.md +352 -352
  186. package/oxe/workflows/next.md +22 -22
  187. package/oxe/workflows/oxe.md +6 -6
  188. package/oxe/workflows/plan-agent.md +9 -9
  189. package/oxe/workflows/quick.md +10 -10
  190. package/oxe/workflows/references/reasoning-discovery.md +28 -28
  191. package/oxe/workflows/references/reasoning-execution.md +29 -29
  192. package/oxe/workflows/references/reasoning-planning.md +32 -32
  193. package/oxe/workflows/references/reasoning-review.md +29 -29
  194. package/oxe/workflows/references/reasoning-status.md +24 -24
  195. package/oxe/workflows/references/robustness-elevation.md +295 -295
  196. package/oxe/workflows/references/workflow-runtime-contracts.json +952 -930
  197. package/oxe/workflows/route.md +16 -16
  198. package/oxe/workflows/session.md +213 -213
  199. package/oxe/workflows/ship.md +142 -142
  200. package/oxe/workflows/skill.md +44 -44
  201. package/oxe/workflows/ui-review.md +36 -36
  202. package/oxe/workflows/verify-audit.md +73 -73
  203. package/oxe/workflows/verify.md +10 -0
  204. package/package.json +92 -92
  205. package/packages/runtime/package.json +17 -17
  206. package/packages/runtime/src/audit/audit-trail.ts +243 -243
  207. package/packages/runtime/src/audit/index.ts +2 -2
  208. package/packages/runtime/src/audit/policy-pack.ts +62 -62
  209. package/packages/runtime/src/compiler/graph-compiler.ts +245 -245
  210. package/packages/runtime/src/compiler/index.ts +1 -1
  211. package/packages/runtime/src/context/context-pack-builder.ts +259 -259
  212. package/packages/runtime/src/context/context-pack-store.ts +197 -197
  213. package/packages/runtime/src/context/context-profiles.ts +60 -60
  214. package/packages/runtime/src/context/index.ts +3 -3
  215. package/packages/runtime/src/decision/decision-engine.ts +174 -174
  216. package/packages/runtime/src/decision/decision-memo.ts +211 -211
  217. package/packages/runtime/src/decision/index.ts +2 -2
  218. package/packages/runtime/src/delivery/branch-manager.ts +91 -84
  219. package/packages/runtime/src/delivery/ci-checks.ts +285 -252
  220. package/packages/runtime/src/delivery/delivery-records.ts +75 -0
  221. package/packages/runtime/src/delivery/index.ts +5 -4
  222. package/packages/runtime/src/delivery/pr-manager.ts +112 -112
  223. package/packages/runtime/src/delivery/promotion-pipeline.ts +334 -180
  224. package/packages/runtime/src/events/bus.ts +92 -92
  225. package/packages/runtime/src/events/catalog.ts +29 -29
  226. package/packages/runtime/src/events/envelope.ts +14 -14
  227. package/packages/runtime/src/events/index.ts +3 -3
  228. package/packages/runtime/src/evidence/evidence-store.ts +130 -130
  229. package/packages/runtime/src/evidence/index.ts +1 -1
  230. package/packages/runtime/src/gate/gate-manager.ts +289 -137
  231. package/packages/runtime/src/gate/index.ts +1 -1
  232. package/packages/runtime/src/index.ts +41 -37
  233. package/packages/runtime/src/models/attempt.ts +19 -19
  234. package/packages/runtime/src/models/evidence.ts +21 -21
  235. package/packages/runtime/src/models/gate-decision.ts +25 -21
  236. package/packages/runtime/src/models/index.ts +8 -8
  237. package/packages/runtime/src/models/run.ts +24 -24
  238. package/packages/runtime/src/models/session.ts +11 -11
  239. package/packages/runtime/src/models/verification-result.ts +10 -10
  240. package/packages/runtime/src/models/work-item.ts +25 -25
  241. package/packages/runtime/src/models/workspace.ts +31 -28
  242. package/packages/runtime/src/plugins/capability-adapter.ts +206 -0
  243. package/packages/runtime/src/plugins/capability-matrix.ts +126 -83
  244. package/packages/runtime/src/plugins/index.ts +5 -4
  245. package/packages/runtime/src/plugins/plugin-abi.ts +97 -95
  246. package/packages/runtime/src/plugins/plugin-manifest.ts +118 -113
  247. package/packages/runtime/src/plugins/plugin-registry.ts +232 -124
  248. package/packages/runtime/src/policy/index.ts +1 -1
  249. package/packages/runtime/src/policy/policy-engine.ts +330 -244
  250. package/packages/runtime/src/projection/index.ts +1 -1
  251. package/packages/runtime/src/projection/projection-engine.ts +328 -249
  252. package/packages/runtime/src/reducers/debug-reducer.ts +36 -36
  253. package/packages/runtime/src/reducers/index.ts +2 -2
  254. package/packages/runtime/src/reducers/run-state-reducer.ts +269 -269
  255. package/packages/runtime/src/scheduler/agent-registry.ts +132 -132
  256. package/packages/runtime/src/scheduler/agent-roles.ts +109 -109
  257. package/packages/runtime/src/scheduler/index.ts +4 -4
  258. package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +521 -333
  259. package/packages/runtime/src/scheduler/run-journal.ts +62 -62
  260. package/packages/runtime/src/scheduler/scheduler.ts +722 -441
  261. package/packages/runtime/src/verification/index.ts +2 -2
  262. package/packages/runtime/src/verification/verification-compiler.ts +436 -225
  263. package/packages/runtime/src/verification/verification-manifest.ts +252 -192
  264. package/packages/runtime/src/workspace/index.ts +5 -5
  265. package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +126 -121
  266. package/packages/runtime/src/workspace/strategies/git-worktree.ts +79 -77
  267. package/packages/runtime/src/workspace/strategies/inplace.ts +38 -35
  268. package/packages/runtime/src/workspace/workspace-manager.ts +16 -15
  269. package/packages/runtime/tsconfig.json +17 -17
  270. package/vscode-extension/.vscodeignore +7 -7
  271. package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
  272. package/vscode-extension/package.json +185 -185
  273. package/vscode-extension/src/extension.js +310 -310
  274. package/vscode-extension/src/shared/contextLoader.js +137 -137
  275. package/vscode-extension/src/shared/contractBuilder.js +159 -159
  276. package/vscode-extension/src/shared/stateReader.js +101 -101
@@ -1,2 +1,2 @@
1
- export * from './verification-compiler';
2
- export * from './verification-manifest';
1
+ export * from './verification-compiler';
2
+ export * from './verification-manifest';
@@ -1,225 +1,436 @@
1
- import crypto from 'crypto';
2
- import { spawnSync } from 'child_process';
3
- import type { EvidenceType } from '../models/evidence';
4
- import type { VerificationStatus } from '../models/verification-result';
5
-
6
- export type CheckType =
7
- | 'unit'
8
- | 'integration'
9
- | 'contract'
10
- | 'smoke'
11
- | 'policy'
12
- | 'security'
13
- | 'ux_snapshot'
14
- | 'performance_baseline'
15
- | 'custom';
16
-
17
- export interface AcceptanceCheck {
18
- id: string;
19
- type: CheckType;
20
- command: string | null;
21
- evidence_type_expected: EvidenceType;
22
- acceptance_ref: string | null;
23
- description: string;
24
- }
25
-
26
- export interface AcceptanceCheckSuite {
27
- checks: AcceptanceCheck[];
28
- compiled_at: string;
29
- spec_hash: string;
30
- plan_hash: string;
31
- }
32
-
33
- export interface CheckResult {
34
- check_id: string;
35
- acceptance_ref: string | null;
36
- status: VerificationStatus;
37
- stdout: string;
38
- stderr: string;
39
- exit_code: number | null;
40
- duration_ms: number;
41
- error: string | null;
42
- }
43
-
44
- // Mirror of ParsedSpec/ParsedPlan (same as in graph-compiler to avoid circular deps)
45
- interface Criterion {
46
- id: string;
47
- criterion: string;
48
- howToVerify: string;
49
- }
50
-
51
- interface ParsedSpecLike {
52
- objective: string | null;
53
- criteria: Criterion[];
54
- }
55
-
56
- interface ParsedTaskLike {
57
- id: string;
58
- verifyCommand: string | null;
59
- aceite: string[];
60
- }
61
-
62
- interface ParsedPlanLike {
63
- tasks: ParsedTaskLike[];
64
- }
65
-
66
- function inferCheckType(howToVerify: string): CheckType {
67
- const v = howToVerify.toLowerCase();
68
- if (v.includes('npm test') || v.includes('jest') || v.includes('vitest') || v.includes('node --test')) return 'unit';
69
- if (v.includes('postman') || v.includes('newman') || v.includes('integration')) return 'integration';
70
- if (v.includes('smoke') || v.includes('curl')) return 'smoke';
71
- if (v.includes('eslint') || v.includes('lint') || v.includes('oxe-policy')) return 'policy';
72
- if (v.includes('security') || v.includes('audit') || v.includes('trivy')) return 'security';
73
- return 'custom';
74
- }
75
-
76
- function inferEvidenceType(checkType: CheckType): EvidenceType {
77
- switch (checkType) {
78
- case 'unit': return 'junit_xml';
79
- case 'integration': return 'api_output';
80
- case 'security': return 'security_report';
81
- case 'policy': return 'log';
82
- default: return 'stdout';
83
- }
84
- }
85
-
86
- export function compile(
87
- spec: ParsedSpecLike,
88
- plan: ParsedPlanLike
89
- ): AcceptanceCheckSuite {
90
- const checks: AcceptanceCheck[] = [];
91
- const seenRefs = new Set<string>();
92
-
93
- // Generate checks from spec criteria
94
- for (const criterion of spec.criteria) {
95
- // Find the verify command from the task that references this criterion
96
- const task = plan.tasks.find((t) => t.aceite.includes(criterion.id));
97
- const command = task?.verifyCommand ?? null;
98
- const type = inferCheckType(criterion.howToVerify);
99
-
100
- checks.push({
101
- id: `check-${criterion.id.toLowerCase()}`,
102
- type,
103
- command: command ?? (criterion.howToVerify.startsWith('#') ? null : criterion.howToVerify),
104
- evidence_type_expected: inferEvidenceType(type),
105
- acceptance_ref: criterion.id,
106
- description: criterion.criterion,
107
- });
108
- seenRefs.add(criterion.id);
109
- }
110
-
111
- // Add checks for task verify commands not already covered
112
- for (const task of plan.tasks) {
113
- if (!task.verifyCommand) continue;
114
- const uncovered = task.aceite.filter((ref) => !seenRefs.has(ref));
115
- if (uncovered.length === 0 && checks.some((c) => c.command === task.verifyCommand)) continue;
116
-
117
- checks.push({
118
- id: `check-task-${task.id.toLowerCase()}`,
119
- type: inferCheckType(task.verifyCommand),
120
- command: task.verifyCommand,
121
- evidence_type_expected: 'stdout',
122
- acceptance_ref: uncovered[0] ?? null,
123
- description: `Verify command for task ${task.id}`,
124
- });
125
- }
126
-
127
- return {
128
- checks,
129
- compiled_at: new Date().toISOString(),
130
- spec_hash: hashObject(spec),
131
- plan_hash: hashObject(plan),
132
- };
133
- }
134
-
135
- export async function runCheck(
136
- check: AcceptanceCheck,
137
- cwd: string,
138
- timeoutMs = 60_000
139
- ): Promise<CheckResult> {
140
- if (!check.command) {
141
- return {
142
- check_id: check.id,
143
- acceptance_ref: check.acceptance_ref,
144
- status: 'skip',
145
- stdout: '',
146
- stderr: '',
147
- exit_code: null,
148
- duration_ms: 0,
149
- error: null,
150
- };
151
- }
152
-
153
- const start = Date.now();
154
- try {
155
- // Split command into program + args (simple split; no shell expansion)
156
- const parts = check.command.split(/\s+/);
157
- const prog = parts[0];
158
- const args = parts.slice(1);
159
-
160
- const result = spawnSync(prog, args, {
161
- cwd,
162
- encoding: 'utf8',
163
- timeout: timeoutMs,
164
- maxBuffer: 2 * 1024 * 1024,
165
- });
166
-
167
- const duration_ms = Date.now() - start;
168
- const status: VerificationStatus = result.status === 0 ? 'pass' : 'fail';
169
-
170
- return {
171
- check_id: check.id,
172
- acceptance_ref: check.acceptance_ref,
173
- status,
174
- stdout: result.stdout ?? '',
175
- stderr: result.stderr ?? '',
176
- exit_code: result.status ?? null,
177
- duration_ms,
178
- error: result.error ? String(result.error) : null,
179
- };
180
- } catch (err) {
181
- return {
182
- check_id: check.id,
183
- acceptance_ref: check.acceptance_ref,
184
- status: 'error',
185
- stdout: '',
186
- stderr: '',
187
- exit_code: null,
188
- duration_ms: Date.now() - start,
189
- error: String(err),
190
- };
191
- }
192
- }
193
-
194
- export async function runSuite(
195
- suite: AcceptanceCheckSuite,
196
- cwd: string,
197
- timeoutMs = 60_000
198
- ): Promise<CheckResult[]> {
199
- const results: CheckResult[] = [];
200
- for (const check of suite.checks) {
201
- results.push(await runCheck(check, cwd, timeoutMs));
202
- }
203
- return results;
204
- }
205
-
206
- export function summarizeSuite(results: CheckResult[]): {
207
- total: number;
208
- pass: number;
209
- fail: number;
210
- skip: number;
211
- error: number;
212
- allPassed: boolean;
213
- } {
214
- const counts = { total: results.length, pass: 0, fail: 0, skip: 0, error: 0 };
215
- for (const r of results) counts[r.status]++;
216
- return { ...counts, allPassed: counts.fail === 0 && counts.error === 0 };
217
- }
218
-
219
- function hashObject(obj: unknown): string {
220
- return crypto
221
- .createHash('sha256')
222
- .update(JSON.stringify(obj))
223
- .digest('hex')
224
- .slice(0, 12);
225
- }
1
+ import crypto from 'crypto';
2
+ import { spawnSync } from 'child_process';
3
+ import type { EvidenceType } from '../models/evidence';
4
+ import type { VerificationStatus } from '../models/verification-result';
5
+ import type { VerificationResult } from '../models/verification-result';
6
+ import type { EvidenceStore } from '../evidence/evidence-store';
7
+ import type { PluginRegistry } from '../plugins/plugin-registry';
8
+ import {
9
+ buildManifest,
10
+ buildRiskLedger,
11
+ summarizeEvidenceCoverage,
12
+ saveManifest,
13
+ saveRiskLedger,
14
+ saveEvidenceCoverage,
15
+ type EvidenceCoverageSummary,
16
+ type ResidualRiskLedger,
17
+ type VerificationManifest,
18
+ } from './verification-manifest';
19
+
20
+ export type CheckType =
21
+ | 'unit'
22
+ | 'integration'
23
+ | 'contract'
24
+ | 'smoke'
25
+ | 'policy'
26
+ | 'security'
27
+ | 'ux_snapshot'
28
+ | 'performance_baseline'
29
+ | 'custom';
30
+
31
+ export interface AcceptanceCheck {
32
+ id: string;
33
+ type: CheckType;
34
+ command: string | null;
35
+ evidence_type_expected: EvidenceType;
36
+ acceptance_ref: string | null;
37
+ description: string;
38
+ }
39
+
40
+ export interface AcceptanceCheckSuite {
41
+ checks: AcceptanceCheck[];
42
+ compiled_at: string;
43
+ spec_hash: string;
44
+ plan_hash: string;
45
+ }
46
+
47
+ export interface CheckResult {
48
+ check_id: string;
49
+ acceptance_ref: string | null;
50
+ status: VerificationStatus;
51
+ stdout: string;
52
+ stderr: string;
53
+ exit_code: number | null;
54
+ duration_ms: number;
55
+ error: string | null;
56
+ evidence_refs?: string[];
57
+ }
58
+
59
+ export interface ExecutedVerificationSuite {
60
+ results: CheckResult[];
61
+ verification_results: VerificationResult[];
62
+ evidence_refs: Map<string, string[]>;
63
+ manifest: VerificationManifest;
64
+ risk_ledger: ResidualRiskLedger;
65
+ evidence_coverage: EvidenceCoverageSummary;
66
+ }
67
+
68
+ export interface VerifyRunResult {
69
+ status: 'passed' | 'failed' | 'partial';
70
+ suite: AcceptanceCheckSuite;
71
+ executed: ExecutedVerificationSuite | null;
72
+ gaps: string[];
73
+ verification_results: VerificationResult[];
74
+ check_results: CheckResult[];
75
+ manifest: VerificationManifest | null;
76
+ risk_ledger: ResidualRiskLedger | null;
77
+ evidence_coverage: EvidenceCoverageSummary | null;
78
+ }
79
+
80
+ // Mirror of ParsedSpec/ParsedPlan (same as in graph-compiler to avoid circular deps)
81
+ interface Criterion {
82
+ id: string;
83
+ criterion: string;
84
+ howToVerify: string;
85
+ }
86
+
87
+ interface ParsedSpecLike {
88
+ objective: string | null;
89
+ criteria: Criterion[];
90
+ }
91
+
92
+ interface ParsedTaskLike {
93
+ id: string;
94
+ verifyCommand: string | null;
95
+ aceite: string[];
96
+ }
97
+
98
+ interface ParsedPlanLike {
99
+ tasks: ParsedTaskLike[];
100
+ }
101
+
102
+ function inferCheckType(howToVerify: string): CheckType {
103
+ const v = howToVerify.toLowerCase();
104
+ if (v.includes('npm test') || v.includes('jest') || v.includes('vitest') || v.includes('node --test')) return 'unit';
105
+ if (v.includes('postman') || v.includes('newman') || v.includes('integration')) return 'integration';
106
+ if (v.includes('smoke') || v.includes('curl')) return 'smoke';
107
+ if (v.includes('eslint') || v.includes('lint') || v.includes('oxe-policy')) return 'policy';
108
+ if (v.includes('security') || v.includes('audit') || v.includes('trivy')) return 'security';
109
+ return 'custom';
110
+ }
111
+
112
+ function inferEvidenceType(checkType: CheckType): EvidenceType {
113
+ switch (checkType) {
114
+ case 'unit': return 'junit_xml';
115
+ case 'integration': return 'api_output';
116
+ case 'security': return 'security_report';
117
+ case 'policy': return 'log';
118
+ default: return 'stdout';
119
+ }
120
+ }
121
+
122
+ export function compile(
123
+ spec: ParsedSpecLike,
124
+ plan: ParsedPlanLike
125
+ ): AcceptanceCheckSuite {
126
+ const checks: AcceptanceCheck[] = [];
127
+ const seenRefs = new Set<string>();
128
+
129
+ // Generate checks from spec criteria
130
+ for (const criterion of spec.criteria) {
131
+ // Find the verify command from the task that references this criterion
132
+ const task = plan.tasks.find((t) => t.aceite.includes(criterion.id));
133
+ const command = task?.verifyCommand ?? null;
134
+ const type = inferCheckType(criterion.howToVerify);
135
+
136
+ checks.push({
137
+ id: `check-${criterion.id.toLowerCase()}`,
138
+ type,
139
+ command: command ?? (criterion.howToVerify.startsWith('#') ? null : criterion.howToVerify),
140
+ evidence_type_expected: inferEvidenceType(type),
141
+ acceptance_ref: criterion.id,
142
+ description: criterion.criterion,
143
+ });
144
+ seenRefs.add(criterion.id);
145
+ }
146
+
147
+ // Add checks for task verify commands not already covered
148
+ for (const task of plan.tasks) {
149
+ if (!task.verifyCommand) continue;
150
+ const uncovered = task.aceite.filter((ref) => !seenRefs.has(ref));
151
+ if (uncovered.length === 0 && checks.some((c) => c.command === task.verifyCommand)) continue;
152
+
153
+ checks.push({
154
+ id: `check-task-${task.id.toLowerCase()}`,
155
+ type: inferCheckType(task.verifyCommand),
156
+ command: task.verifyCommand,
157
+ evidence_type_expected: 'stdout',
158
+ acceptance_ref: uncovered[0] ?? null,
159
+ description: `Verify command for task ${task.id}`,
160
+ });
161
+ }
162
+
163
+ return {
164
+ checks,
165
+ compiled_at: new Date().toISOString(),
166
+ spec_hash: hashObject(spec),
167
+ plan_hash: hashObject(plan),
168
+ };
169
+ }
170
+
171
+ export async function runCheck(
172
+ check: AcceptanceCheck,
173
+ cwd: string,
174
+ timeoutMs = 60_000
175
+ ): Promise<CheckResult> {
176
+ if (!check.command) {
177
+ return {
178
+ check_id: check.id,
179
+ acceptance_ref: check.acceptance_ref,
180
+ status: 'skip',
181
+ stdout: '',
182
+ stderr: '',
183
+ exit_code: null,
184
+ duration_ms: 0,
185
+ error: null,
186
+ };
187
+ }
188
+
189
+ const start = Date.now();
190
+ try {
191
+ // Split command into program + args (simple split; no shell expansion)
192
+ const parts = check.command.split(/\s+/);
193
+ const prog = parts[0];
194
+ const args = parts.slice(1);
195
+
196
+ const result = spawnSync(prog, args, {
197
+ cwd,
198
+ encoding: 'utf8',
199
+ timeout: timeoutMs,
200
+ maxBuffer: 2 * 1024 * 1024,
201
+ });
202
+
203
+ const duration_ms = Date.now() - start;
204
+ const status: VerificationStatus = result.status === 0 ? 'pass' : 'fail';
205
+
206
+ return {
207
+ check_id: check.id,
208
+ acceptance_ref: check.acceptance_ref,
209
+ status,
210
+ stdout: result.stdout ?? '',
211
+ stderr: result.stderr ?? '',
212
+ exit_code: result.status ?? null,
213
+ duration_ms,
214
+ error: result.error ? String(result.error) : null,
215
+ };
216
+ } catch (err) {
217
+ return {
218
+ check_id: check.id,
219
+ acceptance_ref: check.acceptance_ref,
220
+ status: 'error',
221
+ stdout: '',
222
+ stderr: '',
223
+ exit_code: null,
224
+ duration_ms: Date.now() - start,
225
+ error: String(err),
226
+ };
227
+ }
228
+ }
229
+
230
+ export async function runSuite(
231
+ suite: AcceptanceCheckSuite,
232
+ cwd: string,
233
+ timeoutMs = 60_000
234
+ ): Promise<CheckResult[]> {
235
+ const results: CheckResult[] = [];
236
+ for (const check of suite.checks) {
237
+ results.push(await runCheck(check, cwd, timeoutMs));
238
+ }
239
+ return results;
240
+ }
241
+
242
+ export async function executeSuite(
243
+ suite: AcceptanceCheckSuite,
244
+ cwd: string,
245
+ options: {
246
+ timeoutMs?: number;
247
+ runId: string;
248
+ workItemId: string;
249
+ attemptNumber?: number;
250
+ evidenceStore?: EvidenceStore;
251
+ pluginRegistry?: PluginRegistry;
252
+ }
253
+ ): Promise<ExecutedVerificationSuite> {
254
+ const results: CheckResult[] = [];
255
+ const verificationResults: VerificationResult[] = [];
256
+ const evidenceRefs = new Map<string, string[]>();
257
+ const timeoutMs = options.timeoutMs ?? 60_000;
258
+ const attemptNumber = options.attemptNumber ?? 1;
259
+
260
+ for (const check of suite.checks) {
261
+ const provider = options.pluginRegistry?.verifierProviderFor(check.type);
262
+ let result: CheckResult;
263
+ let verificationResult: VerificationResult;
264
+
265
+ if (provider) {
266
+ const providerResult = await provider.execute({
267
+ check_id: check.id,
268
+ check_type: check.type,
269
+ command: check.command,
270
+ work_item_id: options.workItemId,
271
+ workspace_root: cwd,
272
+ evidence_dir: '',
273
+ });
274
+ result = {
275
+ check_id: check.id,
276
+ acceptance_ref: check.acceptance_ref,
277
+ status: providerResult.status,
278
+ stdout: providerResult.summary ?? '',
279
+ stderr: '',
280
+ exit_code: providerResult.status === 'pass' ? 0 : 1,
281
+ duration_ms: 0,
282
+ error: providerResult.status === 'error' ? providerResult.summary ?? 'provider error' : null,
283
+ evidence_refs: providerResult.evidence_refs,
284
+ };
285
+ verificationResult = providerResult;
286
+ } else {
287
+ result = await runCheck(check, cwd, timeoutMs);
288
+ const collectedEvidence = options.evidenceStore
289
+ ? await collectCheckEvidence(options.evidenceStore, check, result, {
290
+ run_id: options.runId,
291
+ work_item_id: options.workItemId,
292
+ attempt_number: attemptNumber,
293
+ })
294
+ : [];
295
+ result.evidence_refs = collectedEvidence;
296
+ verificationResult = {
297
+ verification_id: `vr-${crypto.randomBytes(4).toString('hex')}`,
298
+ work_item_id: options.workItemId,
299
+ check_id: check.id,
300
+ status: result.status,
301
+ evidence_refs: collectedEvidence,
302
+ summary: result.error || result.stderr || result.stdout || null,
303
+ };
304
+ }
305
+
306
+ if (result.evidence_refs && result.evidence_refs.length > 0) {
307
+ evidenceRefs.set(check.id, result.evidence_refs);
308
+ }
309
+ results.push(result);
310
+ verificationResults.push(verificationResult);
311
+ }
312
+
313
+ const manifest = buildManifest(options.runId, results, {
314
+ workItemId: options.workItemId,
315
+ granularity: 'work_item',
316
+ evidenceRefs,
317
+ });
318
+ const riskLedger = buildRiskLedger(options.runId, manifest);
319
+ const evidenceCoverage = summarizeEvidenceCoverage(manifest);
320
+ return {
321
+ results,
322
+ verification_results: verificationResults,
323
+ evidence_refs: evidenceRefs,
324
+ manifest,
325
+ risk_ledger: riskLedger,
326
+ evidence_coverage: evidenceCoverage,
327
+ };
328
+ }
329
+
330
+ export function summarizeSuite(results: CheckResult[]): {
331
+ total: number;
332
+ pass: number;
333
+ fail: number;
334
+ skip: number;
335
+ error: number;
336
+ allPassed: boolean;
337
+ } {
338
+ const counts = { total: results.length, pass: 0, fail: 0, skip: 0, error: 0 };
339
+ for (const r of results) counts[r.status]++;
340
+ return { ...counts, allPassed: counts.fail === 0 && counts.error === 0 };
341
+ }
342
+
343
+ export async function verifyRun(input: {
344
+ projectRoot: string;
345
+ runId: string;
346
+ workItemId: string;
347
+ cwd: string;
348
+ suite: AcceptanceCheckSuite;
349
+ pluginRegistry?: PluginRegistry;
350
+ evidenceStore?: EvidenceStore;
351
+ attemptNumber?: number;
352
+ timeoutMs?: number;
353
+ }): Promise<VerifyRunResult> {
354
+ const gaps: string[] = [];
355
+ if (!input.suite || !Array.isArray(input.suite.checks) || input.suite.checks.length === 0) {
356
+ gaps.push('Nenhum check executável foi compilado a partir de SPEC/PLAN.');
357
+ return {
358
+ status: 'partial',
359
+ suite: input.suite,
360
+ executed: null,
361
+ gaps,
362
+ verification_results: [],
363
+ check_results: [],
364
+ manifest: null,
365
+ risk_ledger: null,
366
+ evidence_coverage: null,
367
+ };
368
+ }
369
+
370
+ const executed = await executeSuite(input.suite, input.cwd, {
371
+ timeoutMs: input.timeoutMs,
372
+ runId: input.runId,
373
+ workItemId: input.workItemId,
374
+ attemptNumber: input.attemptNumber,
375
+ evidenceStore: input.evidenceStore,
376
+ pluginRegistry: input.pluginRegistry,
377
+ });
378
+ saveManifest(input.projectRoot, input.runId, executed.manifest);
379
+ saveRiskLedger(input.projectRoot, input.runId, executed.risk_ledger);
380
+ saveEvidenceCoverage(input.projectRoot, input.runId, executed.evidence_coverage);
381
+ const summary = summarizeSuite(executed.results);
382
+ return {
383
+ status: summary.total === 0 ? 'partial' : summary.allPassed ? 'passed' : 'failed',
384
+ suite: input.suite,
385
+ executed,
386
+ gaps,
387
+ verification_results: executed.verification_results,
388
+ check_results: executed.results,
389
+ manifest: executed.manifest,
390
+ risk_ledger: executed.risk_ledger,
391
+ evidence_coverage: executed.evidence_coverage,
392
+ };
393
+ }
394
+
395
+ function hashObject(obj: unknown): string {
396
+ return crypto
397
+ .createHash('sha256')
398
+ .update(JSON.stringify(obj))
399
+ .digest('hex')
400
+ .slice(0, 12);
401
+ }
402
+
403
+ async function collectCheckEvidence(
404
+ store: EvidenceStore,
405
+ check: AcceptanceCheck,
406
+ result: CheckResult,
407
+ options: { run_id: string; work_item_id: string; attempt_number: number }
408
+ ): Promise<string[]> {
409
+ const refs: string[] = [];
410
+ if (result.stdout) {
411
+ const evidence = await store.collect('stdout', result.stdout, options);
412
+ refs.push(evidence.evidence_id);
413
+ }
414
+ if (result.stderr) {
415
+ const evidence = await store.collect('stderr', result.stderr, options);
416
+ refs.push(evidence.evidence_id);
417
+ }
418
+ const summaryEvidence = await store.collect(
419
+ check.evidence_type_expected,
420
+ JSON.stringify(
421
+ {
422
+ check_id: check.id,
423
+ type: check.type,
424
+ command: check.command,
425
+ status: result.status,
426
+ exit_code: result.exit_code,
427
+ duration_ms: result.duration_ms,
428
+ },
429
+ null,
430
+ 2
431
+ ),
432
+ options
433
+ );
434
+ refs.push(summaryEvidence.evidence_id);
435
+ return refs;
436
+ }