@khoavu882/doflow 2.0.0-beta.3 → 2.0.0-beta.5

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 (236) hide show
  1. package/bin/doflow.js +2 -2
  2. package/core/.antigravity-plugin/plugin.json +0 -1
  3. package/core/.claude-plugin/plugin.json +1 -1
  4. package/core/.codex-plugin/plugin.json +1 -1
  5. package/core/.plugin/plugin.json +1 -1
  6. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  7. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  8. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  9. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  10. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  11. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  12. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  13. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  14. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  15. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  16. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  17. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  18. package/core/harnesses/codex/hooks/subagent-audit.sh +17 -6
  19. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  20. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +7 -18
  21. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +7 -18
  22. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +7 -19
  23. package/core/harnesses/gemini/hooks/session-start.sh +5 -3
  24. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +20 -5
  25. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +20 -5
  26. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +20 -5
  27. package/core/harnesses/kiro/hooks/session-start.sh +11 -5
  28. package/core/harnesses/kiro/hooks/stop-check.sh +21 -30
  29. package/core/harnesses/pi/extensions/doflow-guard.js +159 -0
  30. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -11
  31. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  32. package/core/harnesses/shared/hooks/bridge/bridge.sh +184 -0
  33. package/core/harnesses/shared/hooks/bridge/envelope.jq +60 -0
  34. package/core/harnesses/shared/hooks/bridge/respond.sh +62 -0
  35. package/core/harnesses/shared/hooks/policies/capture-failure.sh +4 -2
  36. package/core/harnesses/shared/hooks/policies/contract.sh +75 -0
  37. package/core/harnesses/shared/hooks/policies/deny-json.sh +39 -4
  38. package/core/harnesses/shared/hooks/policies/lib.sh +4 -2
  39. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +46 -34
  40. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +75 -25
  41. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +67 -73
  42. package/core/harnesses/shared/hooks/policies/session-context.sh +37 -7
  43. package/core/harnesses/shared/hooks/policies/stop-check.sh +42 -15
  44. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +35 -5
  45. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +40 -7
  46. package/core/harnesses/shared/hooks/stream-hook-runner.js +69 -181
  47. package/core/registry/assets.json +19 -0
  48. package/core/registry/contracts.json +2 -2
  49. package/core/registry/harnesses.json +196 -10
  50. package/core/registry/lifecycle.json +2626 -7
  51. package/core/registry/storage.json +110 -83
  52. package/core/registry/verification.json +1 -1
  53. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
  54. package/core/shared/scripts/doflow/bin/doflow-run +10 -6
  55. package/core/shared/skills/do-design/SKILL.md +6 -6
  56. package/core/shared/skills/do-execute-plan/SKILL.md +11 -10
  57. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +2 -0
  58. package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
  59. package/core/shared/skills/do-implement/SKILL.md +3 -2
  60. package/core/shared/skills/do-plan/SKILL.md +7 -8
  61. package/package.json +4 -2
  62. package/src/adapters/antigravity/{index.ts → index.js} +141 -105
  63. package/src/adapters/claude/{index.ts → index.js} +63 -49
  64. package/src/adapters/claude/{mcp.ts → mcp.js} +16 -16
  65. package/src/adapters/codex/{agents.ts → agents.js} +24 -24
  66. package/src/adapters/codex/{config.ts → config.js} +49 -49
  67. package/src/adapters/codex/{hooks.ts → hooks.js} +62 -27
  68. package/src/adapters/codex/{index.ts → index.js} +148 -105
  69. package/src/adapters/codex/{mcp.ts → mcp.js} +38 -38
  70. package/src/adapters/codex/{native-projection.ts → native-projection.js} +5 -5
  71. package/src/adapters/copilot/{index.ts → index.js} +42 -42
  72. package/src/adapters/{copy-tree.ts → copy-tree.js} +74 -74
  73. package/src/adapters/gemini/{hooks.ts → hooks.js} +78 -37
  74. package/src/adapters/gemini/{index.ts → index.js} +96 -57
  75. package/src/adapters/{hook-commands.ts → hook-commands.js} +8 -8
  76. package/src/adapters/{index.ts → index.js} +13 -13
  77. package/src/adapters/kiro/{index.ts → index.js} +49 -35
  78. package/src/adapters/{mcp-entries.ts → mcp-entries.js} +55 -55
  79. package/src/adapters/opencode/{index.ts → index.js} +52 -52
  80. package/src/adapters/pi/hooks.js +119 -0
  81. package/src/adapters/pi/{index.ts → index.js} +64 -39
  82. package/src/adapters/pi/{json-members.ts → json-members.js} +23 -23
  83. package/src/adapters/pi/{mcp.ts → mcp.js} +70 -70
  84. package/src/adapters/{resolve-source.ts → resolve-source.js} +1 -1
  85. package/src/cli/commands/{install.ts → install.js} +25 -25
  86. package/src/cli/commands/{list-backups.ts → list-backups.js} +4 -4
  87. package/src/cli/commands/{reconcile.ts → reconcile.js} +19 -19
  88. package/src/cli/commands/{remove.ts → remove.js} +10 -10
  89. package/src/cli/commands/{rollback.ts → rollback.js} +17 -17
  90. package/src/cli/commands/{self-update.ts → self-update.js} +3 -3
  91. package/src/cli/commands/{status.ts → status.js} +24 -24
  92. package/src/cli/commands/{tools.ts → tools.js} +16 -16
  93. package/src/cli/commands/{update.ts → update.js} +20 -20
  94. package/src/cli/{index.ts → index.js} +43 -31
  95. package/src/cli/{runtime-commands.ts → runtime-commands.js} +97 -58
  96. package/src/cli/{shared.ts → shared.js} +40 -40
  97. package/src/helper/{bash-helper.ts → bash-helper.js} +7 -7
  98. package/src/helper/{git.ts → git.js} +2 -2
  99. package/src/helper/{guardrails.ts → guardrails.js} +10 -10
  100. package/src/helper/{harness-paths.ts → harness-paths.js} +24 -24
  101. package/src/helper/{marker-merge.ts → marker-merge.js} +4 -4
  102. package/src/helper/{prompt.ts → prompt.js} +5 -5
  103. package/src/helper/{repo-root.ts → repo-root.js} +2 -2
  104. package/src/helper/{settings-merge.ts → settings-merge.js} +27 -27
  105. package/src/helper/{settings-scope.ts → settings-scope.js} +3 -3
  106. package/src/helper/{toml.ts → toml.js} +48 -48
  107. package/src/install/{backup-set.ts → backup-set.js} +16 -16
  108. package/src/install/{backup.ts → backup.js} +65 -65
  109. package/src/install/{context.ts → context.js} +15 -15
  110. package/src/install/{manifest.ts → manifest.js} +27 -27
  111. package/src/install/{mcp.ts → mcp.js} +30 -30
  112. package/src/install/{paths.ts → paths.js} +15 -15
  113. package/src/install/{targets.ts → targets.js} +10 -10
  114. package/src/install/{tool-lifecycle.ts → tool-lifecycle.js} +20 -20
  115. package/src/lifecycle/{bash-availability.ts → bash-availability.js} +1 -1
  116. package/src/lifecycle/coverage.js +57 -0
  117. package/src/lifecycle/hook-step.js +61 -0
  118. package/src/lifecycle/{index.ts → index.js} +160 -146
  119. package/src/lifecycle/{mcp-index.ts → mcp-index.js} +1 -1
  120. package/src/lifecycle/{policies.ts → policies.js} +11 -11
  121. package/src/lifecycle/{view.ts → view.js} +28 -28
  122. package/src/registry/{index.ts → index.js} +195 -66
  123. package/src/release/build-package.js +91 -0
  124. package/src/release/changelog-section.js +70 -0
  125. package/src/release/{sync-plugin-versions.ts → sync-plugin-versions.js} +4 -4
  126. package/src/runtime/advice/{cli.ts → cli.js} +31 -31
  127. package/src/runtime/advice/{client.ts → client.js} +44 -44
  128. package/src/runtime/advice/{config.ts → config.js} +16 -16
  129. package/src/runtime/advice/{doctor.ts → doctor.js} +32 -32
  130. package/src/runtime/advice/{endpoint-guard.ts → endpoint-guard.js} +20 -20
  131. package/src/runtime/advice/{kinds.ts → kinds.js} +16 -16
  132. package/src/runtime/advice/providers/{ollama-systemone.ts → ollama-systemone.js} +21 -21
  133. package/src/runtime/advice/{record.ts → record.js} +19 -19
  134. package/src/runtime/advice/{registry.ts → registry.js} +16 -16
  135. package/src/runtime/advice/{strength.ts → strength.js} +7 -7
  136. package/src/runtime/{brief-tools.ts → brief-tools.js} +50 -50
  137. package/src/runtime/{c4-project.ts → c4-project.js} +27 -27
  138. package/src/runtime/candidate.js +505 -0
  139. package/src/runtime/{capability-router.ts → capability-router.js} +39 -39
  140. package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
  141. package/src/runtime/{claims.ts → claims.js} +44 -35
  142. package/src/runtime/{cli-result.ts → cli-result.js} +15 -8
  143. package/src/runtime/{cli.ts → cli.js} +59 -292
  144. package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
  145. package/src/runtime/context/budget.js +203 -0
  146. package/src/runtime/context/compose.js +1367 -0
  147. package/src/runtime/context/delivery-store.js +102 -0
  148. package/src/runtime/context/mandatory.js +594 -0
  149. package/src/runtime/context/pointer.js +142 -0
  150. package/src/runtime/context-pack.js +1277 -0
  151. package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
  152. package/src/runtime/evidence-fields.js +39 -0
  153. package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +32 -25
  154. package/src/runtime/failure/{capture.ts → capture.js} +29 -29
  155. package/src/runtime/failure/{classifier.ts → classifier.js} +4 -4
  156. package/src/runtime/failure/{cli.ts → cli.js} +30 -30
  157. package/src/runtime/failure/{home.ts → home.js} +6 -6
  158. package/src/runtime/failure/{store.ts → store.js} +32 -32
  159. package/src/runtime/{feature-resolve.ts → feature-resolve.js} +6 -6
  160. package/src/runtime/{freshness.ts → freshness.js} +59 -22
  161. package/src/runtime/{health.ts → health.js} +72 -72
  162. package/src/runtime/{history-compactor.ts → history-compactor.js} +25 -25
  163. package/src/runtime/{implementation-gate.ts → implementation-gate.js} +30 -30
  164. package/src/runtime/inventory/{coverage.ts → coverage.js} +10 -10
  165. package/src/runtime/inventory/{identity.ts → identity.js} +2 -2
  166. package/src/runtime/inventory/{index.ts → index.js} +36 -36
  167. package/src/runtime/inventory/{precedence.ts → precedence.js} +2 -2
  168. package/src/runtime/inventory/{read-scopes.ts → read-scopes.js} +9 -9
  169. package/src/runtime/inventory/{siblings.ts → siblings.js} +15 -15
  170. package/src/runtime/knowledge/{chunker.ts → chunker.js} +12 -12
  171. package/src/runtime/knowledge/{hybrid.ts → hybrid.js} +17 -17
  172. package/src/runtime/knowledge/{index-store.ts → index-store.js} +23 -23
  173. package/src/runtime/knowledge/{retrieval.ts → retrieval.js} +27 -27
  174. package/src/runtime/{leak-scan.ts → leak-scan.js} +12 -12
  175. package/src/runtime/lifecycle/{cli.ts → cli.js} +32 -32
  176. package/src/runtime/lifecycle/{event-store.ts → event-store.js} +48 -48
  177. package/src/runtime/lifecycle/{fold.ts → fold.js} +41 -41
  178. package/src/runtime/lifecycle/{followup.ts → followup.js} +54 -54
  179. package/src/runtime/lifecycle/{goal.ts → goal.js} +50 -50
  180. package/src/runtime/lifecycle/{intent-writer.ts → intent-writer.js} +5 -5
  181. package/src/runtime/lifecycle/{overview.ts → overview.js} +47 -47
  182. package/src/runtime/lifecycle/{release.ts → release.js} +29 -29
  183. package/src/runtime/lifecycle/{report-store.ts → report-store.js} +25 -25
  184. package/src/runtime/lifecycle/{retention.ts → retention.js} +37 -37
  185. package/src/runtime/lifecycle/{root.ts → root.js} +9 -9
  186. package/src/runtime/lifecycle/{status.ts → status.js} +64 -64
  187. package/src/runtime/lifecycle/{store-upkeep.ts → store-upkeep.js} +46 -46
  188. package/src/runtime/{locator-resolve.ts → locator-resolve.js} +7 -7
  189. package/src/runtime/{mask.ts → mask.js} +22 -22
  190. package/src/runtime/{mcp-consultations.ts → mcp-consultations.js} +54 -54
  191. package/src/runtime/{mcp-reach.ts → mcp-reach.js} +24 -24
  192. package/src/runtime/{model-router.ts → model-router.js} +20 -20
  193. package/src/runtime/{outcome.ts → outcome.js} +27 -27
  194. package/src/runtime/{reach.ts → reach.js} +21 -21
  195. package/src/runtime/{readiness-record.ts → readiness-record.js} +12 -12
  196. package/src/runtime/{readiness.ts → readiness.js} +113 -43
  197. package/src/runtime/{recovery.ts → recovery.js} +15 -15
  198. package/src/runtime/{research-request.ts → research-request.js} +34 -34
  199. package/src/runtime/{retrieval-plan.ts → retrieval-plan.js} +453 -104
  200. package/src/runtime/retrieval-record.js +223 -0
  201. package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +22 -19
  202. package/src/runtime/scaffold/{fingerprint.ts → fingerprint.js} +3 -3
  203. package/src/runtime/scaffold/{generate.ts → generate.js} +109 -109
  204. package/src/runtime/scaffold/{languages.ts → languages.js} +34 -34
  205. package/src/runtime/source-version.js +289 -0
  206. package/src/runtime/storage/{cli.ts → cli.js} +9 -9
  207. package/src/runtime/storage/{engine.ts → engine.js} +37 -37
  208. package/src/runtime/storage/{registry.ts → registry.js} +19 -19
  209. package/src/runtime/storage/{roots.ts → roots.js} +8 -8
  210. package/src/runtime/storage/{rules.ts → rules.js} +26 -26
  211. package/src/runtime/storage/{upkeep.ts → upkeep.js} +35 -35
  212. package/src/runtime/storage/{work-status.ts → work-status.js} +39 -39
  213. package/src/runtime/{task-attempts.ts → task-attempts.js} +62 -62
  214. package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
  215. package/src/runtime/{task-scope.ts → task-scope.js} +40 -15
  216. package/src/runtime/{task-state.ts → task-state.js} +86 -21
  217. package/src/runtime/trace/{indicators.ts → indicators.js} +22 -22
  218. package/src/runtime/trace/{ledger.ts → ledger.js} +42 -42
  219. package/src/runtime/trace/{render.ts → render.js} +7 -7
  220. package/src/runtime/trace/{views.ts → views.js} +40 -40
  221. package/src/runtime/verification/{contract-runner.ts → contract-runner.js} +23 -23
  222. package/src/runtime/verification/{engine.ts → engine.js} +143 -143
  223. package/src/runtime/verification/{registry.ts → registry.js} +6 -6
  224. package/src/runtime/verification/{scope-bound.ts → scope-bound.js} +50 -50
  225. package/src/runtime/verification/{test-selection.ts → test-selection.js} +28 -28
  226. package/src/runtime/{workflow-engine.ts → workflow-engine.js} +50 -50
  227. package/src/runtime/{workflow-orchestrator.ts → workflow-orchestrator.js} +91 -91
  228. package/src/runtime/{worktree.ts → worktree.js} +31 -31
  229. package/src/state/{index.ts → index.js} +26 -26
  230. package/src/state/{lockfile.ts → lockfile.js} +20 -20
  231. package/src/state/{run-lock.ts → run-lock.js} +44 -44
  232. package/core/.antigravity-plugin/hooks.json +0 -39
  233. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  234. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  235. package/core/harnesses/shared/hooks/hooks.json +0 -47
  236. package/src/runtime/context-pack.ts +0 -492
@@ -1,492 +0,0 @@
1
- 'use strict';
2
-
3
- // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
-
5
- const { EvidenceLedger } = require('./evidence-ledger.ts');
6
- const { ClaimsManager } = require('./claims.ts');
7
- const { ResearchRequestStore } = require('./research-request.ts');
8
- const { finishRuntime, usageError } = require('./cli-result.ts');
9
- const { resolveActiveFeature } = require('./feature-resolve.ts');
10
- const { readRegister } = require('./decision-register.ts');
11
-
12
- const NO_DECISIONS = Object.freeze({ available: false, live: [], liveCount: 0 });
13
-
14
- const TASK_CLASS_BUDGETS: Record<string, any> = Object.freeze({
15
- feature: 225000,
16
- 'dependency-change': 85000,
17
- bug: 71000,
18
- refactor: 71000,
19
- documentation: 57000,
20
- operations: 45000,
21
- review: 42000,
22
- research: 35302,
23
- 'trivial-edit': 30000,
24
- });
25
-
26
- /**
27
- * The live decisions of the feature the caller is working on (IC-012). The feature is resolved
28
- * from the branch, or from `slug` when the task id is not the feature slug. A feature with no
29
- * register or an unresolvable feature reads as "not available"; an unreadable register does too,
30
- * with a `reason`. Neither throws: a context pack is a read, and a missing register must not stop
31
- * a stage from getting its evidence.
32
- * @param {{projectRoot:string, slug?:string|null}} options
33
- * @returns {{available:boolean, live:Array<Object>, liveCount:number, reason?:string}}
34
- */
35
- function loadLiveDecisions({ projectRoot, slug = null }: any) {
36
- try {
37
- const feature = resolveActiveFeature({ projectRoot, slug });
38
- if (feature.error) return { ...NO_DECISIONS };
39
- let register;
40
- try {
41
- register = readRegister(feature.featureDir);
42
- } catch (error: any) {
43
- // The register exists but cannot be trusted. Stay unavailable, but say why, so a stage
44
- // sees the corruption instead of reading "no decisions".
45
- return { ...NO_DECISIONS, reason: `register unreadable: ${error.message}` };
46
- }
47
- if (!register) return { ...NO_DECISIONS };
48
- const live = register.decisions
49
- .filter((d: any) => d.status === 'live')
50
- .sort((a: any, b: any) => (a.topic < b.topic ? -1 : a.topic > b.topic ? 1 : 0))
51
- .map(({ id, topic, statement, decidedBy, stage }: any) => ({ id, topic, statement, decidedBy, stage }));
52
- return { available: true, live, liveCount: live.length };
53
- } catch {
54
- return { ...NO_DECISIONS };
55
- }
56
- }
57
-
58
- class ContextPackCompiler {
59
- declare options: any;
60
- /**
61
- * @param {Object} [defaultOptions]
62
- * @param {number} [defaultOptions.maxFiles=15]
63
- * @param {number} [defaultOptions.maxClaims=20]
64
- * @param {number} [defaultOptions.maxEvidenceItems=25]
65
- */
66
- constructor(defaultOptions: any = {}) {
67
- this.options = {
68
- maxFiles: defaultOptions.maxFiles || 15,
69
- maxClaims: defaultOptions.maxClaims || 20,
70
- maxEvidenceItems: defaultOptions.maxEvidenceItems || 25,
71
- maxResearchRequests: defaultOptions.maxResearchRequests || 20,
72
- };
73
- }
74
-
75
- /**
76
- * Compiles a ContextPack from task evidence and claims.
77
- * @param {Object} params
78
- * @param {string} params.taskId
79
- * @param {string} [params.taskClass='feature']
80
- * @param {string} [params.objective='']
81
- * @param {Array<string>} [params.constraints=[]]
82
- * @param {Array<string>} [params.acceptanceCriteria=[]]
83
- * @param {Object} params.evidenceLedger
84
- * @param {Object} params.claimsManager
85
- * @param {Object} [budgetOverrides={}]
86
- * @returns {Object} ContextPack
87
- */
88
- compileContextPack(params: any, budgetOverrides: any = {}) {
89
- const {
90
- taskId,
91
- taskClass = 'feature',
92
- objective = '',
93
- constraints = [],
94
- acceptanceCriteria = [],
95
- evidenceLedger,
96
- claimsManager,
97
- researchRequests = [],
98
- decisions = NO_DECISIONS,
99
- } = params;
100
-
101
- const limits = { ...this.options, ...budgetOverrides };
102
-
103
- const rawClaims = claimsManager ? claimsManager.getClaims(taskId) : [];
104
- const rawEvidence = evidenceLedger ? evidenceLedger.queryEvidence({ taskId }) : [];
105
-
106
- // Filter claims
107
- const supportedClaims = [];
108
- const activeHypotheses = [];
109
- const conflictedClaims = [];
110
-
111
- for (const claim of rawClaims) {
112
- if (claim.status === 'supported') {
113
- if (supportedClaims.length < limits.maxClaims) {
114
- supportedClaims.push({
115
- id: claim.id,
116
- statement: claim.statement,
117
- evidenceIds: claim.supportingEvidence,
118
- });
119
- }
120
- } else if (claim.status === 'hypothesis') {
121
- activeHypotheses.push({
122
- id: claim.id,
123
- statement: claim.statement,
124
- });
125
- } else if (claim.status === 'conflicted') {
126
- conflictedClaims.push({
127
- id: claim.id,
128
- statement: claim.statement,
129
- supportingEvidence: claim.supportingEvidence,
130
- contradictingEvidence: claim.contradictingEvidence,
131
- });
132
- }
133
- }
134
-
135
- // Extract relevant files and structural context from fresh evidence
136
- const relevantFileSet = new Set();
137
- const structuralNodes = [];
138
- const freshEvidenceItems = [];
139
-
140
- for (const ev of rawEvidence) {
141
- if (ev.freshness?.status === 'FRESH') {
142
- if (ev.locator?.file) {
143
- relevantFileSet.add(ev.locator.file);
144
- }
145
- if (ev.kind === 'structural' && ev.content) {
146
- structuralNodes.push(ev.content);
147
- }
148
- if (freshEvidenceItems.length < limits.maxEvidenceItems) {
149
- freshEvidenceItems.push({
150
- id: ev.id,
151
- kind: ev.kind,
152
- locator: ev.locator,
153
- summary: typeof ev.content === 'string' ? ev.content.slice(0, 120) : null,
154
- });
155
- }
156
- }
157
- }
158
-
159
- const relevantFiles = Array.from(relevantFileSet).slice(0, limits.maxFiles);
160
-
161
- return {
162
- version: 1,
163
- taskId: taskId || 'default',
164
- taskClass,
165
- compiledAt: new Date().toISOString(),
166
- objective,
167
- constraints: [...constraints],
168
- // Ported from `evidence/context_pack.py` (plan task B.3): the only field the Python pack
169
- // carried that this one did not. What the task must satisfy belongs beside the evidence
170
- // gathered to satisfy it, otherwise the verification engine has to re-read the requirement
171
- // to find out what it is verifying against.
172
- verificationRequirements: [...acceptanceCriteria],
173
- claims: {
174
- supported: supportedClaims,
175
- hypotheses: activeHypotheses,
176
- conflicts: conflictedClaims,
177
- },
178
- relevantFiles,
179
- structuralContext: structuralNodes.slice(0, 5),
180
- evidenceCount: freshEvidenceItems.length,
181
- evidenceSummary: freshEvidenceItems,
182
- researchRequests: [...researchRequests]
183
- .sort((a, b) => Number(b.blocking && b.status !== 'ANSWERED')
184
- - Number(a.blocking && a.status !== 'ANSWERED'))
185
- .slice(0, limits.maxResearchRequests).map(r => ({
186
- id: r.id, stageId: r.stageId, question: r.question, status: r.status,
187
- blocking: r.blocking, claimId: r.claimId, evidenceIds: r.evidenceIds, gap: r.gap,
188
- })),
189
- decisions: {
190
- available: decisions.available, live: [...decisions.live], liveCount: decisions.liveCount,
191
- ...(decisions.reason ? { reason: decisions.reason } : {}),
192
- },
193
- budgetEnforcement: {
194
- totalFiles: relevantFiles.length,
195
- totalSupportedClaims: supportedClaims.length,
196
- totalActiveHypotheses: activeHypotheses.length,
197
- limits,
198
- },
199
- };
200
- }
201
-
202
- /**
203
- * Formats a ContextPack into a concise markdown context block.
204
- * @param {Object} pack
205
- * @returns {string}
206
- */
207
- formatMarkdown(pack: any) {
208
- let md = `## ContextPack: [${pack.taskClass.toUpperCase()}] ${pack.taskId}\n`;
209
- if (pack.objective) {
210
- md += `**Objective:** ${pack.objective}\n\n`;
211
- }
212
-
213
- if (pack.claims.supported.length > 0) {
214
- md += `### Supported Facts & Invariants\n`;
215
- for (const c of pack.claims.supported) {
216
- md += `- ✓ ${c.statement} *(ev: ${c.evidenceIds.join(', ')})*\n`;
217
- }
218
- md += '\n';
219
- }
220
-
221
- if (pack.claims.hypotheses.length > 0) {
222
- md += `### Active Hypotheses (Unverified)\n`;
223
- for (const h of pack.claims.hypotheses) {
224
- md += `- ? ${h.statement}\n`;
225
- }
226
- md += '\n';
227
- }
228
-
229
- if (pack.researchRequests.length > 0) {
230
- md += `### Feature Research Requests\n`;
231
- for (const r of pack.researchRequests) {
232
- md += `- ${r.status} ${r.blocking ? '(blocking)' : '(nonblocking)'} ${r.stageId}: ${r.question}`;
233
- if (r.gap) md += ` — ${r.gap}`;
234
- if (r.claimId) md += ` (claim: ${r.claimId})`;
235
- md += '\n';
236
- }
237
- md += '\n';
238
- }
239
-
240
- if (pack.decisions && pack.decisions.liveCount > 0) {
241
- md += `### Live decisions\n`;
242
- for (const d of pack.decisions.live) md += `- ${d.id} (${d.topic}): ${d.statement}\n`;
243
- md += '\n';
244
- }
245
-
246
- if (pack.relevantFiles.length > 0) {
247
- md += `### Relevant File Locators\n`;
248
- for (const f of pack.relevantFiles) {
249
- md += `- \`${f}\`\n`;
250
- }
251
- md += '\n';
252
- }
253
-
254
- return md;
255
- }
256
-
257
- /**
258
- * Compiles bounded context pack payload with mandatory/optional partitioning (IC-001).
259
- * @param {Object} options
260
- * @param {string} options.taskId
261
- * @param {string} [options.taskClass='feature']
262
- * @param {number} [options.maxBytes]
263
- * @param {string} [options.objective='']
264
- * @param {Object} [options.mandatory]
265
- * @param {Array<string>} [options.mandatory.acceptanceCriteria]
266
- * @param {Array<string>} [options.mandatory.constraints]
267
- * @param {string} [options.mandatory.verificationPlan]
268
- * @param {Object} [options.optional]
269
- * @param {Array<string>} [options.optional.hypotheses]
270
- * @param {Array<string>} [options.optional.narrative]
271
- * @param {Array<string>} [options.optional.unverifiedClaims]
272
- * @returns {Object} ContextPackResult
273
- */
274
- compileBoundedContextPack(options: any = {}) {
275
- const {
276
- taskId = 'default',
277
- taskClass = 'feature',
278
- maxBytes,
279
- objective = '',
280
- mandatory = {},
281
- optional = {},
282
- } = options;
283
-
284
- const budgetBytes = Number.isInteger(maxBytes) && maxBytes > 0
285
- ? maxBytes
286
- : (TASK_CLASS_BUDGETS[taskClass] || 225000);
287
-
288
- const acceptanceCriteria = Array.isArray(mandatory.acceptanceCriteria) ? [...mandatory.acceptanceCriteria] : [];
289
- const constraints = Array.isArray(mandatory.constraints) ? [...mandatory.constraints] : [];
290
- const verificationPlan = typeof mandatory.verificationPlan === 'string' ? mandatory.verificationPlan : '';
291
-
292
- // Build mandatory section payload
293
- let mandatoryMd = `## ContextPack: [${taskClass.toUpperCase()}] ${taskId}\n`;
294
- if (objective) {
295
- mandatoryMd += `**Objective:** ${objective}\n\n`;
296
- }
297
- if (acceptanceCriteria.length > 0) {
298
- mandatoryMd += `### Acceptance Criteria\n`;
299
- for (const ac of acceptanceCriteria) {
300
- mandatoryMd += `- [ ] ${ac}\n`;
301
- }
302
- mandatoryMd += '\n';
303
- }
304
- if (constraints.length > 0) {
305
- mandatoryMd += `### Constraints\n`;
306
- for (const c of constraints) {
307
- mandatoryMd += `- ! ${c}\n`;
308
- }
309
- mandatoryMd += '\n';
310
- }
311
- if (verificationPlan) {
312
- mandatoryMd += `### Verification Plan\n${verificationPlan}\n\n`;
313
- }
314
-
315
- const mandatoryBytes = Buffer.byteLength(mandatoryMd, 'utf8');
316
-
317
- // Rule 1: Mandatory content is never truncated; if mandatoryBytes > budgetBytes, returns overflow: true.
318
- if (mandatoryBytes > budgetBytes) {
319
- const omissions = [];
320
- const narrativeList = Array.isArray(optional.narrative) ? optional.narrative : [];
321
- const claimsList = Array.isArray(optional.unverifiedClaims) ? optional.unverifiedClaims : [];
322
- const hypList = Array.isArray(optional.hypotheses) ? optional.hypotheses : [];
323
-
324
- for (let i = 0; i < narrativeList.length; i++) omissions.push({ id: `narrative-${i + 1}`, reason: 'budget-cap-exceeded' });
325
- for (let i = 0; i < claimsList.length; i++) omissions.push({ id: `claim-${i + 1}`, reason: 'budget-cap-exceeded' });
326
- for (let i = 0; i < hypList.length; i++) omissions.push({ id: `hypothesis-${i + 1}`, reason: 'budget-cap-exceeded' });
327
-
328
- return {
329
- taskId,
330
- taskClass,
331
- totalBytes: mandatoryBytes,
332
- budgetBytes,
333
- overflow: true,
334
- mandatoryBytes,
335
- optionalBytes: 0,
336
- omissions,
337
- payload: mandatoryMd,
338
- error: `Mandatory context (${mandatoryBytes} B) exceeds budget (${budgetBytes} B)`,
339
- };
340
- }
341
-
342
- // Rule 2: Optional content is trimmed in reverse priority order when mandatoryBytes + optionalBytes > budgetBytes.
343
- // Priority order: 1. hypotheses, 2. unverifiedClaims, 3. narrative.
344
- // Trimming in reverse priority: narrative first, then claims, then hypotheses.
345
- const hypotheses = Array.isArray(optional.hypotheses) ? [...optional.hypotheses] : [];
346
- const unverifiedClaims = Array.isArray(optional.unverifiedClaims) ? [...optional.unverifiedClaims] : [];
347
- const narrative = Array.isArray(optional.narrative) ? [...optional.narrative] : [];
348
-
349
- const keptHypotheses = [];
350
- const keptClaims = [];
351
- const keptNarrative = [];
352
- const omissions = [];
353
-
354
- const buildPayload = (hList: any, cList: any, nList: any) => {
355
- let md = mandatoryMd;
356
- if (hList.length > 0) {
357
- md += `### Active Hypotheses (Unverified)\n`;
358
- for (const h of hList) md += `- ? ${h}\n`;
359
- md += '\n';
360
- }
361
- if (cList.length > 0) {
362
- md += `### Unverified Claims\n`;
363
- for (const c of cList) md += `- ? ${c}\n`;
364
- md += '\n';
365
- }
366
- if (nList.length > 0) {
367
- md += `### Background Narrative\n`;
368
- for (const n of nList) md += `- ${n}\n`;
369
- md += '\n';
370
- }
371
- return md;
372
- };
373
-
374
- // Forward trial fitting: hypotheses first
375
- for (let i = 0; i < hypotheses.length; i++) {
376
- const trial = [...keptHypotheses, hypotheses[i]];
377
- const trialMd = buildPayload(trial, [], []);
378
- if (Buffer.byteLength(trialMd, 'utf8') <= budgetBytes) {
379
- keptHypotheses.push(hypotheses[i]);
380
- } else {
381
- omissions.push({ id: `hypothesis-${i + 1}`, reason: 'budget-cap-exceeded' });
382
- }
383
- }
384
-
385
- // unverifiedClaims next
386
- for (let i = 0; i < unverifiedClaims.length; i++) {
387
- const trial = [...keptClaims, unverifiedClaims[i]];
388
- const trialMd = buildPayload(keptHypotheses, trial, []);
389
- if (Buffer.byteLength(trialMd, 'utf8') <= budgetBytes) {
390
- keptClaims.push(unverifiedClaims[i]);
391
- } else {
392
- omissions.push({ id: `claim-${i + 1}`, reason: 'budget-cap-exceeded' });
393
- }
394
- }
395
-
396
- // narrative next
397
- for (let i = 0; i < narrative.length; i++) {
398
- const trial = [...keptNarrative, narrative[i]];
399
- const trialMd = buildPayload(keptHypotheses, keptClaims, trial);
400
- if (Buffer.byteLength(trialMd, 'utf8') <= budgetBytes) {
401
- keptNarrative.push(narrative[i]);
402
- } else {
403
- omissions.push({ id: `narrative-${i + 1}`, reason: 'budget-cap-exceeded' });
404
- }
405
- }
406
-
407
- const payload = buildPayload(keptHypotheses, keptClaims, keptNarrative);
408
- const totalBytes = Buffer.byteLength(payload, 'utf8');
409
- const optionalBytes = totalBytes - mandatoryBytes;
410
-
411
- return {
412
- taskId,
413
- taskClass,
414
- totalBytes,
415
- budgetBytes,
416
- overflow: false,
417
- mandatoryBytes,
418
- optionalBytes,
419
- omissions,
420
- payload,
421
- };
422
- }
423
-
424
- /**
425
- * Alias for compileBoundedContextPack.
426
- */
427
- compileBoundedPayload(options: any = {}) {
428
- return this.compileBoundedContextPack(options);
429
- }
430
- }
431
-
432
- /**
433
- * Handles `doflow context-pack` — compile the evidence and claims recorded for a task into the
434
- * context block a stage is handed.
435
- *
436
- * Exits 1 on a pack with nothing in it. An empty pack is not evidence that a task needs no
437
- * context; it is evidence that nothing was recorded, and reporting it as success is the
438
- * empty-contract defect in another costume.
439
- *
440
- * @param {Object} options
441
- * @param {string} options.taskId
442
- * @param {string} [options.taskClass]
443
- * @param {string} [options.objective]
444
- * @param {boolean} [options.json=false]
445
- * @param {string} [options.stateRoot]
446
- * @param {string} [options.slug] feature slug, when the task id is not the feature's own
447
- * @returns {number} exit code
448
- */
449
- function handleContextPackCommand({ taskId, taskClass, objective, json = false, stateRoot, slug }: any = {}) {
450
- const root = stateRoot || process.cwd();
451
- const ledger = new EvidenceLedger({ repoRoot: root, slug });
452
- ledger.load(taskId);
453
- const claims = new ClaimsManager({ evidenceLedger: ledger, repoRoot: root, slug });
454
- claims.load(taskId);
455
- claims.evaluateAll();
456
- const researchRequests = new ResearchRequestStore({ projectRoot: root, slug }).list(taskId);
457
-
458
- const compiler = new ContextPackCompiler();
459
- const pack = compiler.compileContextPack({
460
- taskId,
461
- // The library's own default. Passed through rather than substituted here so there is one
462
- // place that decides what an unstated class means for a *label* — which is all it is in a
463
- // pack, unlike readiness where it selects the contract.
464
- ...(taskClass ? { taskClass } : {}),
465
- objective: objective || '',
466
- evidenceLedger: ledger,
467
- claimsManager: claims,
468
- researchRequests,
469
- decisions: loadLiveDecisions({ projectRoot: root, slug: slug || null }),
470
- });
471
-
472
- const empty = pack.evidenceCount === 0
473
- && pack.claims.supported.length === 0
474
- && pack.claims.hypotheses.length === 0
475
- && pack.claims.conflicts.length === 0
476
- && pack.researchRequests.length === 0
477
- && pack.decisions.liveCount === 0;
478
-
479
- if (json) console.log(JSON.stringify({ ...pack, empty }, null, 2));
480
- else {
481
- console.log(compiler.formatMarkdown(pack));
482
- if (empty) console.log(`_No evidence or claims are recorded for task '${taskId}'; this pack states nothing._\n`);
483
- }
484
- return finishRuntime(empty ? 1 : 0);
485
- }
486
-
487
- module.exports = {
488
- ContextPackCompiler,
489
- TASK_CLASS_BUDGETS,
490
- handleContextPackCommand,
491
- loadLiveDecisions,
492
- };