@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.
- package/bin/doflow.js +2 -2
- package/core/.antigravity-plugin/plugin.json +0 -1
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
- package/core/harnesses/claude/hooks/session-start.sh +5 -3
- package/core/harnesses/claude/hooks/stop-check.sh +5 -3
- package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
- package/core/harnesses/codex/hooks/session-start.sh +5 -3
- package/core/harnesses/codex/hooks/stop-check.sh +6 -5
- package/core/harnesses/codex/hooks/subagent-audit.sh +17 -6
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +7 -18
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +7 -18
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +7 -19
- package/core/harnesses/gemini/hooks/session-start.sh +5 -3
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +20 -5
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +20 -5
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +20 -5
- package/core/harnesses/kiro/hooks/session-start.sh +11 -5
- package/core/harnesses/kiro/hooks/stop-check.sh +21 -30
- package/core/harnesses/pi/extensions/doflow-guard.js +159 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -11
- package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
- package/core/harnesses/shared/hooks/bridge/bridge.sh +184 -0
- package/core/harnesses/shared/hooks/bridge/envelope.jq +60 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +62 -0
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +4 -2
- package/core/harnesses/shared/hooks/policies/contract.sh +75 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +39 -4
- package/core/harnesses/shared/hooks/policies/lib.sh +4 -2
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +46 -34
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +75 -25
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +67 -73
- package/core/harnesses/shared/hooks/policies/session-context.sh +37 -7
- package/core/harnesses/shared/hooks/policies/stop-check.sh +42 -15
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +35 -5
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +40 -7
- package/core/harnesses/shared/hooks/stream-hook-runner.js +69 -181
- package/core/registry/assets.json +19 -0
- package/core/registry/contracts.json +2 -2
- package/core/registry/harnesses.json +196 -10
- package/core/registry/lifecycle.json +2626 -7
- package/core/registry/storage.json +110 -83
- package/core/registry/verification.json +1 -1
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
- package/core/shared/scripts/doflow/bin/doflow-run +10 -6
- package/core/shared/skills/do-design/SKILL.md +6 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +11 -10
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +2 -0
- package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
- package/core/shared/skills/do-implement/SKILL.md +3 -2
- package/core/shared/skills/do-plan/SKILL.md +7 -8
- package/package.json +4 -2
- package/src/adapters/antigravity/{index.ts → index.js} +141 -105
- package/src/adapters/claude/{index.ts → index.js} +63 -49
- package/src/adapters/claude/{mcp.ts → mcp.js} +16 -16
- package/src/adapters/codex/{agents.ts → agents.js} +24 -24
- package/src/adapters/codex/{config.ts → config.js} +49 -49
- package/src/adapters/codex/{hooks.ts → hooks.js} +62 -27
- package/src/adapters/codex/{index.ts → index.js} +148 -105
- package/src/adapters/codex/{mcp.ts → mcp.js} +38 -38
- package/src/adapters/codex/{native-projection.ts → native-projection.js} +5 -5
- package/src/adapters/copilot/{index.ts → index.js} +42 -42
- package/src/adapters/{copy-tree.ts → copy-tree.js} +74 -74
- package/src/adapters/gemini/{hooks.ts → hooks.js} +78 -37
- package/src/adapters/gemini/{index.ts → index.js} +96 -57
- package/src/adapters/{hook-commands.ts → hook-commands.js} +8 -8
- package/src/adapters/{index.ts → index.js} +13 -13
- package/src/adapters/kiro/{index.ts → index.js} +49 -35
- package/src/adapters/{mcp-entries.ts → mcp-entries.js} +55 -55
- package/src/adapters/opencode/{index.ts → index.js} +52 -52
- package/src/adapters/pi/hooks.js +119 -0
- package/src/adapters/pi/{index.ts → index.js} +64 -39
- package/src/adapters/pi/{json-members.ts → json-members.js} +23 -23
- package/src/adapters/pi/{mcp.ts → mcp.js} +70 -70
- package/src/adapters/{resolve-source.ts → resolve-source.js} +1 -1
- package/src/cli/commands/{install.ts → install.js} +25 -25
- package/src/cli/commands/{list-backups.ts → list-backups.js} +4 -4
- package/src/cli/commands/{reconcile.ts → reconcile.js} +19 -19
- package/src/cli/commands/{remove.ts → remove.js} +10 -10
- package/src/cli/commands/{rollback.ts → rollback.js} +17 -17
- package/src/cli/commands/{self-update.ts → self-update.js} +3 -3
- package/src/cli/commands/{status.ts → status.js} +24 -24
- package/src/cli/commands/{tools.ts → tools.js} +16 -16
- package/src/cli/commands/{update.ts → update.js} +20 -20
- package/src/cli/{index.ts → index.js} +43 -31
- package/src/cli/{runtime-commands.ts → runtime-commands.js} +97 -58
- package/src/cli/{shared.ts → shared.js} +40 -40
- package/src/helper/{bash-helper.ts → bash-helper.js} +7 -7
- package/src/helper/{git.ts → git.js} +2 -2
- package/src/helper/{guardrails.ts → guardrails.js} +10 -10
- package/src/helper/{harness-paths.ts → harness-paths.js} +24 -24
- package/src/helper/{marker-merge.ts → marker-merge.js} +4 -4
- package/src/helper/{prompt.ts → prompt.js} +5 -5
- package/src/helper/{repo-root.ts → repo-root.js} +2 -2
- package/src/helper/{settings-merge.ts → settings-merge.js} +27 -27
- package/src/helper/{settings-scope.ts → settings-scope.js} +3 -3
- package/src/helper/{toml.ts → toml.js} +48 -48
- package/src/install/{backup-set.ts → backup-set.js} +16 -16
- package/src/install/{backup.ts → backup.js} +65 -65
- package/src/install/{context.ts → context.js} +15 -15
- package/src/install/{manifest.ts → manifest.js} +27 -27
- package/src/install/{mcp.ts → mcp.js} +30 -30
- package/src/install/{paths.ts → paths.js} +15 -15
- package/src/install/{targets.ts → targets.js} +10 -10
- package/src/install/{tool-lifecycle.ts → tool-lifecycle.js} +20 -20
- package/src/lifecycle/{bash-availability.ts → bash-availability.js} +1 -1
- package/src/lifecycle/coverage.js +57 -0
- package/src/lifecycle/hook-step.js +61 -0
- package/src/lifecycle/{index.ts → index.js} +160 -146
- package/src/lifecycle/{mcp-index.ts → mcp-index.js} +1 -1
- package/src/lifecycle/{policies.ts → policies.js} +11 -11
- package/src/lifecycle/{view.ts → view.js} +28 -28
- package/src/registry/{index.ts → index.js} +195 -66
- package/src/release/build-package.js +91 -0
- package/src/release/changelog-section.js +70 -0
- package/src/release/{sync-plugin-versions.ts → sync-plugin-versions.js} +4 -4
- package/src/runtime/advice/{cli.ts → cli.js} +31 -31
- package/src/runtime/advice/{client.ts → client.js} +44 -44
- package/src/runtime/advice/{config.ts → config.js} +16 -16
- package/src/runtime/advice/{doctor.ts → doctor.js} +32 -32
- package/src/runtime/advice/{endpoint-guard.ts → endpoint-guard.js} +20 -20
- package/src/runtime/advice/{kinds.ts → kinds.js} +16 -16
- package/src/runtime/advice/providers/{ollama-systemone.ts → ollama-systemone.js} +21 -21
- package/src/runtime/advice/{record.ts → record.js} +19 -19
- package/src/runtime/advice/{registry.ts → registry.js} +16 -16
- package/src/runtime/advice/{strength.ts → strength.js} +7 -7
- package/src/runtime/{brief-tools.ts → brief-tools.js} +50 -50
- package/src/runtime/{c4-project.ts → c4-project.js} +27 -27
- package/src/runtime/candidate.js +505 -0
- package/src/runtime/{capability-router.ts → capability-router.js} +39 -39
- package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
- package/src/runtime/{claims.ts → claims.js} +44 -35
- package/src/runtime/{cli-result.ts → cli-result.js} +15 -8
- package/src/runtime/{cli.ts → cli.js} +59 -292
- package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
- package/src/runtime/context/budget.js +203 -0
- package/src/runtime/context/compose.js +1367 -0
- package/src/runtime/context/delivery-store.js +102 -0
- package/src/runtime/context/mandatory.js +594 -0
- package/src/runtime/context/pointer.js +142 -0
- package/src/runtime/context-pack.js +1277 -0
- package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
- package/src/runtime/evidence-fields.js +39 -0
- package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +32 -25
- package/src/runtime/failure/{capture.ts → capture.js} +29 -29
- package/src/runtime/failure/{classifier.ts → classifier.js} +4 -4
- package/src/runtime/failure/{cli.ts → cli.js} +30 -30
- package/src/runtime/failure/{home.ts → home.js} +6 -6
- package/src/runtime/failure/{store.ts → store.js} +32 -32
- package/src/runtime/{feature-resolve.ts → feature-resolve.js} +6 -6
- package/src/runtime/{freshness.ts → freshness.js} +59 -22
- package/src/runtime/{health.ts → health.js} +72 -72
- package/src/runtime/{history-compactor.ts → history-compactor.js} +25 -25
- package/src/runtime/{implementation-gate.ts → implementation-gate.js} +30 -30
- package/src/runtime/inventory/{coverage.ts → coverage.js} +10 -10
- package/src/runtime/inventory/{identity.ts → identity.js} +2 -2
- package/src/runtime/inventory/{index.ts → index.js} +36 -36
- package/src/runtime/inventory/{precedence.ts → precedence.js} +2 -2
- package/src/runtime/inventory/{read-scopes.ts → read-scopes.js} +9 -9
- package/src/runtime/inventory/{siblings.ts → siblings.js} +15 -15
- package/src/runtime/knowledge/{chunker.ts → chunker.js} +12 -12
- package/src/runtime/knowledge/{hybrid.ts → hybrid.js} +17 -17
- package/src/runtime/knowledge/{index-store.ts → index-store.js} +23 -23
- package/src/runtime/knowledge/{retrieval.ts → retrieval.js} +27 -27
- package/src/runtime/{leak-scan.ts → leak-scan.js} +12 -12
- package/src/runtime/lifecycle/{cli.ts → cli.js} +32 -32
- package/src/runtime/lifecycle/{event-store.ts → event-store.js} +48 -48
- package/src/runtime/lifecycle/{fold.ts → fold.js} +41 -41
- package/src/runtime/lifecycle/{followup.ts → followup.js} +54 -54
- package/src/runtime/lifecycle/{goal.ts → goal.js} +50 -50
- package/src/runtime/lifecycle/{intent-writer.ts → intent-writer.js} +5 -5
- package/src/runtime/lifecycle/{overview.ts → overview.js} +47 -47
- package/src/runtime/lifecycle/{release.ts → release.js} +29 -29
- package/src/runtime/lifecycle/{report-store.ts → report-store.js} +25 -25
- package/src/runtime/lifecycle/{retention.ts → retention.js} +37 -37
- package/src/runtime/lifecycle/{root.ts → root.js} +9 -9
- package/src/runtime/lifecycle/{status.ts → status.js} +64 -64
- package/src/runtime/lifecycle/{store-upkeep.ts → store-upkeep.js} +46 -46
- package/src/runtime/{locator-resolve.ts → locator-resolve.js} +7 -7
- package/src/runtime/{mask.ts → mask.js} +22 -22
- package/src/runtime/{mcp-consultations.ts → mcp-consultations.js} +54 -54
- package/src/runtime/{mcp-reach.ts → mcp-reach.js} +24 -24
- package/src/runtime/{model-router.ts → model-router.js} +20 -20
- package/src/runtime/{outcome.ts → outcome.js} +27 -27
- package/src/runtime/{reach.ts → reach.js} +21 -21
- package/src/runtime/{readiness-record.ts → readiness-record.js} +12 -12
- package/src/runtime/{readiness.ts → readiness.js} +113 -43
- package/src/runtime/{recovery.ts → recovery.js} +15 -15
- package/src/runtime/{research-request.ts → research-request.js} +34 -34
- package/src/runtime/{retrieval-plan.ts → retrieval-plan.js} +453 -104
- package/src/runtime/retrieval-record.js +223 -0
- package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +22 -19
- package/src/runtime/scaffold/{fingerprint.ts → fingerprint.js} +3 -3
- package/src/runtime/scaffold/{generate.ts → generate.js} +109 -109
- package/src/runtime/scaffold/{languages.ts → languages.js} +34 -34
- package/src/runtime/source-version.js +289 -0
- package/src/runtime/storage/{cli.ts → cli.js} +9 -9
- package/src/runtime/storage/{engine.ts → engine.js} +37 -37
- package/src/runtime/storage/{registry.ts → registry.js} +19 -19
- package/src/runtime/storage/{roots.ts → roots.js} +8 -8
- package/src/runtime/storage/{rules.ts → rules.js} +26 -26
- package/src/runtime/storage/{upkeep.ts → upkeep.js} +35 -35
- package/src/runtime/storage/{work-status.ts → work-status.js} +39 -39
- package/src/runtime/{task-attempts.ts → task-attempts.js} +62 -62
- package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
- package/src/runtime/{task-scope.ts → task-scope.js} +40 -15
- package/src/runtime/{task-state.ts → task-state.js} +86 -21
- package/src/runtime/trace/{indicators.ts → indicators.js} +22 -22
- package/src/runtime/trace/{ledger.ts → ledger.js} +42 -42
- package/src/runtime/trace/{render.ts → render.js} +7 -7
- package/src/runtime/trace/{views.ts → views.js} +40 -40
- package/src/runtime/verification/{contract-runner.ts → contract-runner.js} +23 -23
- package/src/runtime/verification/{engine.ts → engine.js} +143 -143
- package/src/runtime/verification/{registry.ts → registry.js} +6 -6
- package/src/runtime/verification/{scope-bound.ts → scope-bound.js} +50 -50
- package/src/runtime/verification/{test-selection.ts → test-selection.js} +28 -28
- package/src/runtime/{workflow-engine.ts → workflow-engine.js} +50 -50
- package/src/runtime/{workflow-orchestrator.ts → workflow-orchestrator.js} +91 -91
- package/src/runtime/{worktree.ts → worktree.js} +31 -31
- package/src/state/{index.ts → index.js} +26 -26
- package/src/state/{lockfile.ts → lockfile.js} +20 -20
- package/src/state/{run-lock.ts → run-lock.js} +44 -44
- package/core/.antigravity-plugin/hooks.json +0 -39
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
- package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
- package/core/harnesses/shared/hooks/hooks.json +0 -47
- 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
|
-
};
|