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
@@ -1,193 +1,259 @@
1
- import type { WorkItem } from '../models/work-item';
2
- import type { Evidence } from '../models/evidence';
3
- import type { RunState } from '../reducers/run-state-reducer';
4
-
5
- export interface ContextArtifact {
6
- id: string;
7
- kind: 'evidence' | 'lesson' | 'file' | 'summary';
8
- content: string;
9
- relevanceScore: number;
10
- tags: string[];
11
- }
12
-
13
- export interface LessonMetric {
14
- lesson_id: string;
15
- title: string;
16
- tags: string[];
17
- embedding?: number[];
18
- content: string;
19
- }
20
-
21
- export interface ContextPackOptions {
22
- maxArtifacts?: number;
23
- maxTokensEstimate?: number;
24
- deduplicateThreshold?: number;
25
- }
26
-
27
- export interface ContextPack {
28
- work_item_id: string;
29
- artifacts: ContextArtifact[];
30
- total_artifacts_considered: number;
31
- redundancy_removed: number;
32
- built_at: string;
33
- }
34
-
35
- // ─── Relevance scoring ────────────────────────────────────────────────────────
36
-
37
- function scoreEvidenceRelevance(evidence: Evidence, workItem: WorkItem): number {
38
- let score = 0.5;
39
- const eid = evidence.evidence_id.toLowerCase();
40
- const title = workItem.title.toLowerCase();
41
- const scope = workItem.mutation_scope ?? [];
42
-
43
- if (scope.some((s) => eid.includes(s.toLowerCase()))) score += 0.3;
44
- if (title.split(/\s+/).some((w) => w.length > 3 && eid.includes(w))) score += 0.1;
45
- if (evidence.type === 'junit_xml') score += 0.05;
46
- if (evidence.type === 'diff') score += 0.05;
47
-
48
- return Math.min(score, 1.0);
49
- }
50
-
51
- function scoreLessonRelevance(lesson: LessonMetric, workItem: WorkItem): number {
52
- const itemTags = new Set([
53
- ...workItem.mutation_scope.map((s) => s.toLowerCase()),
54
- ...workItem.title.toLowerCase().split(/\s+/).filter((w) => w.length > 3),
55
- ]);
56
-
57
- const lessonTags = lesson.tags.map((t) => t.toLowerCase());
58
- const overlap = lessonTags.filter((t) => itemTags.has(t)).length;
59
- const jaccard = overlap / (itemTags.size + lessonTags.length - overlap || 1);
60
-
61
- return Math.min(0.3 + jaccard * 0.7, 1.0);
62
- }
63
-
64
- // ─── Redundancy elimination ───────────────────────────────────────────────────
65
-
66
- function cosineSimilarity(a: ContextArtifact, b: ContextArtifact): number {
67
- const wordsA = new Set(a.content.toLowerCase().split(/\W+/).filter((w) => w.length > 3));
68
- const wordsB = new Set(b.content.toLowerCase().split(/\W+/).filter((w) => w.length > 3));
69
- if (wordsA.size === 0 || wordsB.size === 0) return 0;
70
-
71
- let intersection = 0;
72
- for (const w of wordsA) if (wordsB.has(w)) intersection++;
73
- return intersection / Math.sqrt(wordsA.size * wordsB.size);
74
- }
75
-
76
- function deduplicateArtifacts(artifacts: ContextArtifact[], threshold: number): { kept: ContextArtifact[]; removed: number } {
77
- const kept: ContextArtifact[] = [];
78
- let removed = 0;
79
-
80
- for (const candidate of artifacts) {
81
- const isDuplicate = kept.some((existing) => cosineSimilarity(candidate, existing) >= threshold);
82
- if (isDuplicate) {
83
- removed++;
84
- } else {
85
- kept.push(candidate);
86
- }
87
- }
88
-
89
- return { kept, removed };
90
- }
91
-
92
- // ─── Token budget estimation ──────────────────────────────────────────────────
93
-
94
- function estimateTokens(text: string): number {
95
- return Math.ceil(text.length / 4);
96
- }
97
-
98
- function applyTokenBudget(artifacts: ContextArtifact[], maxTokens: number): ContextArtifact[] {
99
- let used = 0;
100
- const result: ContextArtifact[] = [];
101
- for (const a of artifacts) {
102
- const t = estimateTokens(a.content);
103
- if (used + t > maxTokens) break;
104
- result.push(a);
105
- used += t;
106
- }
107
- return result;
108
- }
109
-
110
- // ─── Context Pack Builder ─────────────────────────────────────────────────────
111
-
112
- export class ContextPackBuilder {
113
- constructor(private readonly opts: ContextPackOptions = {}) {}
114
-
115
- build(
116
- workItem: WorkItem,
117
- state: RunState,
118
- evidenceItems: Evidence[],
119
- evidenceContents: Map<string, string>,
120
- lessons: LessonMetric[],
121
- ): ContextPack {
122
- const {
123
- maxArtifacts = 20,
124
- maxTokensEstimate = 8000,
125
- deduplicateThreshold = 0.85,
126
- } = this.opts;
127
-
128
- const raw: ContextArtifact[] = [];
129
-
130
- // Score and collect evidence
131
- for (const ev of evidenceItems) {
132
- const content = evidenceContents.get(ev.evidence_id) ?? '';
133
- if (!content) continue;
134
- raw.push({
135
- id: ev.evidence_id,
136
- kind: 'evidence',
137
- content,
138
- relevanceScore: scoreEvidenceRelevance(ev, workItem),
139
- tags: [ev.type, workItem.work_item_id],
140
- });
141
- }
142
-
143
- // Score and collect lessons
144
- for (const lesson of lessons) {
145
- raw.push({
146
- id: lesson.lesson_id,
147
- kind: 'lesson',
148
- content: lesson.content,
149
- relevanceScore: scoreLessonRelevance(lesson, workItem),
150
- tags: lesson.tags,
151
- });
152
- }
153
-
154
- // Add run-level summary if available
155
- const completedCount = state.completedWorkItems.size;
156
- if (completedCount > 0) {
157
- raw.push({
158
- id: `run-summary-${workItem.run_id}`,
159
- kind: 'summary',
160
- content: `Run progress: ${completedCount} completed, ${state.failedWorkItems.size} failed, ${state.blockedWorkItems.size} blocked.`,
161
- relevanceScore: 0.4,
162
- tags: ['run-context'],
163
- });
164
- }
165
-
166
- const totalConsidered = raw.length;
167
-
168
- // Sort by relevance descending
169
- raw.sort((a, b) => b.relevanceScore - a.relevanceScore);
170
-
171
- // Deduplicate
172
- const { kept, removed } = deduplicateArtifacts(raw, deduplicateThreshold);
173
-
174
- // Apply max artifacts cap
175
- const capped = kept.slice(0, maxArtifacts);
176
-
177
- // Apply token budget
178
- const final = applyTokenBudget(capped, maxTokensEstimate);
179
-
180
- return {
181
- work_item_id: workItem.work_item_id,
182
- artifacts: final,
183
- total_artifacts_considered: totalConsidered,
184
- redundancy_removed: removed,
185
- built_at: new Date().toISOString(),
186
- };
187
- }
188
-
189
- /** Convenience: build with no evidence, just lessons and state summary */
190
- buildLightweight(workItem: WorkItem, state: RunState, lessons: LessonMetric[]): ContextPack {
191
- return this.build(workItem, state, [], new Map(), lessons);
192
- }
193
- }
1
+ import type { WorkItem } from '../models/work-item';
2
+ import type { Evidence } from '../models/evidence';
3
+ import type { RunState } from '../reducers/run-state-reducer';
4
+ import type { ContextProfile } from './context-profiles';
5
+ import type { AutonomyTier } from '../policy/policy-engine';
6
+
7
+ export interface ContextArtifact {
8
+ id: string;
9
+ kind: 'evidence' | 'lesson' | 'file' | 'summary';
10
+ content: string;
11
+ relevanceScore: number;
12
+ tags: string[];
13
+ }
14
+
15
+ export interface LessonMetric {
16
+ lesson_id: string;
17
+ title: string;
18
+ tags: string[];
19
+ embedding?: number[];
20
+ content: string;
21
+ }
22
+
23
+ export interface ContextPackOptions {
24
+ maxArtifacts?: number;
25
+ maxTokensEstimate?: number;
26
+ deduplicateThreshold?: number;
27
+ }
28
+
29
+ export interface ContextPack {
30
+ work_item_id: string;
31
+ artifacts: ContextArtifact[];
32
+ total_artifacts_considered: number;
33
+ redundancy_removed: number;
34
+ built_at: string;
35
+ }
36
+
37
+ // ─── Quality scoring ─────────────────────────────────────────────────────────
38
+
39
+ export interface ContextQualityScore {
40
+ completeness: number;
41
+ relevance_mean: number;
42
+ redundancy: number;
43
+ recency_score: number;
44
+ overall: number;
45
+ }
46
+
47
+ export function scorePackQuality(pack: ContextPack, profile: ContextProfile): ContextQualityScore {
48
+ const expectedKinds = Object.keys(profile.artifact_kind_weights) as ContextArtifact['kind'][];
49
+ const presentKinds = new Set(pack.artifacts.map((a) => a.kind));
50
+ const completeness = expectedKinds.length > 0
51
+ ? expectedKinds.filter((k) => presentKinds.has(k)).length / expectedKinds.length
52
+ : 0;
53
+
54
+ const relevance_mean = pack.artifacts.length > 0
55
+ ? pack.artifacts.reduce((sum, a) => sum + a.relevanceScore, 0) / pack.artifacts.length
56
+ : 0;
57
+
58
+ const total = pack.total_artifacts_considered;
59
+ const redundancy = total > 0 ? 1 - (pack.artifacts.length / total) : 0;
60
+
61
+ const ageMs = Date.now() - new Date(pack.built_at).getTime();
62
+ const maxAgeMs = 24 * 60 * 60 * 1000;
63
+ const recency_score = Math.max(0, 1 - ageMs / maxAgeMs);
64
+
65
+ const overall = Math.min(1,
66
+ 0.3 * completeness +
67
+ 0.35 * relevance_mean +
68
+ 0.1 * (1 - redundancy) +
69
+ 0.25 * recency_score
70
+ );
71
+
72
+ return {
73
+ completeness: Math.round(completeness * 100) / 100,
74
+ relevance_mean: Math.round(relevance_mean * 100) / 100,
75
+ redundancy: Math.round(redundancy * 100) / 100,
76
+ recency_score: Math.round(recency_score * 100) / 100,
77
+ overall: Math.round(overall * 100) / 100,
78
+ };
79
+ }
80
+
81
+ // ─── Relevance scoring ────────────────────────────────────────────────────────
82
+
83
+ function scoreEvidenceRelevance(evidence: Evidence, workItem: WorkItem): number {
84
+ let score = 0.5;
85
+ const eid = evidence.evidence_id.toLowerCase();
86
+ const title = workItem.title.toLowerCase();
87
+ const scope = workItem.mutation_scope ?? [];
88
+
89
+ if (scope.some((s) => eid.includes(s.toLowerCase()))) score += 0.3;
90
+ if (title.split(/\s+/).some((w) => w.length > 3 && eid.includes(w))) score += 0.1;
91
+ if (evidence.type === 'junit_xml') score += 0.05;
92
+ if (evidence.type === 'diff') score += 0.05;
93
+
94
+ return Math.min(score, 1.0);
95
+ }
96
+
97
+ function scoreLessonRelevance(lesson: LessonMetric, workItem: WorkItem): number {
98
+ const itemTags = new Set([
99
+ ...workItem.mutation_scope.map((s) => s.toLowerCase()),
100
+ ...workItem.title.toLowerCase().split(/\s+/).filter((w) => w.length > 3),
101
+ ]);
102
+
103
+ const lessonTags = lesson.tags.map((t) => t.toLowerCase());
104
+ const overlap = lessonTags.filter((t) => itemTags.has(t)).length;
105
+ const jaccard = overlap / (itemTags.size + lessonTags.length - overlap || 1);
106
+
107
+ return Math.min(0.3 + jaccard * 0.7, 1.0);
108
+ }
109
+
110
+ // ─── Redundancy elimination ───────────────────────────────────────────────────
111
+
112
+ function cosineSimilarity(a: ContextArtifact, b: ContextArtifact): number {
113
+ const wordsA = new Set(a.content.toLowerCase().split(/\W+/).filter((w) => w.length > 3));
114
+ const wordsB = new Set(b.content.toLowerCase().split(/\W+/).filter((w) => w.length > 3));
115
+ if (wordsA.size === 0 || wordsB.size === 0) return 0;
116
+
117
+ let intersection = 0;
118
+ for (const w of wordsA) if (wordsB.has(w)) intersection++;
119
+ return intersection / Math.sqrt(wordsA.size * wordsB.size);
120
+ }
121
+
122
+ function deduplicateArtifacts(artifacts: ContextArtifact[], threshold: number): { kept: ContextArtifact[]; removed: number } {
123
+ const kept: ContextArtifact[] = [];
124
+ let removed = 0;
125
+
126
+ for (const candidate of artifacts) {
127
+ const isDuplicate = kept.some((existing) => cosineSimilarity(candidate, existing) >= threshold);
128
+ if (isDuplicate) {
129
+ removed++;
130
+ } else {
131
+ kept.push(candidate);
132
+ }
133
+ }
134
+
135
+ return { kept, removed };
136
+ }
137
+
138
+ // ─── Token budget estimation ──────────────────────────────────────────────────
139
+
140
+ function estimateTokens(text: string): number {
141
+ return Math.ceil(text.length / 4);
142
+ }
143
+
144
+ function applyTokenBudget(artifacts: ContextArtifact[], maxTokens: number): ContextArtifact[] {
145
+ let used = 0;
146
+ const result: ContextArtifact[] = [];
147
+ for (const a of artifacts) {
148
+ const t = estimateTokens(a.content);
149
+ if (used + t > maxTokens) break;
150
+ result.push(a);
151
+ used += t;
152
+ }
153
+ return result;
154
+ }
155
+
156
+ // ─── Context Pack Builder ─────────────────────────────────────────────────────
157
+
158
+ export class ContextPackBuilder {
159
+ constructor(private readonly opts: ContextPackOptions = {}) {}
160
+
161
+ build(
162
+ workItem: WorkItem,
163
+ state: RunState,
164
+ evidenceItems: Evidence[],
165
+ evidenceContents: Map<string, string>,
166
+ lessons: LessonMetric[],
167
+ ): ContextPack {
168
+ const {
169
+ maxArtifacts = 20,
170
+ maxTokensEstimate = 8000,
171
+ deduplicateThreshold = 0.85,
172
+ } = this.opts;
173
+
174
+ const raw: ContextArtifact[] = [];
175
+
176
+ // Score and collect evidence
177
+ for (const ev of evidenceItems) {
178
+ const content = evidenceContents.get(ev.evidence_id) ?? '';
179
+ if (!content) continue;
180
+ raw.push({
181
+ id: ev.evidence_id,
182
+ kind: 'evidence',
183
+ content,
184
+ relevanceScore: scoreEvidenceRelevance(ev, workItem),
185
+ tags: [ev.type, workItem.work_item_id],
186
+ });
187
+ }
188
+
189
+ // Score and collect lessons
190
+ for (const lesson of lessons) {
191
+ raw.push({
192
+ id: lesson.lesson_id,
193
+ kind: 'lesson',
194
+ content: lesson.content,
195
+ relevanceScore: scoreLessonRelevance(lesson, workItem),
196
+ tags: lesson.tags,
197
+ });
198
+ }
199
+
200
+ // Add run-level summary if available
201
+ const completedCount = state.completedWorkItems.size;
202
+ if (completedCount > 0) {
203
+ raw.push({
204
+ id: `run-summary-${workItem.run_id}`,
205
+ kind: 'summary',
206
+ content: `Run progress: ${completedCount} completed, ${state.failedWorkItems.size} failed, ${state.blockedWorkItems.size} blocked.`,
207
+ relevanceScore: 0.4,
208
+ tags: ['run-context'],
209
+ });
210
+ }
211
+
212
+ const totalConsidered = raw.length;
213
+
214
+ // Sort by relevance descending
215
+ raw.sort((a, b) => b.relevanceScore - a.relevanceScore);
216
+
217
+ // Deduplicate
218
+ const { kept, removed } = deduplicateArtifacts(raw, deduplicateThreshold);
219
+
220
+ // Apply max artifacts cap
221
+ const capped = kept.slice(0, maxArtifacts);
222
+
223
+ // Apply token budget
224
+ const final = applyTokenBudget(capped, maxTokensEstimate);
225
+
226
+ return {
227
+ work_item_id: workItem.work_item_id,
228
+ artifacts: final,
229
+ total_artifacts_considered: totalConsidered,
230
+ redundancy_removed: removed,
231
+ built_at: new Date().toISOString(),
232
+ };
233
+ }
234
+
235
+ /** Convenience: build with no evidence, just lessons and state summary */
236
+ buildLightweight(workItem: WorkItem, state: RunState, lessons: LessonMetric[]): ContextPack {
237
+ return this.build(workItem, state, [], new Map(), lessons);
238
+ }
239
+
240
+ /**
241
+ * Filter artifacts to those whose path-like tags are within mutation_scope.
242
+ * L0/L1 tiers apply the filter; L2/L3 skip it (full access).
243
+ */
244
+ filterByMutationScope(
245
+ artifacts: ContextArtifact[],
246
+ mutationScope: string[],
247
+ autonomyTier: AutonomyTier
248
+ ): ContextArtifact[] {
249
+ if (autonomyTier === 'L2' || autonomyTier === 'L3') return artifacts;
250
+ const scope = mutationScope.map((s) => s.toLowerCase());
251
+ return artifacts.filter((a) => {
252
+ const pathTags = a.tags.filter((t) => t.includes('/') || t.includes('\\'));
253
+ if (pathTags.length === 0) return true;
254
+ return pathTags.some((tag) =>
255
+ scope.some((s) => tag.toLowerCase().includes(s) || s.includes(tag.toLowerCase()))
256
+ );
257
+ });
258
+ }
259
+ }
@@ -0,0 +1,197 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import type { ContextPack, ContextArtifact, ContextQualityScore } from './context-pack-builder';
4
+
5
+ export interface ContextPackMeta {
6
+ pack_id: string;
7
+ work_item_id: string;
8
+ run_id: string;
9
+ built_at: string;
10
+ artifact_count: number;
11
+ estimated_tokens: number;
12
+ stale: boolean;
13
+ stale_reason: string | null;
14
+ }
15
+
16
+ export interface ContextPackDiff {
17
+ added: string[];
18
+ removed: string[];
19
+ score_changed: Array<{ id: string; before: number; after: number }>;
20
+ }
21
+
22
+ function packPath(projectRoot: string, runId: string, workItemId: string): string {
23
+ return path.join(projectRoot, '.oxe', 'runs', runId, `context-pack-${workItemId}.json`);
24
+ }
25
+
26
+ function metaIndexPath(projectRoot: string, runId: string): string {
27
+ return path.join(projectRoot, '.oxe', 'runs', runId, 'context-packs.index.json');
28
+ }
29
+
30
+ function estimateTokens(pack: ContextPack): number {
31
+ return Math.ceil(pack.artifacts.reduce((sum, a) => sum + a.content.length, 0) / 4);
32
+ }
33
+
34
+ export function savePack(
35
+ projectRoot: string,
36
+ runId: string,
37
+ pack: ContextPack
38
+ ): ContextPackMeta {
39
+ const p = packPath(projectRoot, runId, pack.work_item_id);
40
+ fs.mkdirSync(path.dirname(p), { recursive: true });
41
+ fs.writeFileSync(p, JSON.stringify(pack, null, 2), 'utf8');
42
+
43
+ const meta: ContextPackMeta = {
44
+ pack_id: `cp-${runId}-${pack.work_item_id}`,
45
+ work_item_id: pack.work_item_id,
46
+ run_id: runId,
47
+ built_at: pack.built_at,
48
+ artifact_count: pack.artifacts.length,
49
+ estimated_tokens: estimateTokens(pack),
50
+ stale: false,
51
+ stale_reason: null,
52
+ };
53
+
54
+ updateMetaIndex(projectRoot, runId, meta);
55
+ return meta;
56
+ }
57
+
58
+ export function loadPack(
59
+ projectRoot: string,
60
+ runId: string,
61
+ workItemId: string
62
+ ): ContextPack | null {
63
+ const p = packPath(projectRoot, runId, workItemId);
64
+ if (!fs.existsSync(p)) return null;
65
+ try {
66
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as ContextPack;
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ export function markStale(
73
+ projectRoot: string,
74
+ runId: string,
75
+ workItemId: string,
76
+ reason: string
77
+ ): void {
78
+ const index = loadMetaIndex(projectRoot, runId);
79
+ const meta = index.find((m) => m.work_item_id === workItemId);
80
+ if (!meta) return;
81
+ meta.stale = true;
82
+ meta.stale_reason = reason;
83
+ saveMetaIndex(projectRoot, runId, index);
84
+ }
85
+
86
+ export function isStale(
87
+ projectRoot: string,
88
+ runId: string,
89
+ workItemId: string
90
+ ): boolean {
91
+ const index = loadMetaIndex(projectRoot, runId);
92
+ return index.find((m) => m.work_item_id === workItemId)?.stale ?? false;
93
+ }
94
+
95
+ export function diffPacks(before: ContextPack, after: ContextPack): ContextPackDiff {
96
+ const beforeIds = new Set(before.artifacts.map((a) => a.id));
97
+ const afterIds = new Set(after.artifacts.map((a) => a.id));
98
+ const beforeMap = new Map(before.artifacts.map((a) => [a.id, a]));
99
+ const afterMap = new Map(after.artifacts.map((a) => [a.id, a]));
100
+
101
+ const added = [...afterIds].filter((id) => !beforeIds.has(id));
102
+ const removed = [...beforeIds].filter((id) => !afterIds.has(id));
103
+
104
+ const score_changed: ContextPackDiff['score_changed'] = [];
105
+ for (const id of afterIds) {
106
+ if (!beforeIds.has(id)) continue;
107
+ const bScore = beforeMap.get(id)!.relevanceScore;
108
+ const aScore = afterMap.get(id)!.relevanceScore;
109
+ if (Math.abs(bScore - aScore) > 0.05) {
110
+ score_changed.push({ id, before: bScore, after: aScore });
111
+ }
112
+ }
113
+
114
+ return { added, removed, score_changed };
115
+ }
116
+
117
+ export function listPackMeta(projectRoot: string, runId: string): ContextPackMeta[] {
118
+ return loadMetaIndex(projectRoot, runId);
119
+ }
120
+
121
+ // ─── ContextPackRef — link pack to a specific execution attempt ───────────────
122
+
123
+ export interface ContextPackRef {
124
+ ref_id: string;
125
+ pack_id: string;
126
+ attempt_id: string;
127
+ work_item_id: string;
128
+ run_id: string;
129
+ artifacts_used: string[];
130
+ quality: ContextQualityScore;
131
+ linked_at: string;
132
+ }
133
+
134
+ function packRefPath(projectRoot: string, runId: string, attemptId: string): string {
135
+ return path.join(projectRoot, '.oxe', 'runs', runId, `context-ref-${attemptId}.json`);
136
+ }
137
+
138
+ export function linkPackToAttempt(
139
+ projectRoot: string,
140
+ runId: string,
141
+ attemptId: string,
142
+ pack: ContextPack,
143
+ quality: ContextQualityScore
144
+ ): ContextPackRef {
145
+ const ref: ContextPackRef = {
146
+ ref_id: `ref-${runId}-${attemptId}`,
147
+ pack_id: `cp-${runId}-${pack.work_item_id}`,
148
+ attempt_id: attemptId,
149
+ work_item_id: pack.work_item_id,
150
+ run_id: runId,
151
+ artifacts_used: pack.artifacts.map((a) => a.id),
152
+ quality,
153
+ linked_at: new Date().toISOString(),
154
+ };
155
+ const p = packRefPath(projectRoot, runId, attemptId);
156
+ fs.mkdirSync(path.dirname(p), { recursive: true });
157
+ fs.writeFileSync(p, JSON.stringify(ref, null, 2), 'utf8');
158
+ return ref;
159
+ }
160
+
161
+ export function getPackRefForAttempt(
162
+ projectRoot: string,
163
+ runId: string,
164
+ attemptId: string
165
+ ): ContextPackRef | null {
166
+ const p = packRefPath(projectRoot, runId, attemptId);
167
+ if (!fs.existsSync(p)) return null;
168
+ try {
169
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as ContextPackRef;
170
+ } catch {
171
+ return null;
172
+ }
173
+ }
174
+
175
+ function loadMetaIndex(projectRoot: string, runId: string): ContextPackMeta[] {
176
+ const p = metaIndexPath(projectRoot, runId);
177
+ if (!fs.existsSync(p)) return [];
178
+ try {
179
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as ContextPackMeta[];
180
+ } catch {
181
+ return [];
182
+ }
183
+ }
184
+
185
+ function saveMetaIndex(projectRoot: string, runId: string, index: ContextPackMeta[]): void {
186
+ const p = metaIndexPath(projectRoot, runId);
187
+ fs.mkdirSync(path.dirname(p), { recursive: true });
188
+ fs.writeFileSync(p, JSON.stringify(index, null, 2), 'utf8');
189
+ }
190
+
191
+ function updateMetaIndex(projectRoot: string, runId: string, meta: ContextPackMeta): void {
192
+ const index = loadMetaIndex(projectRoot, runId);
193
+ const idx = index.findIndex((m) => m.work_item_id === meta.work_item_id);
194
+ if (idx >= 0) index[idx] = meta;
195
+ else index.push(meta);
196
+ saveMetaIndex(projectRoot, runId, index);
197
+ }