@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.
Files changed (167) hide show
  1. package/bin/doflow.js +2 -2
  2. package/core/.claude-plugin/plugin.json +1 -1
  3. package/core/.codex-plugin/plugin.json +1 -1
  4. package/core/.plugin/plugin.json +1 -1
  5. package/core/registry/storage.json +87 -83
  6. package/core/registry/verification.json +1 -1
  7. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
  8. package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
  9. package/package.json +4 -2
  10. package/src/adapters/antigravity/{index.ts → index.js} +60 -60
  11. package/src/adapters/claude/{index.ts → index.js} +48 -48
  12. package/src/adapters/claude/{mcp.ts → mcp.js} +16 -16
  13. package/src/adapters/codex/{agents.ts → agents.js} +24 -24
  14. package/src/adapters/codex/{config.ts → config.js} +49 -49
  15. package/src/adapters/codex/{hooks.ts → hooks.js} +23 -23
  16. package/src/adapters/codex/{index.ts → index.js} +98 -98
  17. package/src/adapters/codex/{mcp.ts → mcp.js} +38 -38
  18. package/src/adapters/codex/{native-projection.ts → native-projection.js} +5 -5
  19. package/src/adapters/copilot/{index.ts → index.js} +42 -42
  20. package/src/adapters/{copy-tree.ts → copy-tree.js} +70 -70
  21. package/src/adapters/gemini/{hooks.ts → hooks.js} +24 -24
  22. package/src/adapters/gemini/{index.ts → index.js} +41 -41
  23. package/src/adapters/{hook-commands.ts → hook-commands.js} +8 -8
  24. package/src/adapters/{index.ts → index.js} +13 -13
  25. package/src/adapters/kiro/{index.ts → index.js} +34 -34
  26. package/src/adapters/{mcp-entries.ts → mcp-entries.js} +55 -55
  27. package/src/adapters/opencode/{index.ts → index.js} +52 -52
  28. package/src/adapters/pi/{index.ts → index.js} +30 -30
  29. package/src/adapters/pi/{json-members.ts → json-members.js} +23 -23
  30. package/src/adapters/pi/{mcp.ts → mcp.js} +70 -70
  31. package/src/adapters/{resolve-source.ts → resolve-source.js} +1 -1
  32. package/src/cli/commands/{install.ts → install.js} +24 -24
  33. package/src/cli/commands/{list-backups.ts → list-backups.js} +4 -4
  34. package/src/cli/commands/{reconcile.ts → reconcile.js} +19 -19
  35. package/src/cli/commands/{remove.ts → remove.js} +10 -10
  36. package/src/cli/commands/{rollback.ts → rollback.js} +17 -17
  37. package/src/cli/commands/{self-update.ts → self-update.js} +3 -3
  38. package/src/cli/commands/{status.ts → status.js} +24 -24
  39. package/src/cli/commands/{tools.ts → tools.js} +16 -16
  40. package/src/cli/commands/{update.ts → update.js} +19 -19
  41. package/src/cli/{index.ts → index.js} +26 -26
  42. package/src/cli/{runtime-commands.ts → runtime-commands.js} +48 -48
  43. package/src/cli/{shared.ts → shared.js} +40 -40
  44. package/src/helper/{bash-helper.ts → bash-helper.js} +7 -7
  45. package/src/helper/{git.ts → git.js} +2 -2
  46. package/src/helper/{guardrails.ts → guardrails.js} +10 -10
  47. package/src/helper/{harness-paths.ts → harness-paths.js} +24 -24
  48. package/src/helper/{marker-merge.ts → marker-merge.js} +4 -4
  49. package/src/helper/{prompt.ts → prompt.js} +5 -5
  50. package/src/helper/{repo-root.ts → repo-root.js} +2 -2
  51. package/src/helper/{settings-merge.ts → settings-merge.js} +27 -27
  52. package/src/helper/{settings-scope.ts → settings-scope.js} +3 -3
  53. package/src/helper/{toml.ts → toml.js} +48 -48
  54. package/src/install/{backup-set.ts → backup-set.js} +16 -16
  55. package/src/install/{backup.ts → backup.js} +65 -65
  56. package/src/install/{context.ts → context.js} +15 -15
  57. package/src/install/{manifest.ts → manifest.js} +27 -27
  58. package/src/install/{mcp.ts → mcp.js} +30 -30
  59. package/src/install/{paths.ts → paths.js} +15 -15
  60. package/src/install/{targets.ts → targets.js} +10 -10
  61. package/src/install/{tool-lifecycle.ts → tool-lifecycle.js} +20 -20
  62. package/src/lifecycle/{bash-availability.ts → bash-availability.js} +1 -1
  63. package/src/lifecycle/{index.ts → index.js} +140 -140
  64. package/src/lifecycle/{mcp-index.ts → mcp-index.js} +1 -1
  65. package/src/lifecycle/{policies.ts → policies.js} +11 -11
  66. package/src/lifecycle/{view.ts → view.js} +28 -28
  67. package/src/registry/{index.ts → index.js} +60 -60
  68. package/src/release/build-package.js +91 -0
  69. package/src/release/changelog-section.js +70 -0
  70. package/src/release/{sync-plugin-versions.ts → sync-plugin-versions.js} +4 -4
  71. package/src/runtime/advice/{cli.ts → cli.js} +31 -31
  72. package/src/runtime/advice/{client.ts → client.js} +44 -44
  73. package/src/runtime/advice/{config.ts → config.js} +16 -16
  74. package/src/runtime/advice/{doctor.ts → doctor.js} +32 -32
  75. package/src/runtime/advice/{endpoint-guard.ts → endpoint-guard.js} +20 -20
  76. package/src/runtime/advice/{kinds.ts → kinds.js} +16 -16
  77. package/src/runtime/advice/providers/{ollama-systemone.ts → ollama-systemone.js} +21 -21
  78. package/src/runtime/advice/{record.ts → record.js} +19 -19
  79. package/src/runtime/advice/{registry.ts → registry.js} +16 -16
  80. package/src/runtime/advice/{strength.ts → strength.js} +7 -7
  81. package/src/runtime/{brief-tools.ts → brief-tools.js} +50 -50
  82. package/src/runtime/{c4-project.ts → c4-project.js} +27 -27
  83. package/src/runtime/{capability-router.ts → capability-router.js} +39 -39
  84. package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
  85. package/src/runtime/{claims.ts → claims.js} +30 -30
  86. package/src/runtime/{cli-result.ts → cli-result.js} +4 -4
  87. package/src/runtime/{cli.ts → cli.js} +37 -37
  88. package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
  89. package/src/runtime/{context-pack.ts → context-pack.js} +20 -20
  90. package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
  91. package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +25 -25
  92. package/src/runtime/failure/{capture.ts → capture.js} +29 -29
  93. package/src/runtime/failure/{classifier.ts → classifier.js} +4 -4
  94. package/src/runtime/failure/{cli.ts → cli.js} +30 -30
  95. package/src/runtime/failure/{home.ts → home.js} +6 -6
  96. package/src/runtime/failure/{store.ts → store.js} +32 -32
  97. package/src/runtime/{feature-resolve.ts → feature-resolve.js} +6 -6
  98. package/src/runtime/{freshness.ts → freshness.js} +15 -15
  99. package/src/runtime/{health.ts → health.js} +72 -72
  100. package/src/runtime/{history-compactor.ts → history-compactor.js} +25 -25
  101. package/src/runtime/{implementation-gate.ts → implementation-gate.js} +30 -30
  102. package/src/runtime/inventory/{coverage.ts → coverage.js} +10 -10
  103. package/src/runtime/inventory/{identity.ts → identity.js} +2 -2
  104. package/src/runtime/inventory/{index.ts → index.js} +36 -36
  105. package/src/runtime/inventory/{precedence.ts → precedence.js} +2 -2
  106. package/src/runtime/inventory/{read-scopes.ts → read-scopes.js} +9 -9
  107. package/src/runtime/inventory/{siblings.ts → siblings.js} +15 -15
  108. package/src/runtime/knowledge/{chunker.ts → chunker.js} +12 -12
  109. package/src/runtime/knowledge/{hybrid.ts → hybrid.js} +17 -17
  110. package/src/runtime/knowledge/{index-store.ts → index-store.js} +23 -23
  111. package/src/runtime/knowledge/{retrieval.ts → retrieval.js} +27 -27
  112. package/src/runtime/{leak-scan.ts → leak-scan.js} +12 -12
  113. package/src/runtime/lifecycle/{cli.ts → cli.js} +32 -32
  114. package/src/runtime/lifecycle/{event-store.ts → event-store.js} +48 -48
  115. package/src/runtime/lifecycle/{fold.ts → fold.js} +41 -41
  116. package/src/runtime/lifecycle/{followup.ts → followup.js} +54 -54
  117. package/src/runtime/lifecycle/{goal.ts → goal.js} +50 -50
  118. package/src/runtime/lifecycle/{intent-writer.ts → intent-writer.js} +5 -5
  119. package/src/runtime/lifecycle/{overview.ts → overview.js} +47 -47
  120. package/src/runtime/lifecycle/{release.ts → release.js} +29 -29
  121. package/src/runtime/lifecycle/{report-store.ts → report-store.js} +25 -25
  122. package/src/runtime/lifecycle/{retention.ts → retention.js} +37 -37
  123. package/src/runtime/lifecycle/{root.ts → root.js} +9 -9
  124. package/src/runtime/lifecycle/{status.ts → status.js} +64 -64
  125. package/src/runtime/lifecycle/{store-upkeep.ts → store-upkeep.js} +46 -46
  126. package/src/runtime/{locator-resolve.ts → locator-resolve.js} +7 -7
  127. package/src/runtime/{mask.ts → mask.js} +22 -22
  128. package/src/runtime/{mcp-consultations.ts → mcp-consultations.js} +54 -54
  129. package/src/runtime/{mcp-reach.ts → mcp-reach.js} +24 -24
  130. package/src/runtime/{model-router.ts → model-router.js} +20 -20
  131. package/src/runtime/{outcome.ts → outcome.js} +27 -27
  132. package/src/runtime/{reach.ts → reach.js} +21 -21
  133. package/src/runtime/{readiness-record.ts → readiness-record.js} +12 -12
  134. package/src/runtime/{readiness.ts → readiness.js} +35 -35
  135. package/src/runtime/{recovery.ts → recovery.js} +15 -15
  136. package/src/runtime/{research-request.ts → research-request.js} +34 -34
  137. package/src/runtime/{retrieval-plan.ts → retrieval-plan.js} +40 -40
  138. package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +19 -19
  139. package/src/runtime/scaffold/{fingerprint.ts → fingerprint.js} +3 -3
  140. package/src/runtime/scaffold/{generate.ts → generate.js} +109 -109
  141. package/src/runtime/scaffold/{languages.ts → languages.js} +34 -34
  142. package/src/runtime/storage/{cli.ts → cli.js} +9 -9
  143. package/src/runtime/storage/{engine.ts → engine.js} +37 -37
  144. package/src/runtime/storage/{registry.ts → registry.js} +19 -19
  145. package/src/runtime/storage/{roots.ts → roots.js} +8 -8
  146. package/src/runtime/storage/{rules.ts → rules.js} +26 -26
  147. package/src/runtime/storage/{upkeep.ts → upkeep.js} +35 -35
  148. package/src/runtime/storage/{work-status.ts → work-status.js} +39 -39
  149. package/src/runtime/{task-attempts.ts → task-attempts.js} +61 -61
  150. package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
  151. package/src/runtime/{task-scope.ts → task-scope.js} +13 -13
  152. package/src/runtime/{task-state.ts → task-state.js} +15 -15
  153. package/src/runtime/trace/{indicators.ts → indicators.js} +22 -22
  154. package/src/runtime/trace/{ledger.ts → ledger.js} +42 -42
  155. package/src/runtime/trace/{render.ts → render.js} +7 -7
  156. package/src/runtime/trace/{views.ts → views.js} +40 -40
  157. package/src/runtime/verification/{contract-runner.ts → contract-runner.js} +23 -23
  158. package/src/runtime/verification/{engine.ts → engine.js} +143 -143
  159. package/src/runtime/verification/{registry.ts → registry.js} +6 -6
  160. package/src/runtime/verification/{scope-bound.ts → scope-bound.js} +50 -50
  161. package/src/runtime/verification/{test-selection.ts → test-selection.js} +28 -28
  162. package/src/runtime/{workflow-engine.ts → workflow-engine.js} +50 -50
  163. package/src/runtime/{workflow-orchestrator.ts → workflow-orchestrator.js} +91 -91
  164. package/src/runtime/{worktree.ts → worktree.js} +31 -31
  165. package/src/state/{index.ts → index.js} +26 -26
  166. package/src/state/{lockfile.ts → lockfile.js} +20 -20
  167. 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
  const { execFileSync } = require('node:child_process');
9
- const { REPO_ROOT } = require('../helper/repo-root.ts');
9
+ const { REPO_ROOT } = require('../helper/repo-root.js');
10
10
 
11
11
  // Freshness is measured against the bytes observed, not whether the file was clean at HEAD.
12
12
  // Git identity remains provenance and a conservative fallback for older records without hashes.
13
- function fileHash(root: string, locator: any): string | null {
13
+ function fileHash(root , locator ) {
14
14
  if (!locator?.file) return null;
15
15
  try {
16
16
  const absolute = path.resolve(root, locator.file);
@@ -19,26 +19,26 @@ function fileHash(root: string, locator: any): string | null {
19
19
  } catch { return null; }
20
20
  }
21
21
 
22
- function measureFreshness(root: string, locator: any, gitCommit: any): any {
22
+ function measureFreshness(root , locator , gitCommit ) {
23
23
  return { gitCommit, fileHash: fileHash(root, locator), observedAt: new Date().toISOString(), status: 'FRESH' };
24
24
  }
25
25
 
26
26
  class FreshnessValidator {
27
- repoRoot: string;
28
- gitRunner: (args: string[], cwd?: string) => string | null;
29
- declare diffCache?: Map<string, Set<string>>;
27
+ repoRoot ;
28
+ gitRunner ;
29
+
30
30
 
31
31
  /**
32
32
  * @param {Object} [options]
33
33
  * @param {string} [options.repoRoot]
34
34
  * @param {Function} [options.gitRunner]
35
35
  */
36
- constructor(options: any = {}) {
36
+ constructor(options = {}) {
37
37
  this.repoRoot = options.repoRoot || REPO_ROOT;
38
38
  this.gitRunner = options.gitRunner || this.defaultGitRunner.bind(this);
39
39
  }
40
40
 
41
- defaultGitRunner(args: string[], cwd: string = this.repoRoot): string | null {
41
+ defaultGitRunner(args , cwd = this.repoRoot) {
42
42
  try {
43
43
  return execFileSync('git', args, {
44
44
  cwd,
@@ -55,7 +55,7 @@ class FreshnessValidator {
55
55
  * Retrieves the current HEAD commit hash.
56
56
  * @returns {string|null}
57
57
  */
58
- getCurrentHead(): string | null {
58
+ getCurrentHead() {
59
59
  return this.gitRunner(['rev-parse', 'HEAD']);
60
60
  }
61
61
 
@@ -63,11 +63,11 @@ class FreshnessValidator {
63
63
  * Retrieves all modified/unstaged/staged files in the repository.
64
64
  * @returns {Set<string>}
65
65
  */
66
- getDirtyFiles(): Set<string> {
66
+ getDirtyFiles() {
67
67
  const output = this.gitRunner(['status', '--porcelain']);
68
68
  if (!output) return new Set();
69
69
 
70
- const dirty = new Set<string>();
70
+ const dirty = new Set ();
71
71
  const lines = output.split('\n');
72
72
  for (const line of lines) {
73
73
  if (line.length > 3) {
@@ -83,14 +83,14 @@ class FreshnessValidator {
83
83
  * @param {string} [refCommit]
84
84
  * @returns {Set<string>}
85
85
  */
86
- getModifiedFilesSince(refCommit?: string): Set<string> {
86
+ getModifiedFilesSince(refCommit ) {
87
87
  // `checkEvidenceFreshness` calls this once per evidence item, and a batch of evidence shares
88
88
  // one recorded commit — so without a memo a task with ninety items ran ninety `git diff`s to
89
89
  // answer the same question. Keyed on the commit because that is the axis the work collapses
90
90
  // on. Instance-scoped, so it lives exactly as long as one invocation.
91
91
  if (!this.diffCache) this.diffCache = new Map();
92
92
  const key = refCommit || '';
93
- if (this.diffCache.has(key)) return this.diffCache.get(key) as Set<string>;
93
+ if (this.diffCache.has(key)) return this.diffCache.get(key) ;
94
94
 
95
95
  const dirty = this.getDirtyFiles();
96
96
  if (!refCommit) {
@@ -113,7 +113,7 @@ class FreshnessValidator {
113
113
  * @param {Object} item - Evidence item
114
114
  * @returns {{ status: 'FRESH'|'STALE', reason?: string }}
115
115
  */
116
- checkEvidenceFreshness(item: any): { status: 'FRESH' | 'STALE'; reason?: string } {
116
+ checkEvidenceFreshness(item ) {
117
117
  if (!item) return { status: 'STALE', reason: 'Evidence item is missing' };
118
118
 
119
119
  // If explicitly marked stale
@@ -152,7 +152,7 @@ class FreshnessValidator {
152
152
  * @param {Object} ledger - EvidenceLedger instance
153
153
  * @returns {number} count of newly invalidated items
154
154
  */
155
- validateLedgerFreshness(ledger: any): number {
155
+ validateLedgerFreshness(ledger ) {
156
156
  if (!ledger || typeof ledger.getAllEvidence !== 'function') return 0;
157
157
 
158
158
  let count = 0;
@@ -21,12 +21,12 @@ const fs = require('node:fs');
21
21
  const os = require('node:os');
22
22
  const path = require('node:path');
23
23
  const { execFileSync } = require('node:child_process');
24
- const { CapabilityRouter } = require('./capability-router.ts');
25
- const { loadRegistry } = require('../registry/index.ts');
26
- const { evaluateReach } = require('./reach.ts');
27
- const { mcpReach } = require('./mcp-reach.ts');
28
- const { OUTCOME_LABELS } = require('./mcp-consultations.ts');
29
- const { REPO_ROOT } = require('../helper/repo-root.ts');
24
+ const { CapabilityRouter } = require('./capability-router.js');
25
+ const { loadRegistry } = require('../registry/index.js');
26
+ const { evaluateReach } = require('./reach.js');
27
+ const { mcpReach } = require('./mcp-reach.js');
28
+ const { OUTCOME_LABELS } = require('./mcp-consultations.js');
29
+ const { REPO_ROOT } = require('../helper/repo-root.js');
30
30
 
31
31
  /** Answered a probe. */
32
32
  const HEALTHY = 'HEALTHY';
@@ -49,15 +49,15 @@ const BANNER_MAX = 80;
49
49
  * them exists the result is UNKNOWN naming the paths searched, because a provider that owns its
50
50
  * own cache layout must not have a freshness verdict invented for it.
51
51
  */
52
- const PROVIDER_ARTIFACTS: Record<string, any> = Object.freeze({
52
+ const PROVIDER_ARTIFACTS = Object.freeze({
53
53
  'graphify.query': {
54
54
  label: 'code graph',
55
- candidates: (root: any) => [path.join(root, 'graphify-out', 'graph.json')],
55
+ candidates: (root ) => [path.join(root, 'graphify-out', 'graph.json')],
56
56
  refresh: 'graphify update .',
57
57
  },
58
58
  'semble.search': {
59
59
  label: 'semantic index',
60
- candidates: (root: any, home: any) => [
60
+ candidates: (root , home ) => [
61
61
  path.join(root, '.semble', 'index.json'),
62
62
  path.join(root, '.semble'),
63
63
  path.join(home, '.cache', 'semble', 'index'),
@@ -84,7 +84,7 @@ const SCAN_FILE_LIMIT = 4000;
84
84
  * @param {number} [options.timeoutMs=PROBE_TIMEOUT_MS]
85
85
  * @returns {{ok: boolean, output: string, durationMs: number, timedOut: boolean, error: string|null}}
86
86
  */
87
- function runProbe(command: any, { execFileImpl = execFileSync, timeoutMs = PROBE_TIMEOUT_MS }: any = {}) {
87
+ function runProbe(command , { execFileImpl = execFileSync, timeoutMs = PROBE_TIMEOUT_MS } = {}) {
88
88
  const [bin, ...args] = command;
89
89
  const started = Number(process.hrtime.bigint() / 1000000n);
90
90
  try {
@@ -100,7 +100,7 @@ function runProbe(command: any, { execFileImpl = execFileSync, timeoutMs = PROBE
100
100
  timedOut: false,
101
101
  error: null,
102
102
  };
103
- } catch (error: any) {
103
+ } catch (error ) {
104
104
  // A killed process and a non-zero exit are both "did not answer", but they are different
105
105
  // repairs — a timeout usually means a first-run index build, a non-zero exit usually means a
106
106
  // broken install — so they are reported apart rather than as one failure string.
@@ -117,7 +117,7 @@ function runProbe(command: any, { execFileImpl = execFileSync, timeoutMs = PROBE
117
117
 
118
118
  /** First line of probe output, trimmed to a banner. Control characters are stripped so a provider
119
119
  * cannot rewrite the doctor report with an escape sequence. */
120
- function banner(output: any) {
120
+ function banner(output ) {
121
121
  if (!output) return null;
122
122
  // Control characters are removed by code point rather than by a literal class, so this source
123
123
  // file stays free of the escape sequences it is defending against.
@@ -137,7 +137,7 @@ function banner(output: any) {
137
137
  * @param {number} [options.limit=SCAN_FILE_LIMIT]
138
138
  * @returns {{mtimeMs: number|null, filesScanned: number, truncated: boolean}}
139
139
  */
140
- function newestSourceMtime(root: any, { fsImpl = fs, limit = SCAN_FILE_LIMIT }: any = {}) {
140
+ function newestSourceMtime(root , { fsImpl = fs, limit = SCAN_FILE_LIMIT } = {}) {
141
141
  let mtimeMs = null;
142
142
  let filesScanned = 0;
143
143
  let truncated = false;
@@ -180,7 +180,7 @@ function newestSourceMtime(root: any, { fsImpl = fs, limit = SCAN_FILE_LIMIT }:
180
180
  * @param {Object} [options.fsImpl=fs]
181
181
  * @returns {Object|null} null when the provider is not index-backed
182
182
  */
183
- function probeFreshness(providerId: any, { root = process.cwd(), homeDir = os.homedir(), fsImpl = fs }: any = {}) {
183
+ function probeFreshness(providerId , { root = process.cwd(), homeDir = os.homedir(), fsImpl = fs } = {}) {
184
184
  const spec = PROVIDER_ARTIFACTS[providerId];
185
185
  if (!spec) return null;
186
186
 
@@ -253,11 +253,11 @@ function probeFreshness(providerId: any, { root = process.cwd(), homeDir = os.ho
253
253
  * @param {Object} [options.fsImpl]
254
254
  * @returns {Object} probe result
255
255
  */
256
- function probeProvider(provider: any, { router, projectRoot = process.cwd(), execFileImpl, fsImpl = fs }: any = {}) {
256
+ function probeProvider(provider , { router, projectRoot = process.cwd(), execFileImpl, fsImpl = fs } = {}) {
257
257
  if (!provider || !provider.id) {
258
258
  return { id: null, status: UNVERIFIED, detail: 'no provider declared' };
259
259
  }
260
- const result: any = {
260
+ const result = {
261
261
  id: provider.id,
262
262
  name: provider.name || provider.id,
263
263
  binary: provider.binary || null,
@@ -326,11 +326,11 @@ function probeProvider(provider: any, { router, projectRoot = process.cwd(), exe
326
326
  * @param {CapabilityRouter} [options.router]
327
327
  * @returns {Object} map of provider id -> probe result
328
328
  */
329
- function probeProviders({ repoRoot, projectRoot = process.cwd(), ids = null, router, execFileImpl, fsImpl = fs }: any = {}) {
329
+ function probeProviders({ repoRoot, projectRoot = process.cwd(), ids = null, router, execFileImpl, fsImpl = fs } = {}) {
330
330
  const activeRouter = router || new CapabilityRouter({ repoRoot: repoRoot || REPO_ROOT, projectRoot });
331
331
  const wanted = ids ? new Set(ids) : null;
332
- const results: Record<string, any> = {};
333
- for (const capability of Object.values<any>(activeRouter.capabilities || {})) {
332
+ const results = {};
333
+ for (const capability of Object.values (activeRouter.capabilities || {})) {
334
334
  for (const provider of capability.providers || []) {
335
335
  if (!provider || !provider.id) continue;
336
336
  if (wanted && !wanted.has(provider.id)) continue;
@@ -355,18 +355,18 @@ function probeProviders({ repoRoot, projectRoot = process.cwd(), ids = null, rou
355
355
  * @param {Function} [options.detector] injection seam; defaults to the C.2 module when present
356
356
  * @returns {{status: string, build: Object|null, test: Object|null, reason?: string}}
357
357
  */
358
- function detectProjectCommands({ projectRoot = process.cwd(), detector }: any = {}) {
358
+ function detectProjectCommands({ projectRoot = process.cwd(), detector } = {}) {
359
359
  let detect = detector;
360
360
  if (!detect) {
361
361
  let mod = null;
362
362
  try {
363
- mod = require('./command-detect.ts');
363
+ mod = require('./command-detect.js');
364
364
  } catch {
365
365
  return {
366
366
  status: 'UNKNOWN',
367
367
  build: null,
368
368
  test: null,
369
- reason: 'src/runtime/command-detect.ts is not present in this build; DoFlow reports detected commands but does not detect them itself, and will not guess',
369
+ reason: 'src/runtime/command-detect.js is not present in this build; DoFlow reports detected commands but does not detect them itself, and will not guess',
370
370
  };
371
371
  }
372
372
  detect = typeof mod.detectCommands === 'function' ? mod.detectCommands : null;
@@ -375,7 +375,7 @@ function detectProjectCommands({ projectRoot = process.cwd(), detector }: any =
375
375
  status: 'UNKNOWN',
376
376
  build: null,
377
377
  test: null,
378
- reason: `src/runtime/command-detect.ts exports no detectCommands() (found: ${Object.keys(mod).join(', ') || 'nothing'})`,
378
+ reason: `src/runtime/command-detect.js exports no detectCommands() (found: ${Object.keys(mod).join(', ') || 'nothing'})`,
379
379
  };
380
380
  }
381
381
  }
@@ -383,7 +383,7 @@ function detectProjectCommands({ projectRoot = process.cwd(), detector }: any =
383
383
  let detected;
384
384
  try {
385
385
  detected = detect({ projectRoot }) || {};
386
- } catch (error: any) {
386
+ } catch (error ) {
387
387
  return { status: 'UNKNOWN', build: null, test: null, reason: `command detection failed: ${error.message}` };
388
388
  }
389
389
 
@@ -414,15 +414,15 @@ function detectProjectCommands({ projectRoot = process.cwd(), detector }: any =
414
414
  }
415
415
 
416
416
  /** Roll a capability's provider probes up into one status. */
417
- function capabilityStatus(probes: any) {
417
+ function capabilityStatus(probes ) {
418
418
  if (!probes.length) return { status: 'UNAVAILABLE', activeProvider: null };
419
- const firstHealthy = probes.findIndex((probe: any) => probe.status === HEALTHY);
419
+ const firstHealthy = probes.findIndex((probe ) => probe.status === HEALTHY);
420
420
  if (firstHealthy === 0) return { status: HEALTHY, activeProvider: probes[0].id };
421
421
  if (firstHealthy > 0) return { status: 'FALLBACK', activeProvider: probes[firstHealthy].id };
422
422
  // Nothing answered. "Installed but broken" and "not installed" are different problems: the first
423
423
  // is actionable now, the second is the graceful degradation NFR-002 requires.
424
- if (probes.some((probe: any) => probe.status === UNHEALTHY)) return { status: 'DEGRADED', activeProvider: null };
425
- if (probes.every((probe: any) => probe.status === ABSENT)) return { status: 'UNAVAILABLE', activeProvider: null };
424
+ if (probes.some((probe ) => probe.status === UNHEALTHY)) return { status: 'DEGRADED', activeProvider: null };
425
+ if (probes.every((probe ) => probe.status === ABSENT)) return { status: 'UNAVAILABLE', activeProvider: null };
426
426
  return { status: UNVERIFIED, activeProvider: null };
427
427
  }
428
428
 
@@ -434,7 +434,7 @@ function capabilityStatus(probes: any) {
434
434
  * @returns {Object} report model
435
435
  */
436
436
  /** The installed DoFlow source's own version, read from its package.json; null when unreadable. */
437
- function installVersion(root: any, fsImpl = fs) {
437
+ function installVersion(root , fsImpl = fs) {
438
438
  try {
439
439
  return JSON.parse(fsImpl.readFileSync(path.join(root, 'package.json'), 'utf8')).version || null;
440
440
  } catch {
@@ -443,8 +443,8 @@ function installVersion(root: any, fsImpl = fs) {
443
443
  }
444
444
 
445
445
  /** The project's git identity — short commit and branch — or null outside a repository. */
446
- function projectGitIdentity(projectRoot: any) {
447
- const git = (args: any) => {
446
+ function projectGitIdentity(projectRoot ) {
447
+ const git = (args ) => {
448
448
  try {
449
449
  return execFileSync('git', ['-C', projectRoot, ...args], {
450
450
  encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'],
@@ -468,19 +468,19 @@ const NO_OUTCOME_SHOWN = 3;
468
468
  * it and the command that adds it where it is missing. Read-only; starts no server (NFR-001).
469
469
  * Server ids come from the registry, never from this file.
470
470
  */
471
- function mcpServersView({ registry, projectRoot, fsImpl, adapters }: any) {
472
- const named = registry.mcp.filter((server: any) => (server.steps || []).length);
471
+ function mcpServersView({ registry, projectRoot, fsImpl, adapters } ) {
472
+ const named = registry.mcp.filter((server ) => (server.steps || []).length);
473
473
  if (!named.length) return [];
474
474
  if (!adapters) throw new Error('no adapter registry was given');
475
475
  const reach = mcpReach({ registry, projectRoot, fsImpl, adapters });
476
- const unreadableFile = (harness: any) => reach.unreadable.find((item: any) => item.harness === harness.id && item.scope === harness.scope);
477
- return named.map((server: any) => ({
476
+ const unreadableFile = (harness ) => reach.unreadable.find((item ) => item.harness === harness.id && item.scope === harness.scope);
477
+ return named.map((server ) => ({
478
478
  id: server.id,
479
479
  selection: server.selection,
480
- namedBy: [...new Set(server.steps.map((step: any) => (step.expectedWhen === 'research-request' ? `${step.skill} (research request)` : step.skill)))],
481
- harnesses: reach.harnesses.map((harness: any) => {
480
+ namedBy: [...new Set(server.steps.map((step ) => (step.expectedWhen === 'research-request' ? `${step.skill} (research request)` : step.skill)))],
481
+ harnesses: reach.harnesses.map((harness ) => {
482
482
  const state = harness.servers[server.id];
483
- const row: any = { id: harness.id, scope: harness.scope, state };
483
+ const row = { id: harness.id, scope: harness.scope, state };
484
484
  const unreadable = state === 'unknown' ? unreadableFile(harness) : null;
485
485
  // An unreadable config is fixed before anything is added to it (IC-014).
486
486
  if (unreadable) row.fix = unreadable.file || `${harness.id}'s MCP config`;
@@ -490,7 +490,7 @@ function mcpServersView({ registry, projectRoot, fsImpl, adapters }: any) {
490
490
  }));
491
491
  }
492
492
 
493
- const byText = (a: any, b: any) => (a < b ? -1 : a > b ? 1 : 0);
493
+ const byText = (a , b ) => (a < b ? -1 : a > b ? 1 : 0);
494
494
 
495
495
  /**
496
496
  * The `[MCP Consultations]` data (IC-015): the recorded `consultations` of the project's run
@@ -498,10 +498,10 @@ const byText = (a: any, b: any) => (a < b ? -1 : a > b ? 1 : 0);
498
498
  * `at`, counted per server. An entry without `consultations` predates the feature and is never
499
499
  * counted (NFR-005); "no outcome" is `named` minus the servers with an outcome, never stored.
500
500
  */
501
- function mcpConsultationsView({ projectRoot, fsImpl }: any) {
501
+ function mcpConsultationsView({ projectRoot, fsImpl } ) {
502
502
  const dir = path.join(projectRoot, '.doflow', 'state', 'orchestration');
503
503
  let files = [];
504
- try { files = fsImpl.readdirSync(dir).filter((name: any) => name.endsWith('.json')).sort(); } catch { files = []; }
504
+ try { files = fsImpl.readdirSync(dir).filter((name ) => name.endsWith('.json')).sort(); } catch { files = []; }
505
505
  let unreadableRuns = 0;
506
506
  const bySkill = new Map();
507
507
  for (const name of files) {
@@ -517,14 +517,14 @@ function mcpConsultationsView({ projectRoot, fsImpl }: any) {
517
517
  }
518
518
  const stages = [...bySkill.keys()].sort(byText).map((skill) => {
519
519
  const kept = bySkill.get(skill)
520
- .sort((a: any, b: any) => byText(b.at, a.at) || byText(a.taskId, b.taskId) || byText(String(a.node), String(b.node)))
520
+ .sort((a , b ) => byText(b.at, a.at) || byText(a.taskId, b.taskId) || byText(String(a.node), String(b.node)))
521
521
  .slice(0, CONSULTATION_WINDOW);
522
522
  const counts = new Map();
523
- const row = (server: any) => {
523
+ const row = (server ) => {
524
524
  if (!counts.has(server)) counts.set(server, { server, used: 0, nothingUsable: 0, skipped: 0, unavailable: 0, noOutcome: 0 });
525
525
  return counts.get(server);
526
526
  };
527
- const key: Record<string, any> = { 'consulted-used': 'used', 'consulted-nothing-usable': 'nothingUsable', skipped: 'skipped', unavailable: 'unavailable' };
527
+ const key = { 'consulted-used': 'used', 'consulted-nothing-usable': 'nothingUsable', skipped: 'skipped', unavailable: 'unavailable' };
528
528
  const noOutcome = [];
529
529
  const shown = new Map();
530
530
  for (const { taskId, node, at, record } of kept) {
@@ -533,7 +533,7 @@ function mcpConsultationsView({ projectRoot, fsImpl }: any) {
533
533
  if (outcome && typeof outcome.server === 'string' && key[outcome.state]) outcomes.set(outcome.server, key[outcome.state]);
534
534
  }
535
535
  for (const [server, field] of outcomes) row(server)[field] += 1;
536
- for (const server of (Array.isArray(record.named) ? record.named : []).filter((id: any) => typeof id === 'string').sort(byText)) {
536
+ for (const server of (Array.isArray(record.named) ? record.named : []).filter((id ) => typeof id === 'string').sort(byText)) {
537
537
  if (outcomes.has(server)) continue;
538
538
  row(server).noOutcome += 1;
539
539
  // `kept` is newest first, so the first entries per server are its latest.
@@ -548,14 +548,14 @@ function mcpConsultationsView({ projectRoot, fsImpl }: any) {
548
548
 
549
549
  /** The doctor's `mcp` block. A servers view that cannot be built degrades to a one-line note; the
550
550
  * sections never enter findings or change the exit code (FR-011, FR-012). */
551
- function mcpView({ registry, projectRoot, fsImpl, adapters }: any) {
551
+ function mcpView({ registry, projectRoot, fsImpl, adapters } ) {
552
552
  let servers = [];
553
553
  let serversNote;
554
- try { servers = mcpServersView({ registry, projectRoot, fsImpl, adapters }); } catch (error: any) { serversNote = `MCP server view unavailable: ${error.message}`; }
554
+ try { servers = mcpServersView({ registry, projectRoot, fsImpl, adapters }); } catch (error ) { serversNote = `MCP server view unavailable: ${error.message}`; }
555
555
  return { servers, ...(serversNote ? { serversNote } : {}), consultations: mcpConsultationsView({ projectRoot, fsImpl }) };
556
556
  }
557
557
 
558
- const MCP_STATE_MARK: Record<string, any> = Object.freeze({
558
+ const MCP_STATE_MARK = Object.freeze({
559
559
  selected: '✓ selected',
560
560
  configured: '✓ configured',
561
561
  'not-selected': '○ not selected',
@@ -563,11 +563,11 @@ const MCP_STATE_MARK: Record<string, any> = Object.freeze({
563
563
  unknown: '? unknown',
564
564
  });
565
565
 
566
- function printMcpSections(mcp: any) {
566
+ function printMcpSections(mcp ) {
567
567
  console.log('\n[MCP Servers] — named by shipped stages; not blocking');
568
568
  if (mcp.serversNote) {
569
569
  console.log(` ${mcp.serversNote}`);
570
- } else if (!mcp.servers.some((server: any) => server.harnesses.length)) {
570
+ } else if (!mcp.servers.some((server ) => server.harnesses.length)) {
571
571
  console.log(' No harness has DoFlow ledger rows here, so no server selection to report.');
572
572
  } else {
573
573
  for (const server of mcp.servers) {
@@ -602,11 +602,11 @@ function printMcpSections(mcp: any) {
602
602
  if (unreadableRuns) console.log(` ${unreadableRuns} run file(s) could not be read`);
603
603
  }
604
604
 
605
- function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, execFileImpl, fsImpl = fs, detector, adapters }: any = {}) {
605
+ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, execFileImpl, fsImpl = fs, detector, adapters } = {}) {
606
606
  const root = repoRoot || REPO_ROOT;
607
607
  const registry = loadRegistry({ repoRoot: root });
608
608
  const activeRouter = router || new CapabilityRouter({ repoRoot: root, projectRoot });
609
- const probes: Record<string, any> = probeProviders({ repoRoot: root, projectRoot, router: activeRouter, execFileImpl, fsImpl });
609
+ const probes = probeProviders({ repoRoot: root, projectRoot, router: activeRouter, execFileImpl, fsImpl });
610
610
  const project = { root: path.resolve(projectRoot), commands: detectProjectCommands({ projectRoot, detector }) };
611
611
 
612
612
  // `native.test` is the one provider with neither a binary nor a probe: it stands for whatever the
@@ -621,8 +621,8 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
621
621
  : 'no probe of its own, and no project test command was detected — nothing establishes that this capability can answer';
622
622
  }
623
623
 
624
- const capabilities = Object.entries<any>(activeRouter.capabilities || {}).map(([id, capability]) => {
625
- const declared = (capability.providers || []).map((provider: any) => probes[provider.id]).filter(Boolean);
624
+ const capabilities = Object.entries (activeRouter.capabilities || {}).map(([id, capability]) => {
625
+ const declared = (capability.providers || []).map((provider ) => probes[provider.id]).filter(Boolean);
626
626
  const rolled = capabilityStatus(declared);
627
627
  return {
628
628
  capability: id,
@@ -630,14 +630,14 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
630
630
  status: rolled.status,
631
631
  activeProvider: rolled.activeProvider,
632
632
  totalProviders: declared.length,
633
- providers: declared.map((probe: any) => ({ id: probe.id, status: probe.status, detail: probe.detail })),
633
+ providers: declared.map((probe ) => ({ id: probe.id, status: probe.status, detail: probe.detail })),
634
634
  };
635
635
  });
636
636
 
637
637
  // External tools are the same binaries the providers use, so their status comes from the probe
638
638
  // that already ran rather than from a second, weaker presence check.
639
- const externalTools = registry.externalTools.map((tool: any) => {
640
- const probe: any = Object.values(probes).find((candidate) => candidate.binary === tool.id);
639
+ const externalTools = registry.externalTools.map((tool ) => {
640
+ const probe = Object.values(probes).find((candidate) => candidate.binary === tool.id);
641
641
  if (probe) return { id: tool.id, displayName: tool.displayName, status: probe.status, detail: probe.detail };
642
642
  const present = activeRouter.isBinaryAvailable(tool.id);
643
643
  return {
@@ -662,8 +662,8 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
662
662
  .filter((capability) => capability.status === 'DEGRADED')
663
663
  .map((capability) => ({ kind: 'capability-degraded', subject: capability.capability, detail: 'every installed provider for this capability failed its probe' })),
664
664
  ...reach.rows
665
- .filter((row: any) => row.state === 'NO-REACH')
666
- .map((row: any) => ({ kind: 'runtime-no-reach', subject: `${row.harness}:${row.scope}`, detail: `${row.reason}; fix: ${row.fix}` })),
665
+ .filter((row ) => row.state === 'NO-REACH')
666
+ .map((row ) => ({ kind: 'runtime-no-reach', subject: `${row.harness}:${row.scope}`, detail: `${row.reason}; fix: ${row.fix}` })),
667
667
  ];
668
668
  const warnings = [
669
669
  ...freshness
@@ -676,7 +676,7 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
676
676
  .filter((probe) => probe.status === UNVERIFIED)
677
677
  .map((probe) => ({ kind: 'provider-unverified', subject: probe.id, detail: probe.detail })),
678
678
  ...reach.unreadable
679
- .map((item: any) => ({ kind: 'reach-ledger-unreadable', subject: `${item.scope}: ${item.ledger}`, detail: item.detail })),
679
+ .map((item ) => ({ kind: 'reach-ledger-unreadable', subject: `${item.scope}: ${item.ledger}`, detail: item.detail })),
680
680
  ...(project.commands.status === 'DETECTED' ? [] : [{ kind: 'project-commands', subject: 'build/test', detail: project.commands.reason }]),
681
681
  ];
682
682
 
@@ -692,11 +692,11 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
692
692
 
693
693
  return {
694
694
  identity,
695
- harnesses: registry.harnesses.map((harness: any) => ({
695
+ harnesses: registry.harnesses.map((harness ) => ({
696
696
  id: harness.id,
697
697
  displayName: harness.displayName,
698
698
  status: 'PASS',
699
- reach: reach.rows.filter((row: any) => row.harness === harness.id).map(({ harness: _harness, ...row }: any) => row),
699
+ reach: reach.rows.filter((row ) => row.harness === harness.id).map(({ harness: _harness, ...row } ) => row),
700
700
  })),
701
701
  externalTools,
702
702
  capabilities,
@@ -728,12 +728,12 @@ function buildHealthReport({ repoRoot, projectRoot = process.cwd(), router, exec
728
728
  * @param {number} code
729
729
  * @returns {number}
730
730
  */
731
- function finish(code: any) {
731
+ function finish(code ) {
732
732
  process.exitCode = code;
733
733
  return code;
734
734
  }
735
735
 
736
- const STATUS_MARK: Record<string, any> = Object.freeze({
736
+ const STATUS_MARK = Object.freeze({
737
737
  HEALTHY: '✓ HEALTHY',
738
738
  UNHEALTHY: '✗ UNHEALTHY',
739
739
  ABSENT: '○ ABSENT',
@@ -743,13 +743,13 @@ const STATUS_MARK: Record<string, any> = Object.freeze({
743
743
  UNAVAILABLE: '○ UNAVAILABLE',
744
744
  });
745
745
 
746
- const REACH_MARK: Record<string, any> = Object.freeze({
746
+ const REACH_MARK = Object.freeze({
747
747
  REACHED: '✓ REACHED',
748
748
  'NO-REACH': '✗ NO-REACH',
749
749
  'N/A': '○ N/A',
750
750
  });
751
751
 
752
- const FRESHNESS_MARK: Record<string, any> = Object.freeze({
752
+ const FRESHNESS_MARK = Object.freeze({
753
753
  FRESH: '✓ FRESH',
754
754
  STALE: '▲ STALE',
755
755
  UNKNOWN: '? UNKNOWN',
@@ -764,9 +764,9 @@ const FRESHNESS_MARK: Record<string, any> = Object.freeze({
764
764
  * @returns {number} process exit code — 1 when a provider is installed but does not answer, or an
765
765
  * installed harness's skills cannot reach a runtime
766
766
  */
767
- async function handleDoctorCommand({ json = false, repoRoot, projectRoot = process.cwd(), ...rest }: any = {}) {
768
- const report: any = buildHealthReport({ repoRoot, projectRoot, ...rest });
769
- const { buildAdviceDoctor, printAdviceDoctor } = require('./advice/doctor.ts');
767
+ async function handleDoctorCommand({ json = false, repoRoot, projectRoot = process.cwd(), ...rest } = {}) {
768
+ const report = buildHealthReport({ repoRoot, projectRoot, ...rest });
769
+ const { buildAdviceDoctor, printAdviceDoctor } = require('./advice/doctor.js');
770
770
  const adviceSections = await buildAdviceDoctor({ repoRoot, projectRoot, fsImpl: rest.fsImpl });
771
771
  report.decisionModel = adviceSections.decisionModel;
772
772
  report.advice = adviceSections.advice;
@@ -790,8 +790,8 @@ async function handleDoctorCommand({ json = false, repoRoot, projectRoot = proce
790
790
  for (const harness of report.harnesses) console.log(` ${harness.displayName.padEnd(28)} adapter PASS`);
791
791
 
792
792
  console.log('\n[Runtime Reach]');
793
- const reachLines = report.harnesses.flatMap((harness: any) => harness.reach.map((row: any) => {
794
- const detail = ({ REACHED: row.root, 'NO-REACH': `fix: ${row.fix}`, 'N/A': row.reason } as Record<string, any>)[row.state];
793
+ const reachLines = report.harnesses.flatMap((harness ) => harness.reach.map((row ) => {
794
+ const detail = ({ REACHED: row.root, 'NO-REACH': `fix: ${row.fix}`, 'N/A': row.reason } )[row.state];
795
795
  const where = row.scope === 'project' ? ` [install at ${row.installRoot}]` : '';
796
796
  return ` ${harness.id.padEnd(14)}${row.scope.padEnd(9)}${(REACH_MARK[row.state] || row.state).padEnd(13)}${detail}${where}`;
797
797
  }));
@@ -819,7 +819,7 @@ async function handleDoctorCommand({ json = false, repoRoot, projectRoot = proce
819
819
 
820
820
  console.log('\n[Project Commands]');
821
821
  const commands = report.project.commands;
822
- const commandLine = (role: any) => (role
822
+ const commandLine = (role ) => (role
823
823
  ? `✓ ${role.command}${role.source ? ` (${role.source}, ${role.derivation || 'declared'})` : ''}`
824
824
  : '? not detected');
825
825
  console.log(` build ${commandLine(commands.build)}`);