@khoavu882/doflow 2.0.0-beta.3 → 2.0.0-beta.4
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/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/registry/storage.json +87 -83
- package/core/registry/verification.json +1 -1
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
- package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
- package/package.json +4 -2
- package/src/adapters/antigravity/{index.ts → index.js} +60 -60
- package/src/adapters/claude/{index.ts → index.js} +48 -48
- 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} +23 -23
- package/src/adapters/codex/{index.ts → index.js} +98 -98
- 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} +70 -70
- package/src/adapters/gemini/{hooks.ts → hooks.js} +24 -24
- package/src/adapters/gemini/{index.ts → index.js} +41 -41
- 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} +34 -34
- 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/{index.ts → index.js} +30 -30
- 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} +24 -24
- 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} +19 -19
- package/src/cli/{index.ts → index.js} +26 -26
- package/src/cli/{runtime-commands.ts → runtime-commands.js} +48 -48
- 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/{index.ts → index.js} +140 -140
- 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} +60 -60
- 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/{capability-router.ts → capability-router.js} +39 -39
- package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
- package/src/runtime/{claims.ts → claims.js} +30 -30
- package/src/runtime/{cli-result.ts → cli-result.js} +4 -4
- package/src/runtime/{cli.ts → cli.js} +37 -37
- package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
- package/src/runtime/{context-pack.ts → context-pack.js} +20 -20
- package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
- package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +25 -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} +15 -15
- 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} +35 -35
- 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} +40 -40
- package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +19 -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/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} +61 -61
- package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
- package/src/runtime/{task-scope.ts → task-scope.js} +13 -13
- package/src/runtime/{task-state.ts → task-state.js} +15 -15
- 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
|
@@ -6,11 +6,11 @@ const fs = require('node:fs');
|
|
|
6
6
|
const path = require('node:path');
|
|
7
7
|
const crypto = require('node:crypto');
|
|
8
8
|
// Shared with EvidenceLedger so both stores enforce one definition of a safe task id.
|
|
9
|
-
const { assertSafeTaskId, EvidenceLedger } = require('./evidence-ledger.
|
|
10
|
-
const { updateTaskState, readTaskState, mergeRecords } = require('./task-state.
|
|
11
|
-
const { taskStoreDir } = require('./task-scope.
|
|
12
|
-
const { finishRuntime, usageError } = require('./cli-result.
|
|
13
|
-
const { REPO_ROOT } = require('../helper/repo-root.
|
|
9
|
+
const { assertSafeTaskId, EvidenceLedger } = require('./evidence-ledger.js');
|
|
10
|
+
const { updateTaskState, readTaskState, mergeRecords } = require('./task-state.js');
|
|
11
|
+
const { taskStoreDir } = require('./task-scope.js');
|
|
12
|
+
const { finishRuntime, usageError } = require('./cli-result.js');
|
|
13
|
+
const { REPO_ROOT } = require('../helper/repo-root.js');
|
|
14
14
|
|
|
15
15
|
const CLAIM_STATUSES = new Set([
|
|
16
16
|
'hypothesis',
|
|
@@ -38,15 +38,15 @@ const CLAIM_STATUSES = new Set([
|
|
|
38
38
|
const TERMINAL_CLAIM_STATUSES = new Set(['retracted', 'superseded']);
|
|
39
39
|
|
|
40
40
|
class ClaimsManager {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
50
|
/**
|
|
51
51
|
* @param {Object} [options]
|
|
52
52
|
* @param {Object} [options.evidenceLedger]
|
|
@@ -55,7 +55,7 @@ class ClaimsManager {
|
|
|
55
55
|
* @param {string} [options.slug] feature whose namespace the records live under (see task-scope.js)
|
|
56
56
|
* @param {Object} [options.fsImpl]
|
|
57
57
|
*/
|
|
58
|
-
constructor(options
|
|
58
|
+
constructor(options = {}) {
|
|
59
59
|
this.fsImpl = options.fsImpl || fs;
|
|
60
60
|
this.evidenceLedger = options.evidenceLedger || null;
|
|
61
61
|
this.repoRoot = options.repoRoot || REPO_ROOT;
|
|
@@ -68,7 +68,7 @@ class ClaimsManager {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/** Where this task's claims file lives: beside its evidence, in the feature's namespace when it has one. */
|
|
71
|
-
fileFor(taskId
|
|
71
|
+
fileFor(taskId ) {
|
|
72
72
|
const dir = this.fixedStateDir
|
|
73
73
|
|| taskStoreDir({ projectRoot: this.repoRoot, store: 'evidence', taskId, slug: this.slug });
|
|
74
74
|
return path.join(dir, `${assertSafeTaskId(taskId)}_claims.json`);
|
|
@@ -87,7 +87,7 @@ class ClaimsManager {
|
|
|
87
87
|
* @param {Object} item - { statement, taskId, status, id, role }
|
|
88
88
|
* @returns {string} claimId
|
|
89
89
|
*/
|
|
90
|
-
addClaim(item
|
|
90
|
+
addClaim(item ) {
|
|
91
91
|
if (!item || typeof item !== 'object') {
|
|
92
92
|
throw new Error('Claim item must be an object');
|
|
93
93
|
}
|
|
@@ -125,7 +125,7 @@ class ClaimsManager {
|
|
|
125
125
|
* @param {string} id
|
|
126
126
|
* @returns {Object|null}
|
|
127
127
|
*/
|
|
128
|
-
getClaim(id
|
|
128
|
+
getClaim(id ) {
|
|
129
129
|
return this.claimsMap.get(id) || null;
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -135,7 +135,7 @@ class ClaimsManager {
|
|
|
135
135
|
* @param {string} evidenceId
|
|
136
136
|
* @param {'supports'|'contradicts'} [relation='supports']
|
|
137
137
|
*/
|
|
138
|
-
linkEvidence(claimId
|
|
138
|
+
linkEvidence(claimId , evidenceId , relation = 'supports') {
|
|
139
139
|
const claim = this.claimsMap.get(claimId);
|
|
140
140
|
if (!claim) {
|
|
141
141
|
throw new Error(`Unknown claim '${claimId}'`);
|
|
@@ -174,7 +174,7 @@ class ClaimsManager {
|
|
|
174
174
|
* @param {string} claimId
|
|
175
175
|
* @returns {'hypothesis'|'supported'|'conflicted'|'invalidated'|'unknown'}
|
|
176
176
|
*/
|
|
177
|
-
evaluateClaim(claimId
|
|
177
|
+
evaluateClaim(claimId ) {
|
|
178
178
|
const claim = this.claimsMap.get(claimId);
|
|
179
179
|
if (!claim) {
|
|
180
180
|
throw new Error(`Unknown claim '${claimId}'`);
|
|
@@ -239,7 +239,7 @@ class ClaimsManager {
|
|
|
239
239
|
* @param {string} [supersededBy]
|
|
240
240
|
* @returns {string} the new status
|
|
241
241
|
*/
|
|
242
|
-
finalizeClaim(claimId
|
|
242
|
+
finalizeClaim(claimId , status , supersededBy ) {
|
|
243
243
|
const claim = this.claimsMap.get(claimId);
|
|
244
244
|
if (!claim) {
|
|
245
245
|
throw new Error(`Unknown claim '${claimId}'`);
|
|
@@ -260,7 +260,7 @@ class ClaimsManager {
|
|
|
260
260
|
* @param {string} claimId
|
|
261
261
|
* @returns {string} the new status
|
|
262
262
|
*/
|
|
263
|
-
retractClaim(claimId
|
|
263
|
+
retractClaim(claimId ) {
|
|
264
264
|
return this.finalizeClaim(claimId, 'retracted');
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -273,7 +273,7 @@ class ClaimsManager {
|
|
|
273
273
|
* @param {string} replacedBy
|
|
274
274
|
* @returns {string} the new status
|
|
275
275
|
*/
|
|
276
|
-
supersedeClaim(claimId
|
|
276
|
+
supersedeClaim(claimId , replacedBy ) {
|
|
277
277
|
// The target is checked first: validating the replacement before the claim being superseded
|
|
278
278
|
// reported a missing replacement when the caller had actually mistyped the target, sending them
|
|
279
279
|
// to fix the wrong id.
|
|
@@ -307,7 +307,7 @@ class ClaimsManager {
|
|
|
307
307
|
* @param {string} [taskId]
|
|
308
308
|
* @returns {Array<Object>}
|
|
309
309
|
*/
|
|
310
|
-
getClaims(taskId
|
|
310
|
+
getClaims(taskId ) {
|
|
311
311
|
const results = [];
|
|
312
312
|
for (const claim of this.claimsMap.values()) {
|
|
313
313
|
if (!taskId || claim.taskId === taskId) {
|
|
@@ -322,13 +322,13 @@ class ClaimsManager {
|
|
|
322
322
|
* @param {string} [taskId='default']
|
|
323
323
|
* @returns {string} filePath
|
|
324
324
|
*/
|
|
325
|
-
save(taskId = 'default')
|
|
325
|
+
save(taskId = 'default') {
|
|
326
326
|
const targetFile = this.fileFor(taskId);
|
|
327
|
-
let merged
|
|
327
|
+
let merged ;
|
|
328
328
|
const file = updateTaskState({
|
|
329
329
|
fsImpl: this.fsImpl,
|
|
330
330
|
file: targetFile,
|
|
331
|
-
build: (disk
|
|
331
|
+
build: (disk ) => {
|
|
332
332
|
merged = mergeRecords(this.getClaims(taskId), disk?.claims || [], this.baseline);
|
|
333
333
|
return { taskId, updatedAt: new Date().toISOString(), claimsCount: merged.length, claims: merged };
|
|
334
334
|
},
|
|
@@ -345,7 +345,7 @@ class ClaimsManager {
|
|
|
345
345
|
* @param {string} [taskId='default']
|
|
346
346
|
* @returns {number}
|
|
347
347
|
*/
|
|
348
|
-
load(taskId = 'default')
|
|
348
|
+
load(taskId = 'default') {
|
|
349
349
|
const targetFile = this.fileFor(taskId);
|
|
350
350
|
const data = readTaskState(this.fsImpl, targetFile);
|
|
351
351
|
if (data && Array.isArray(data.claims)) {
|
|
@@ -385,7 +385,7 @@ class ClaimsManager {
|
|
|
385
385
|
* @param {string} [options.slug] feature the task belongs to, when not the branch's
|
|
386
386
|
* @returns {number} exit code
|
|
387
387
|
*/
|
|
388
|
-
function handleClaimCommand({ taskId, action = 'list', statement, claimId, evidenceId, replacedBy, relation = 'supports', role, json = false, stateRoot, slug }
|
|
388
|
+
function handleClaimCommand({ taskId, action = 'list', statement, claimId, evidenceId, replacedBy, relation = 'supports', role, json = false, stateRoot, slug } = {}) {
|
|
389
389
|
const root = stateRoot || process.cwd();
|
|
390
390
|
const ledger = new EvidenceLedger({ repoRoot: root, slug });
|
|
391
391
|
ledger.load(taskId);
|
|
@@ -437,7 +437,7 @@ function handleClaimCommand({ taskId, action = 'list', statement, claimId, evide
|
|
|
437
437
|
} else {
|
|
438
438
|
return usageError('claim', `unknown --action '${action}'. Valid: list, add, link, retract, supersede`, json);
|
|
439
439
|
}
|
|
440
|
-
} catch (error
|
|
440
|
+
} catch (error ) {
|
|
441
441
|
return usageError('claim', error.message, json, error);
|
|
442
442
|
}
|
|
443
443
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @param {number} code
|
|
17
17
|
* @returns {number} the code, for chaining
|
|
18
18
|
*/
|
|
19
|
-
function finishRuntime(code
|
|
19
|
+
function finishRuntime(code ) {
|
|
20
20
|
process.exitCode = code;
|
|
21
21
|
return code;
|
|
22
22
|
}
|
|
@@ -29,8 +29,8 @@ function finishRuntime(code: number): number {
|
|
|
29
29
|
* @param {string} command the verb or installer command name
|
|
30
30
|
* @param {number} exit the exit status the caller is about to produce
|
|
31
31
|
*/
|
|
32
|
-
function captureCaught(error
|
|
33
|
-
try { require('./failure/capture.
|
|
32
|
+
function captureCaught(error , command , exit ) {
|
|
33
|
+
try { require('./failure/capture.js').captureError(error, { command, exit }); } catch { /* capture is best-effort */ }
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -45,7 +45,7 @@ function captureCaught(error: any, command: string, exit: number): void {
|
|
|
45
45
|
* @param {Error} [error]
|
|
46
46
|
* @returns {number} 2 (USAGE error exit code)
|
|
47
47
|
*/
|
|
48
|
-
function usageError(verb
|
|
48
|
+
function usageError(verb , message , json , error ) {
|
|
49
49
|
if (error !== undefined) captureCaught(error, verb, 2);
|
|
50
50
|
if (json) console.log(JSON.stringify({ ok: false, status: 'USAGE', exitCode: 2, error: 'usage', summary: message }, null, 2));
|
|
51
51
|
else console.error(`doflow ${verb}: ${message}`);
|
|
@@ -6,18 +6,18 @@ const crypto = require('node:crypto');
|
|
|
6
6
|
const fs = require('node:fs');
|
|
7
7
|
const path = require('node:path');
|
|
8
8
|
const { execFileSync } = require('node:child_process');
|
|
9
|
-
const { CapabilityRouter } = require('./capability-router.
|
|
10
|
-
const { EvidenceLedger, VALID_EVIDENCE_KINDS, VALID_PROVENANCE } = require('./evidence-ledger.
|
|
11
|
-
const { resolveLocator, describeResolution } = require('./locator-resolve.
|
|
12
|
-
const { ClaimsManager } = require('./claims.
|
|
13
|
-
const { measureFreshness } = require('./freshness.
|
|
14
|
-
const { evaluateTaskReadiness } = require('./readiness.
|
|
15
|
-
const { writeReadinessRecord } = require('./readiness-record.
|
|
16
|
-
const { parseDeclaredScope } = require('./verification/scope-bound.
|
|
17
|
-
const { loadRegistry } = require('../registry/index.
|
|
18
|
-
const { REPO_ROOT } = require('../helper/repo-root.
|
|
9
|
+
const { CapabilityRouter } = require('./capability-router.js');
|
|
10
|
+
const { EvidenceLedger, VALID_EVIDENCE_KINDS, VALID_PROVENANCE } = require('./evidence-ledger.js');
|
|
11
|
+
const { resolveLocator, describeResolution } = require('./locator-resolve.js');
|
|
12
|
+
const { ClaimsManager } = require('./claims.js');
|
|
13
|
+
const { measureFreshness } = require('./freshness.js');
|
|
14
|
+
const { evaluateTaskReadiness } = require('./readiness.js');
|
|
15
|
+
const { writeReadinessRecord } = require('./readiness-record.js');
|
|
16
|
+
const { parseDeclaredScope } = require('./verification/scope-bound.js');
|
|
17
|
+
const { loadRegistry } = require('../registry/index.js');
|
|
18
|
+
const { REPO_ROOT } = require('../helper/repo-root.js');
|
|
19
19
|
// One definition of the exit and usage helpers (design §4.2); `finish` is the local spelling of `finishRuntime`.
|
|
20
|
-
const { finishRuntime: finish, usageError } = require('./cli-result.
|
|
20
|
+
const { finishRuntime: finish, usageError } = require('./cli-result.js');
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Handles `doflow capabilities` command execution.
|
|
@@ -26,7 +26,7 @@ const { finishRuntime: finish, usageError } = require('./cli-result.ts');
|
|
|
26
26
|
* @param {boolean} [options.check=false]
|
|
27
27
|
* @param {string} [options.repoRoot]
|
|
28
28
|
*/
|
|
29
|
-
function handleCapabilitiesCommand({ json = false, check = false, repoRoot }
|
|
29
|
+
function handleCapabilitiesCommand({ json = false, check = false, repoRoot } = {}) {
|
|
30
30
|
const root = repoRoot || REPO_ROOT;
|
|
31
31
|
const router = new CapabilityRouter({ repoRoot: root });
|
|
32
32
|
const report = router.getAllCapabilitiesHealth(check);
|
|
@@ -92,7 +92,7 @@ function handleCapabilitiesCommand({ json = false, check = false, repoRoot }: an
|
|
|
92
92
|
function handleReadinessCommand({
|
|
93
93
|
taskClass = 'feature', taskId = 'default', json = false, repoRoot, stateRoot,
|
|
94
94
|
verificationPlan, scopeClear, invariants, userDecisionPending = false, mode = 'workflow', now, slug = null,
|
|
95
|
-
}
|
|
95
|
+
} = {}) {
|
|
96
96
|
// Two different roots, previously conflated into one. `root` locates the *registry* (the
|
|
97
97
|
// readiness templates ship inside the DoFlow package). `state` locates the invoking project's
|
|
98
98
|
// evidence, which belongs to the caller's repo — not to wherever DoFlow happens to be installed.
|
|
@@ -102,7 +102,7 @@ function handleReadinessCommand({
|
|
|
102
102
|
const state = stateRoot || process.cwd();
|
|
103
103
|
// Only what the caller actually told us. An absent key must stay absent rather than become a
|
|
104
104
|
// falsy default, because the engine reads presence, not truth.
|
|
105
|
-
const profile
|
|
105
|
+
const profile = { taskId, taskClass };
|
|
106
106
|
if (typeof verificationPlan === 'string' && verificationPlan.trim() !== '') profile.verificationPlan = verificationPlan;
|
|
107
107
|
if (typeof scopeClear === 'string' && scopeClear.trim() !== '') profile.scopeClear = scopeClear;
|
|
108
108
|
if (typeof invariants === 'string' && invariants.trim() !== '') profile.invariants = invariants;
|
|
@@ -112,25 +112,25 @@ function handleReadinessCommand({
|
|
|
112
112
|
let report;
|
|
113
113
|
try {
|
|
114
114
|
report = evaluateTaskReadiness({ taskProfile: profile, repoRoot: root, projectRoot: state, mode });
|
|
115
|
-
} catch (error
|
|
115
|
+
} catch (error ) {
|
|
116
116
|
return usageError('readiness', error.message, json, error);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// The evaluation is recorded so the handoff, `verify` and the edit hook can later ask whether
|
|
120
120
|
// this task was READY before its work began. A scope that parses as a path list is also the
|
|
121
121
|
// declared scope `verify` bounds a change by; any other wording stays a statement only.
|
|
122
|
-
const inputs
|
|
122
|
+
const inputs = {};
|
|
123
123
|
if (profile.verificationPlan) inputs.verificationPlan = profile.verificationPlan;
|
|
124
124
|
if (profile.scopeClear) inputs.scope = profile.scopeClear;
|
|
125
125
|
if (profile.invariants) inputs.invariants = profile.invariants;
|
|
126
126
|
if (profile.userDecisionPending) inputs.userDecisionPending = true;
|
|
127
127
|
const declared = inputs.scope ? parseDeclaredScope(inputs.scope) : null;
|
|
128
128
|
const declaredScope = declared && !declared.reason ? declared.paths : null;
|
|
129
|
-
let recorded
|
|
129
|
+
let recorded ;
|
|
130
130
|
try {
|
|
131
131
|
const { file, replacedUnreadable } = writeReadinessRecord({ stateRoot: state, taskId, slug, report, inputs, declaredScope, mode, now: now || new Date() });
|
|
132
132
|
recorded = { file, written: true, ...(replacedUnreadable ? { replacedUnreadable } : {}) };
|
|
133
|
-
} catch (error
|
|
133
|
+
} catch (error ) {
|
|
134
134
|
recorded = { file: null, written: false, error: error.message };
|
|
135
135
|
}
|
|
136
136
|
const exitCode = recorded.written ? 0 : 1;
|
|
@@ -232,7 +232,7 @@ const EVIDENCE_SCORE_FIELDS = new Set([
|
|
|
232
232
|
]);
|
|
233
233
|
|
|
234
234
|
/** The one refusal message for a score offered as a property of a fact. */
|
|
235
|
-
function scoreFieldRefusal(name
|
|
235
|
+
function scoreFieldRefusal(name ) {
|
|
236
236
|
return `'${name}' is a retrieval score and this boundary records none (FR-007). Relevance is a `
|
|
237
237
|
+ 'property of a search, not of a fact: stored beside the fact it is read as confidence by the '
|
|
238
238
|
+ 'next worker, which is the specific interpretation the requirement forbids. Record the '
|
|
@@ -241,7 +241,7 @@ function scoreFieldRefusal(name: any) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
/** Refuses a score-shaped key anywhere in an item, including nested under source or locator. */
|
|
244
|
-
function assertNoScoreFields(value
|
|
244
|
+
function assertNoScoreFields(value , prefix ) {
|
|
245
245
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return;
|
|
246
246
|
for (const [key, inner] of Object.entries(value)) {
|
|
247
247
|
const dotted = prefix ? `${prefix}.${key}` : key;
|
|
@@ -255,7 +255,7 @@ function assertNoScoreFields(value: any, prefix: any) {
|
|
|
255
255
|
* @param {Object|string} raw
|
|
256
256
|
* @returns {Object}
|
|
257
257
|
*/
|
|
258
|
-
function parseLocator(raw
|
|
258
|
+
function parseLocator(raw ) {
|
|
259
259
|
if (typeof raw === 'string') {
|
|
260
260
|
const text = raw.trim();
|
|
261
261
|
if (text === '') throw new Error('locator is empty');
|
|
@@ -267,7 +267,7 @@ function parseLocator(raw: any) {
|
|
|
267
267
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
268
268
|
throw new Error("locator must be an object, or a 'path/to/file[:line]' or URI string");
|
|
269
269
|
}
|
|
270
|
-
const locator
|
|
270
|
+
const locator = {};
|
|
271
271
|
for (const [key, value] of Object.entries(raw)) {
|
|
272
272
|
if (!EVIDENCE_LOCATOR_FIELDS.includes(key)) {
|
|
273
273
|
throw new Error(`unknown locator field '${key}'. Accepted: ${EVIDENCE_LOCATOR_FIELDS.join(', ')}`);
|
|
@@ -298,7 +298,7 @@ function parseLocator(raw: any) {
|
|
|
298
298
|
* @param {string} [repoRoot] root a relative locator resolves against; defaults to cwd
|
|
299
299
|
* @returns {{kind:string, provenance:string, source:Object, locator:Object, content:(string|null)}}
|
|
300
300
|
*/
|
|
301
|
-
function validateEvidenceItem(raw
|
|
301
|
+
function validateEvidenceItem(raw , taskId , repoRoot ) {
|
|
302
302
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('an evidence item must be a JSON object');
|
|
303
303
|
assertNoScoreFields(raw, '');
|
|
304
304
|
|
|
@@ -381,7 +381,7 @@ function validateEvidenceItem(raw: any, taskId: any, repoRoot: any) {
|
|
|
381
381
|
// `blast_radius` at once by category alone (review R1).
|
|
382
382
|
let establishes = [];
|
|
383
383
|
if (raw.establishes !== undefined) {
|
|
384
|
-
const list = typeof raw.establishes === 'string' ? raw.establishes.split(',').map((s
|
|
384
|
+
const list = typeof raw.establishes === 'string' ? raw.establishes.split(',').map((s ) => s.trim()) : raw.establishes;
|
|
385
385
|
if (!Array.isArray(list) || list.length === 0 || list.some((r) => typeof r !== 'string' || r.trim() === '')) {
|
|
386
386
|
throw new Error("'establishes' must be a requirement id, a comma-separated list of them, or a non-empty array of non-empty strings");
|
|
387
387
|
}
|
|
@@ -436,7 +436,7 @@ function validateEvidenceItem(raw: any, taskId: any, repoRoot: any) {
|
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
/** HEAD of the tree the evidence was observed in, or null outside a repo. Measured, not asserted. */
|
|
439
|
-
function headCommit(root
|
|
439
|
+
function headCommit(root ) {
|
|
440
440
|
try {
|
|
441
441
|
return execFileSync('git', ['-C', root, 'rev-parse', 'HEAD'], {
|
|
442
442
|
encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'],
|
|
@@ -452,17 +452,17 @@ function headCommit(root: any) {
|
|
|
452
452
|
* @param {string} batchPath a file path, or `-` for stdin
|
|
453
453
|
* @returns {Array<Object>}
|
|
454
454
|
*/
|
|
455
|
-
function readEvidenceBatch(batchPath
|
|
455
|
+
function readEvidenceBatch(batchPath ) {
|
|
456
456
|
let text;
|
|
457
457
|
try {
|
|
458
458
|
text = batchPath === '-' ? fs.readFileSync(0, 'utf8') : fs.readFileSync(path.resolve(batchPath), 'utf8');
|
|
459
|
-
} catch (error
|
|
459
|
+
} catch (error ) {
|
|
460
460
|
throw new Error(`cannot read the batch at '${batchPath}': ${error.message}`);
|
|
461
461
|
}
|
|
462
462
|
let data;
|
|
463
463
|
try {
|
|
464
464
|
data = JSON.parse(text);
|
|
465
|
-
} catch (error
|
|
465
|
+
} catch (error ) {
|
|
466
466
|
throw new Error(`the batch at '${batchPath}' is not valid JSON: ${error.message}`);
|
|
467
467
|
}
|
|
468
468
|
if (Array.isArray(data)) return data;
|
|
@@ -483,7 +483,7 @@ function readEvidenceBatch(batchPath: any) {
|
|
|
483
483
|
* The `--action add` arm: validate the whole batch, then write it.
|
|
484
484
|
* @returns {number} exit code
|
|
485
485
|
*/
|
|
486
|
-
function addEvidence({ ledger, root, taskId, item, batchPath, json }
|
|
486
|
+
function addEvidence({ ledger, root, taskId, item, batchPath, json } ) {
|
|
487
487
|
const flagged = item && Object.keys(item).length > 0;
|
|
488
488
|
if (flagged && batchPath) {
|
|
489
489
|
return usageError('evidence', '--batch and the single-item flags are two spellings of the same write; use one', json);
|
|
@@ -496,7 +496,7 @@ function addEvidence({ ledger, root, taskId, item, batchPath, json }: any) {
|
|
|
496
496
|
let raws;
|
|
497
497
|
try {
|
|
498
498
|
raws = batchPath ? readEvidenceBatch(batchPath) : [item];
|
|
499
|
-
} catch (error
|
|
499
|
+
} catch (error ) {
|
|
500
500
|
return usageError('evidence', error.message, json, error);
|
|
501
501
|
}
|
|
502
502
|
if (raws.length === 0) {
|
|
@@ -510,7 +510,7 @@ function addEvidence({ ledger, root, taskId, item, batchPath, json }: any) {
|
|
|
510
510
|
for (const [index, raw] of raws.entries()) {
|
|
511
511
|
try {
|
|
512
512
|
validated.push(validateEvidenceItem(raw, taskId, root));
|
|
513
|
-
} catch (error
|
|
513
|
+
} catch (error ) {
|
|
514
514
|
const where = raws.length > 1 ? `batch item ${index + 1} of ${raws.length}: ` : '';
|
|
515
515
|
return usageError('evidence', `${where}${error.message}`, json, error);
|
|
516
516
|
}
|
|
@@ -529,7 +529,7 @@ function addEvidence({ ledger, root, taskId, item, batchPath, json }: any) {
|
|
|
529
529
|
written.push(ledger.getEvidence(id));
|
|
530
530
|
}
|
|
531
531
|
stateFile = ledger.save(taskId);
|
|
532
|
-
} catch (error
|
|
532
|
+
} catch (error ) {
|
|
533
533
|
return usageError('evidence', error.message, json, error);
|
|
534
534
|
}
|
|
535
535
|
|
|
@@ -558,7 +558,7 @@ function addEvidence({ ledger, root, taskId, item, batchPath, json }: any) {
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
/** One-line rendering of a locator for the table views. */
|
|
561
|
-
function locatorText(locator
|
|
561
|
+
function locatorText(locator ) {
|
|
562
562
|
if (!locator) return '';
|
|
563
563
|
if (locator.file) return locator.line ? `${locator.file}:${locator.line}` : locator.file;
|
|
564
564
|
return locator.uri || locator.symbol || '';
|
|
@@ -569,14 +569,14 @@ function locatorText(locator: any) {
|
|
|
569
569
|
* `handleClaimCommand`'s `supersede` branch — validate, write, save, report the same shape.
|
|
570
570
|
* @returns {number} exit code
|
|
571
571
|
*/
|
|
572
|
-
function supersedeEvidence({ ledger, taskId, evidenceId, replacedBy, json }
|
|
572
|
+
function supersedeEvidence({ ledger, taskId, evidenceId, replacedBy, json } ) {
|
|
573
573
|
if (!evidenceId || !replacedBy) {
|
|
574
574
|
return usageError('evidence', '--evidence-id and --replaced-by are both required for --action supersede', json);
|
|
575
575
|
}
|
|
576
576
|
let status;
|
|
577
577
|
try {
|
|
578
578
|
status = ledger.supersedeEvidence(evidenceId, replacedBy);
|
|
579
|
-
} catch (error
|
|
579
|
+
} catch (error ) {
|
|
580
580
|
return usageError('evidence', error.message, json, error);
|
|
581
581
|
}
|
|
582
582
|
const stateFile = ledger.save(taskId);
|
|
@@ -610,7 +610,7 @@ function supersedeEvidence({ ledger, taskId, evidenceId, replacedBy, json }: any
|
|
|
610
610
|
* @param {string} [options.stateRoot]
|
|
611
611
|
* @returns {number} exit code
|
|
612
612
|
*/
|
|
613
|
-
function handleEvidenceCommand({ taskId = 'default', action = 'list', item = null, batchPath = null, evidenceId = null, replacedBy = null, json = false, repoRoot, stateRoot }
|
|
613
|
+
function handleEvidenceCommand({ taskId = 'default', action = 'list', item = null, batchPath = null, evidenceId = null, replacedBy = null, json = false, repoRoot, stateRoot } = {}) {
|
|
614
614
|
// See handleReadinessCommand: evidence is the caller's project state, not DoFlow package state.
|
|
615
615
|
const root = stateRoot || repoRoot || process.cwd();
|
|
616
616
|
const isQuery = action === 'list' || action === 'status';
|
|
@@ -626,7 +626,7 @@ function handleEvidenceCommand({ taskId = 'default', action = 'list', item = nul
|
|
|
626
626
|
const ledger = new EvidenceLedger({ repoRoot: root });
|
|
627
627
|
try {
|
|
628
628
|
ledger.load(taskId);
|
|
629
|
-
} catch (error
|
|
629
|
+
} catch (error ) {
|
|
630
630
|
return usageError('evidence', error.message, json, error);
|
|
631
631
|
}
|
|
632
632
|
|