@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
@@ -33,10 +33,10 @@ const RESOLUTION_REASONS = new Set([
33
33
  * every language in the repository, and a parser per language is a far larger thing than the
34
34
  * question being asked.
35
35
  */
36
- function findSymbolLines(lines: string[], symbol: string): number[] {
36
+ function findSymbolLines(lines , symbol ) {
37
37
  const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
38
38
  const pattern = new RegExp(`(?:^|[^A-Za-z0-9_$])${escaped}(?:[^A-Za-z0-9_$]|$)`);
39
- const hits: number[] = [];
39
+ const hits = [];
40
40
  for (let i = 0; i < lines.length; i += 1) {
41
41
  if (pattern.test(lines[i])) hits.push(i + 1);
42
42
  }
@@ -52,10 +52,10 @@ function findSymbolLines(lines: string[], symbol: string): number[] {
52
52
  *
53
53
  * @returns {{lines: string[]}|{missing: true}}
54
54
  */
55
- function readTargetLines(locator: any, root: string, impl: any): { lines: string[] } | { missing: true } {
55
+ function readTargetLines(locator , root , impl ) {
56
56
  const target = path.isAbsolute(locator.file) ? locator.file : path.join(root, locator.file);
57
57
 
58
- let content: string;
58
+ let content ;
59
59
  try {
60
60
  if (!impl.existsSync(target)) return { missing: true };
61
61
  content = impl.readFileSync(target, 'utf8');
@@ -78,7 +78,7 @@ function readTargetLines(locator: any, root: string, impl: any): { lines: string
78
78
  * already reports. Only absence is unresolvable — that distinction is the whole of this function
79
79
  * and is easier to see with nothing else around it.
80
80
  */
81
- function checkSymbol(lines: string[], symbol: string): any {
81
+ function checkSymbol(lines , symbol ) {
82
82
  const symbolLines = findSymbolLines(lines, symbol);
83
83
  if (symbolLines.length === 0) {
84
84
  return { resolved: false, reason: 'symbol-absent', actual: { lines: lines.length, symbolLines: [] } };
@@ -105,7 +105,7 @@ const NOT_CHECKABLE = { resolved: true, reason: 'not-checkable', actual: null };
105
105
  * `actual` names what the file does offer, so a caller can build a message the writer can act on:
106
106
  * `{ lines }` for a line miss, `{ symbolLines }` for a symbol miss.
107
107
  */
108
- function resolveLocator({ locator, repoRoot, fsImpl }: any = {}): { resolved: boolean; reason: string | null; actual: any } {
108
+ function resolveLocator({ locator, repoRoot, fsImpl } = {}) {
109
109
  if (!locator || typeof locator !== 'object' || Array.isArray(locator)) return { ...NOT_CHECKABLE };
110
110
  // A uri-only locator, or an empty locator on a non-extracted item. Nothing readable here.
111
111
  if (!locator.file) return { ...NOT_CHECKABLE };
@@ -130,7 +130,7 @@ function resolveLocator({ locator, repoRoot, fsImpl }: any = {}): { resolved: bo
130
130
  * @param {{resolved: boolean, reason: (string|null), actual: (Object|null)}} result
131
131
  * @returns {string|null}
132
132
  */
133
- function describeResolution(locator: any, result: any): string | null {
133
+ function describeResolution(locator , result ) {
134
134
  if (!result || result.resolved) return null;
135
135
  const file = (locator && locator.file) || '(no file)';
136
136
  switch (result.reason) {
@@ -52,10 +52,10 @@ const KEY_VALUE_BODY = new RegExp(`(${KEY_NAME}["']?[ \\t]*[=:][ \\t]*)("[^"\\r\
52
52
  const AUTH_HEADER = /((?:Proxy-)?Authorization:)[ \t]*([^\r\n]*)/gi;
53
53
  const SECRET_FLAG = /(--(?:password|passwd|token|secret|api-key|client-secret)(?:=|[ \t]+))("[^"\r\n]*"|'[^'\r\n]*'|[^\s"']+)/gi;
54
54
 
55
- function escapeRegExp(text: string): string { return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
55
+ function escapeRegExp(text ) { return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
56
56
 
57
57
  /** The home directory to abbreviate: an absolute path other than the file system root. */
58
- function homeOf(options?: any): string | null {
58
+ function homeOf(options ) {
59
59
  const raw = options && 'home' in options ? options.home : process.env.HOME;
60
60
  if (typeof raw !== 'string' || !raw.startsWith('/')) return null;
61
61
  const home = raw.replace(/\/+$/, '');
@@ -63,12 +63,12 @@ function homeOf(options?: any): string | null {
63
63
  }
64
64
 
65
65
  /** A run of 32 or more characters that is a path: starts with `/`, `~` or `.` and has no part of 32+. */
66
- function isPathRun(run: string, before: string | undefined): boolean {
66
+ function isPathRun(run , before ) {
67
67
  if (!(run.startsWith('/') || before === '~' || before === '.')) return false;
68
- return run.split('/').every((part: string) => part.length < 32);
68
+ return run.split('/').every((part ) => part.length < 32);
69
69
  }
70
70
 
71
- function looksLikeSecretRun(run: string, minDigits: number): boolean {
71
+ function looksLikeSecretRun(run , minDigits ) {
72
72
  const digits = (run.match(/[0-9]/g) || []).length;
73
73
  const upper = (run.match(/[A-Z]/g) || []).length;
74
74
  const lower = (run.match(/[a-z]/g) || []).length;
@@ -84,14 +84,14 @@ function looksLikeSecretRun(run: string, minDigits: number): boolean {
84
84
  const KEY_VALUE_40 = /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40}(?![A-Za-z0-9+/])/g;
85
85
 
86
86
  /** Masks the 40-character values inside a run that did not qualify as a whole. */
87
- function mask40(run: string, before: string | undefined): string {
88
- return run.replace(KEY_VALUE_40, (value: string, index: number) => (
87
+ function mask40(run , before ) {
88
+ return run.replace(KEY_VALUE_40, (value , index ) => (
89
89
  looksLikeSecretRun(value, 1) && !isPathRun(value, index === 0 ? before : run[index - 1]) ? MASKED : value));
90
90
  }
91
91
 
92
- function isMasked(value: string): boolean { return value.replace(/^["']|["']$/g, '') === MASKED; }
92
+ function isMasked(value ) { return value.replace(/^["']|["']$/g, '') === MASKED; }
93
93
 
94
- function count(text: string, token: string): number { return text.split(token).length - 1; }
94
+ function count(text , token ) { return text.split(token).length - 1; }
95
95
 
96
96
  /**
97
97
  * Masks `text` with a profile.
@@ -102,7 +102,7 @@ function count(text: string, token: string): number { return text.split(token).l
102
102
  * @returns {{text: string, masked: number}} `masked` counts the values replaced: the net growth in
103
103
  * the number of `<masked>`, `<email>` and `<ip>` markers, so a value two rules both reach counts once
104
104
  */
105
- function mask(text: any, profile: 'line' | 'body', options: any = {}): { text: string; masked: number } {
105
+ function mask(text , profile , options = {}) {
106
106
  if (profile !== 'line' && profile !== 'body') throw new TypeError(`unknown mask profile '${profile}'`);
107
107
  const input = text == null ? '' : String(text);
108
108
  let out = input;
@@ -119,33 +119,33 @@ function mask(text: any, profile: 'line' | 'body', options: any = {}): { text: s
119
119
  // 3. Bearer tokens and URL credentials.
120
120
  out = out.replace(BEARER, `$1$2${MASKED}`).replace(URL_CREDENTIALS, `://${MASKED}@`);
121
121
  // 4. Key=value, unquoted, when the value is not plain letters.
122
- out = out.replace(KEY_VALUE_LINE, (match: string, key: string, separator: string, value: string) => (
122
+ out = out.replace(KEY_VALUE_LINE, (match , key , separator , value ) => (
123
123
  isMasked(value) || value.startsWith(MASKED) || !/[^A-Za-z]/.test(value) ? match : `${key}${separator}${MASKED}`));
124
124
  // 5. Long secret-looking runs that are not paths.
125
- out = out.replace(LONG_RUN, (run: string, offset: number) => (
125
+ out = out.replace(LONG_RUN, (run , offset ) => (
126
126
  looksLikeSecretRun(run, 2) && !isPathRun(run, out[offset - 1]) ? MASKED : mask40(run, out[offset - 1])));
127
127
  // 6. Email addresses and IPv4 addresses.
128
128
  out = out.replace(EMAIL_ADDRESS, EMAIL).replace(IPV4, IP);
129
129
 
130
130
  if (profile === 'body') {
131
131
  // 7. Key and value, quoted or not, whatever the value looks like.
132
- out = out.replace(KEY_VALUE_BODY, (match: string, head: string, value: string) => {
132
+ out = out.replace(KEY_VALUE_BODY, (match , head , value ) => {
133
133
  if (isMasked(value) || value.startsWith(MASKED)) return match;
134
134
  const quote = value[0] === '"' || value[0] === "'" ? value[0] : '';
135
135
  return `${head}${quote}${MASKED}${quote}`;
136
136
  });
137
137
  // 8. Authorization headers: everything after the colon.
138
- out = out.replace(AUTH_HEADER, (match: string, name: string, rest: string) => (rest === '' || rest === MASKED ? match : `${name} ${MASKED}`));
138
+ out = out.replace(AUTH_HEADER, (match , name , rest ) => (rest === '' || rest === MASKED ? match : `${name} ${MASKED}`));
139
139
  // 9. Secret-bearing command-line flags.
140
- out = out.replace(SECRET_FLAG, (match: string, flag: string, value: string) => (isMasked(value) ? match : `${flag}${MASKED}`));
140
+ out = out.replace(SECRET_FLAG, (match , flag , value ) => (isMasked(value) ? match : `${flag}${MASKED}`));
141
141
  }
142
142
 
143
143
  const masked = Math.max(0, [MASKED, EMAIL, IP].reduce((sum, token) => sum + count(out, token) - count(input, token), 0));
144
144
  return { text: out, masked };
145
145
  }
146
146
 
147
- const maskLine = (text: any, options?: any) => mask(text, 'line', options);
148
- const maskBody = (text: any, options?: any) => mask(text, 'body', options);
147
+ const maskLine = (text , options ) => mask(text, 'line', options);
148
+ const maskBody = (text , options ) => mask(text, 'body', options);
149
149
 
150
150
  const ABSOLUTE_PATH = /(?<![A-Za-z0-9_.:/~-])(?:~(?![A-Za-z0-9_])\/?|\/)[^\s"'`<>:;,()[\]{}]*|[A-Za-z]:\\[^\s"'`<>:;,()[\]{}]*/g;
151
151
 
@@ -154,7 +154,7 @@ const ABSOLUTE_PATH = /(?<![A-Za-z0-9_.:/~-])(?:~(?![A-Za-z0-9_])\/?|\/)[^\s"'`<
154
154
  * @param {*} text
155
155
  * @returns {string}
156
156
  */
157
- function normalise(text: any): string {
157
+ function normalise(text ) {
158
158
  let out = text == null ? '' : String(text);
159
159
  out = out.replace(ABSOLUTE_PATH, '<path>'); // 10
160
160
  out = out.replace(/"[^"]*"|(?<![A-Za-z0-9])'[^']*'|`[^`]*`/g, '"..."'); // 11
@@ -168,7 +168,7 @@ function normalise(text: any): string {
168
168
  * a path with a long mixed-case segment would otherwise be masked by rule 5 as `<masked>` while a
169
169
  * short one becomes `<path>`.
170
170
  */
171
- function normaliseMessage(text: any, options?: any): string {
171
+ function normaliseMessage(text , options ) {
172
172
  const paths = (text == null ? '' : String(text)).replace(ABSOLUTE_PATH, '<path>');
173
173
  return normalise(maskLine(paths, options).text);
174
174
  }
@@ -193,14 +193,14 @@ const REPLACEMENT = '\uFFFD';
193
193
  * @param {{keepLineBreaks?: boolean}} [options]
194
194
  * @returns {T}
195
195
  */
196
- function printSafe(value: any, options: { keepLineBreaks?: boolean } = {}): any {
196
+ function printSafe(value , options = {}) {
197
197
  if (typeof value === 'string') {
198
198
  const spaced = options.keepLineBreaks ? value : value.replace(PRINT_LINE_BREAK, ' ');
199
199
  return spaced.replace(PRINT_CONTROL, REPLACEMENT);
200
200
  }
201
- if (Array.isArray(value)) return value.map((item: any) => printSafe(item, options));
201
+ if (Array.isArray(value)) return value.map((item ) => printSafe(item, options));
202
202
  if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {
203
- const out: Record<string, any> = {};
203
+ const out = {};
204
204
  for (const key of Object.keys(value)) out[key] = printSafe(value[key], options);
205
205
  return out;
206
206
  }
@@ -20,7 +20,7 @@ const OUTCOME_STATES = Object.freeze(['consulted-used', 'consulted-nothing-usabl
20
20
 
21
21
  /** Five distinct labels (NFR-007). `no-outcome` is derived, never stored. A skipped outcome's
22
22
  * text surfaces append its reason: see `outcomeLabel`. */
23
- const OUTCOME_LABELS: Readonly<Record<string, string>> = Object.freeze({
23
+ const OUTCOME_LABELS = Object.freeze({
24
24
  'consulted-used': 'consulted, used',
25
25
  'consulted-nothing-usable': 'consulted, nothing usable',
26
26
  skipped: 'skipped',
@@ -28,7 +28,7 @@ const OUTCOME_LABELS: Readonly<Record<string, string>> = Object.freeze({
28
28
  'no-outcome': 'no outcome recorded',
29
29
  });
30
30
 
31
- const FLAG_TOKEN_STATE: Readonly<Record<string, string>> = Object.freeze({
31
+ const FLAG_TOKEN_STATE = Object.freeze({
32
32
  used: 'consulted-used',
33
33
  'nothing-usable': 'consulted-nothing-usable',
34
34
  unavailable: 'unavailable',
@@ -41,11 +41,11 @@ const CONTENT_LIMIT = 500;
41
41
  const SCHEMA = 1;
42
42
 
43
43
  // used > nothing usable > unavailable > skipped (IC-008 rule 2).
44
- const PRECEDENCE: Readonly<Record<string, number>> = Object.freeze({
44
+ const PRECEDENCE = Object.freeze({
45
45
  'consulted-used': 4, 'consulted-nothing-usable': 3, unavailable: 2, skipped: 1,
46
46
  });
47
47
 
48
- function outcomeLabel(outcome: any): string {
48
+ function outcomeLabel(outcome ) {
49
49
  const label = OUTCOME_LABELS[outcome.state];
50
50
  return outcome.state === 'skipped' && outcome.reason ? `${label}: ${outcome.reason}` : label;
51
51
  }
@@ -54,7 +54,7 @@ function outcomeLabel(outcome: any): string {
54
54
  * Parse one outcome token (IC-005 flag token). Returns `{ state, reason? }` or `{ error }`.
55
55
  * @param {string} token
56
56
  */
57
- function parseOutcomeToken(token: any): any {
57
+ function parseOutcomeToken(token ) {
58
58
  const text = String(token ?? '').trim();
59
59
  if (Object.hasOwn(FLAG_TOKEN_STATE, text)) return { state: FLAG_TOKEN_STATE[text] };
60
60
  if (text === 'skipped' || text === 'skipped:') return { error: 'skipped needs a reason: skipped:<reason>' };
@@ -72,10 +72,10 @@ function parseOutcomeToken(token: any): any {
72
72
  * @param {string[]|string|undefined} values
73
73
  * @returns {{ outcomes: Map<string, {state: string, reason?: string}>, ignored: Array<{value: string, reason: string}> }}
74
74
  */
75
- function parseMcpOutcomeFlags(values?: string[] | string | null): { outcomes: Map<string, any>; ignored: Array<{ value: string; reason: string }> } {
76
- const list: any[] = values === undefined || values === null ? [] : ([] as any[]).concat(values);
77
- const outcomes = new Map<string, any>();
78
- const ignored: Array<{ value: string; reason: string }> = [];
75
+ function parseMcpOutcomeFlags(values ) {
76
+ const list = values === undefined || values === null ? [] : ([] ).concat(values);
77
+ const outcomes = new Map ();
78
+ const ignored = [];
79
79
  for (const raw of list) {
80
80
  const value = String(raw);
81
81
  const at = value.indexOf('=');
@@ -94,7 +94,7 @@ function parseMcpOutcomeFlags(values?: string[] | string | null): { outcomes: Ma
94
94
 
95
95
  /** Strip a leading `- `, `**...**` emphasis and a line-wide pair of backticks, so
96
96
  * `- **Tools used:** a` and `` `Tools used: a` `` both read as `Tools used: a`. */
97
- function plainLine(line: string): string {
97
+ function plainLine(line ) {
98
98
  let text = line.trim().replace(/^-\s+/, '');
99
99
  if (text.startsWith('**')) text = text.slice(2).replace('**', '');
100
100
  if (text.startsWith('`Tools used:') && text.endsWith('`')) text = text.slice(1, -1);
@@ -102,8 +102,8 @@ function plainLine(line: string): string {
102
102
  }
103
103
 
104
104
  /** Split on commas outside parentheses, so a note like `(a, b)` stays with its entry. */
105
- function splitEntries(body: string): string[] {
106
- const pieces: string[] = [];
105
+ function splitEntries(body ) {
106
+ const pieces = [];
107
107
  let depth = 0;
108
108
  let current = '';
109
109
  for (const char of body) {
@@ -116,7 +116,7 @@ function splitEntries(body: string): string[] {
116
116
  }
117
117
 
118
118
  /** One entry with a trailing ` (note)` and a surrounding pair of backticks removed. */
119
- function plainEntry(piece: string): string {
119
+ function plainEntry(piece ) {
120
120
  let text = piece.trim().replace(/\s+\([^()]*\)$/, '').trim();
121
121
  if (text.length > 1 && text.startsWith('`') && text.endsWith('`')) text = text.slice(1, -1).trim();
122
122
  return text;
@@ -127,7 +127,7 @@ function plainEntry(piece: string): string {
127
127
  * @param {string} text report text
128
128
  * @returns {null | { line: number, raw: string, entries: Array<{name: string, state?: string, reason?: string, raw: string, valid: boolean}> }}
129
129
  */
130
- function parseToolsUsed(text: any): any {
130
+ function parseToolsUsed(text ) {
131
131
  const lines = String(text ?? '').split('\n');
132
132
  let found = -1;
133
133
  for (let i = 0; i < lines.length; i += 1) {
@@ -136,7 +136,7 @@ function parseToolsUsed(text: any): any {
136
136
  if (found === -1) return null;
137
137
  const raw = lines[found].replace(/\s+$/, '').trim();
138
138
  const body = plainLine(lines[found]).slice('Tools used:'.length).trim();
139
- const entries: any[] = [];
139
+ const entries = [];
140
140
  if (body !== '' && body !== 'none') {
141
141
  for (const piece of splitEntries(body)) {
142
142
  const entry = plainEntry(piece);
@@ -154,9 +154,9 @@ function parseToolsUsed(text: any): any {
154
154
  }
155
155
 
156
156
  /** Server ids the registry knows: `mcp` servers plus every provider's `mcp.server`. */
157
- function knownServerIds(registry: any): Set<string> {
158
- const ids = new Set<string>((registry?.mcp || []).map((server: any) => server.id));
159
- for (const capability of Object.values(registry?.capabilities || {}) as any[]) {
157
+ function knownServerIds(registry ) {
158
+ const ids = new Set ((registry?.mcp || []).map((server ) => server.id));
159
+ for (const capability of Object.values(registry?.capabilities || {}) ) {
160
160
  for (const provider of capability?.providers || []) {
161
161
  if (provider?.mcp?.server) ids.add(provider.mcp.server);
162
162
  }
@@ -168,17 +168,17 @@ function knownServerIds(registry: any): Set<string> {
168
168
  * Servers a stage run names (IC-001 meaning). Sorted.
169
169
  * @param {{registry: object, skill: string, stageId?: string, taskId?: string, requests?: {list: Function}}} input
170
170
  */
171
- function namedServers({ registry, skill, stageId, taskId, requests }: any): string[] {
172
- let researchRequested: boolean | undefined;
173
- const hasRequest = (): boolean => {
171
+ function namedServers({ registry, skill, stageId, taskId, requests } ) {
172
+ let researchRequested ;
173
+ const hasRequest = () => {
174
174
  if (researchRequested === undefined) {
175
- let list: any = [];
175
+ let list = [];
176
176
  try { list = requests && taskId ? requests.list(taskId) : []; } catch { list = []; }
177
- researchRequested = Array.isArray(list) && list.some((request: any) => request && request.stageId === stageId);
177
+ researchRequested = Array.isArray(list) && list.some((request ) => request && request.stageId === stageId);
178
178
  }
179
179
  return researchRequested;
180
180
  };
181
- const named = new Set<string>();
181
+ const named = new Set ();
182
182
  for (const server of registry?.mcp || []) {
183
183
  for (const step of server.steps || []) {
184
184
  if (step.expectedWhen === 'research-request') {
@@ -191,7 +191,7 @@ function namedServers({ registry, skill, stageId, taskId, requests }: any): stri
191
191
  return [...named].sort();
192
192
  }
193
193
 
194
- const bySortKey = (a: any, b: any): number => (a < b ? -1 : a > b ? 1 : 0);
194
+ const bySortKey = (a , b ) => (a < b ? -1 : a > b ? 1 : 0);
195
195
 
196
196
  /**
197
197
  * Resolve a stage run's MCP consultations (IC-008).
@@ -213,11 +213,11 @@ const bySortKey = (a: any, b: any): number => (a < b ? -1 : a > b ? 1 : 0);
213
213
  function resolveConsultations({
214
214
  taskId = null, stageId = null, skill, flags, registry, ledger, requests,
215
215
  briefRecords = [], readReport, reach, addCommand, harnessName, since = null,
216
- }: any = {}): { record: any; warnings: any[]; notices: any[]; evidenceToAdd: any[] } {
217
- const warnings: any[] = [];
218
- const notices: any[] = [];
219
- const evidenceToAdd: any[] = [];
220
- const registered = new Set((registry?.mcp || []).map((server: any) => server.id));
216
+ } = {}) {
217
+ const warnings = [];
218
+ const notices = [];
219
+ const evidenceToAdd = [];
220
+ const registered = new Set((registry?.mcp || []).map((server ) => server.id));
221
221
  const known = knownServerIds(registry);
222
222
  const named = namedServers({ registry, skill, stageId, taskId, requests });
223
223
 
@@ -232,28 +232,28 @@ function resolveConsultations({
232
232
 
233
233
  // Rule 2: Tools used lines in the reports of this run's briefs. Records with no stage are never
234
234
  // ingested (design A6).
235
- const toolsUsed: any[] = [];
236
- const fromReports = new Map<string, any[]>();
235
+ const toolsUsed = [];
236
+ const fromReports = new Map ();
237
237
  const records = (Array.isArray(briefRecords) ? briefRecords : [])
238
- .filter((record: any) => record && stageId && taskId && record.stage === stageId && record.runTaskId === taskId);
239
- const reports: Array<{ id: string; report: string }> = [];
238
+ .filter((record ) => record && stageId && taskId && record.stage === stageId && record.runTaskId === taskId);
239
+ const reports = [];
240
240
  for (const record of records) {
241
241
  for (const task of record.tasks || []) {
242
242
  if (task && typeof task.id === 'string' && typeof task.report === 'string') reports.push({ id: task.id, report: task.report });
243
243
  }
244
244
  }
245
245
  reports.sort((a, b) => bySortKey(a.id, b.id) || bySortKey(a.report, b.report));
246
- const existing = new Map<string, any[]>();
247
- const existingFor = (id: string): any[] => {
246
+ const existing = new Map ();
247
+ const existingFor = (id ) => {
248
248
  if (!existing.has(id)) {
249
- let items: any[] = [];
249
+ let items = [];
250
250
  try { items = ledger ? ledger.queryEvidence({ taskId: id }) : []; } catch { items = []; }
251
- existing.set(id, items.filter((item: any) => item && item.status === 'active'));
251
+ existing.set(id, items.filter((item ) => item && item.status === 'active'));
252
252
  }
253
- return existing.get(id) as any[];
253
+ return existing.get(id) ;
254
254
  };
255
255
  for (const { id, report } of reports) {
256
- let text: any = null;
256
+ let text = null;
257
257
  try { text = typeof readReport === 'function' ? readReport(report) : null; } catch { text = null; }
258
258
  if (typeof text !== 'string') {
259
259
  toolsUsed.push({ taskId: id, status: 'no-report', report });
@@ -274,9 +274,9 @@ function resolveConsultations({
274
274
  }
275
275
  const source = { provider: 'dispatched-agent', capability: 'tools-used' };
276
276
  const content = parsed.raw.slice(0, CONTENT_LIMIT);
277
- const duplicate = existingFor(id).find((item: any) => item.source?.provider === source.provider
277
+ const duplicate = existingFor(id).find((item ) => item.source?.provider === source.provider
278
278
  && item.source?.capability === source.capability && item.content === content);
279
- const inBatch = evidenceToAdd.some((item: any) => item.taskId === id && item.content === content);
279
+ const inBatch = evidenceToAdd.some((item ) => item.taskId === id && item.content === content);
280
280
  if (duplicate) {
281
281
  toolsUsed.push({ taskId: id, status: 'already-recorded', evidenceId: duplicate.id });
282
282
  } else if (inBatch) {
@@ -301,10 +301,10 @@ function resolveConsultations({
301
301
 
302
302
  // Rule 3: evidence attributed to a server by `source.provider`, observed during this stage run:
303
303
  // after `since` (the previous stage's completion or the run start) when the caller knows it.
304
- const evidenceServers = new Set<string>();
305
- const inThisStage = (item: any): boolean => since === null || (typeof item.freshness?.observedAt === 'string' && item.freshness.observedAt > since);
304
+ const evidenceServers = new Set ();
305
+ const inThisStage = (item ) => since === null || (typeof item.freshness?.observedAt === 'string' && item.freshness.observedAt > since);
306
306
  if (ledger && taskId) {
307
- let items: any[] = [];
307
+ let items = [];
308
308
  try { items = ledger.queryEvidence({ taskId }); } catch { items = []; }
309
309
  for (const item of items) {
310
310
  if (item && item.status === 'active' && known.has(item.source?.provider) && inThisStage(item)) evidenceServers.add(item.source.provider);
@@ -313,8 +313,8 @@ function resolveConsultations({
313
313
 
314
314
  // Rule 4: a brief record for this stage that expected the server and found it unreachable. The
315
315
  // brief writes `unreachable` only where every config the harness merges was read (IC-017).
316
- const unreachable = new Map<string, any>();
317
- const reachableOn = new Map<string, any>();
316
+ const unreachable = new Map ();
317
+ const reachableOn = new Map ();
318
318
  for (const record of records) {
319
319
  for (const expected of record.expected || []) {
320
320
  if (!expected || typeof expected.server !== 'string') continue;
@@ -324,16 +324,16 @@ function resolveConsultations({
324
324
  }
325
325
 
326
326
  /** Who has a server the run asserted unavailable: the brief's harness, else an installed one. */
327
- const nameOf = (id: any): string => (typeof harnessName === 'function' && harnessName(id)) || id;
328
- const contradiction = (server: string): string | null => {
327
+ const nameOf = (id ) => (typeof harnessName === 'function' && harnessName(id)) || id;
328
+ const contradiction = (server ) => {
329
329
  if (reachableOn.has(server)) {
330
330
  const id = reachableOn.get(server);
331
331
  return id ? nameOf(id) : 'an installed harness';
332
332
  }
333
- let has: any = null;
333
+ let has = null;
334
334
  try { has = reach && typeof reach.anyHarnessHas === 'function' ? reach.anyHarnessHas(server) : null; } catch { has = null; }
335
335
  if (has !== true) return null;
336
- let name: any = null;
336
+ let name = null;
337
337
  try { name = typeof reach.harnessWith === 'function' ? reach.harnessWith(server) : null; } catch { name = null; }
338
338
  return name || 'an installed harness';
339
339
  };
@@ -341,14 +341,14 @@ function resolveConsultations({
341
341
  const candidates = new Set([
342
342
  ...named, ...parsedFlags.outcomes.keys(), ...fromReports.keys(), ...evidenceServers, ...unreachable.keys(),
343
343
  ]);
344
- const outcomes: any[] = [];
344
+ const outcomes = [];
345
345
  for (const server of [...candidates].sort()) {
346
- let outcome: any = null;
346
+ let outcome = null;
347
347
  const flag = parsedFlags.outcomes.get(server);
348
348
  if (flag) {
349
349
  outcome = { server, state: flag.state, ...(flag.reason ? { reason: flag.reason } : {}), source: 'flag' };
350
350
  } else if (fromReports.has(server)) {
351
- const best = (fromReports.get(server) as any[]).reduce((a: any, b: any) => (PRECEDENCE[b.state] > PRECEDENCE[a.state] ? b : a));
351
+ const best = (fromReports.get(server) ).reduce((a , b ) => (PRECEDENCE[b.state] > PRECEDENCE[a.state] ? b : a));
352
352
  outcome = {
353
353
  server, state: best.state, ...(best.reason ? { reason: best.reason } : {}), source: 'tools-used', taskId: best.taskId,
354
354
  };
@@ -17,16 +17,16 @@
17
17
  const fs = require('node:fs');
18
18
  const os = require('node:os');
19
19
  const path = require('node:path');
20
- const { readLedger } = require('../state/index.ts');
21
- const { resolveAdapter } = require('../adapters/index.ts');
22
- const { evaluateReach } = require('./reach.ts');
20
+ const { readLedger } = require('../state/index.js');
21
+ const { resolveAdapter } = require('../adapters/index.js');
22
+ const { evaluateReach } = require('./reach.js');
23
23
 
24
- const SCOPE_ORDER: Record<string, number> = { project: 0, global: 1 };
24
+ const SCOPE_ORDER = { project: 0, global: 1 };
25
25
 
26
26
  /** Every server id the answer covers: the MCP catalog, then each provider's own MCP server. */
27
- function serverIdsOf(registry: any) {
28
- const ids = (registry.mcp || []).map((server: any) => server.id);
29
- for (const capability of (Object.values(registry.capabilities || {}) as any[])) {
27
+ function serverIdsOf(registry ) {
28
+ const ids = (registry.mcp || []).map((server ) => server.id);
29
+ for (const capability of (Object.values(registry.capabilities || {}) )) {
30
30
  for (const provider of capability.providers || []) if (provider.mcp?.server) ids.push(provider.mcp.server);
31
31
  }
32
32
  return [...new Set(ids)];
@@ -34,16 +34,16 @@ function serverIdsOf(registry: any) {
34
34
 
35
35
  /** The MCP file an adapter's discovery could not read and the fixed reason it gives, or null.
36
36
  * Reasons come from the adapters (invalid JSON, wrong shape), never from file content. */
37
- function unreadableDetail(discovery: any) {
38
- for (const [file, read] of (Object.entries(discovery.mcpSnapshot || {}) as [string, any][])) if (read?.ok === false) return { detail: read.reason, file };
39
- for (const [file, read] of (Object.entries(discovery.mcp || {}) as [string, any][])) if (read?.doc?.ok === false) return { detail: read.doc.reason, file };
37
+ function unreadableDetail(discovery ) {
38
+ for (const [file, read] of (Object.entries(discovery.mcpSnapshot || {}) )) if (read?.ok === false) return { detail: read.reason, file };
39
+ for (const [file, read] of (Object.entries(discovery.mcp || {}) )) if (read?.doc?.ok === false) return { detail: read.doc.reason, file };
40
40
  if (discovery.settings?.error) return { detail: 'invalid JSON', ...(discovery.paths?.settings ? { file: discovery.paths.settings } : {}) };
41
41
  return null;
42
42
  }
43
43
 
44
44
  /** A server is absent (`not-taken`, `not-selected`) only where the adapter read every source its
45
45
  * harness merges (`mcpComplete: true`); anywhere else absence is no proof and the state is unknown. */
46
- function stateOf(row: any, id: any) {
46
+ function stateOf(row , id ) {
47
47
  if (row.selected.has(id)) return 'selected';
48
48
  if (row.configured?.includes(id)) return 'configured';
49
49
  if (row.unreadable || row.configured === null || !row.complete) return 'unknown';
@@ -59,14 +59,14 @@ function stateOf(row: any, id: any) {
59
59
  * @param {Object} options.adapters adapter registry (`buildAdapterRegistry()`)
60
60
  * @returns {{harnesses: Object[], unreadable: Object[]}} plain data; `anyHarnessHas` and `addCommand` ride along unenumerated
61
61
  */
62
- function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs, adapters }: any) {
62
+ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs, adapters } ) {
63
63
  const serverIds = serverIdsOf(registry);
64
- const catalogIds = (registry.mcp || []).map((server: any) => server.id);
65
- const harnessOrder = registry.harnesses.map((harness: any) => harness.id);
64
+ const catalogIds = (registry.mcp || []).map((server ) => server.id);
65
+ const harnessOrder = registry.harnesses.map((harness ) => harness.id);
66
66
  const { rows: reached } = evaluateReach({ registry, projectRoot, homeDir, fsImpl });
67
67
 
68
68
  const ledgers = new Map();
69
- const ledgerOf = ({ scope, installRoot }: any) => {
69
+ const ledgerOf = ({ scope, installRoot } ) => {
70
70
  const key = `${scope}\0${installRoot}`;
71
71
  if (!ledgers.has(key)) {
72
72
  let ledger = null;
@@ -78,12 +78,12 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
78
78
 
79
79
  const unreadable = [];
80
80
  const seen = new Set();
81
- const rows: any[] = [];
81
+ const rows = [];
82
82
  for (const { harness: id, scope, installRoot } of reached) {
83
83
  const key = `${id}\0${scope}\0${installRoot}`;
84
84
  if (seen.has(key)) continue;
85
85
  seen.add(key);
86
- const harness = registry.harnesses.find((item: any) => item.id === id);
86
+ const harness = registry.harnesses.find((item ) => item.id === id);
87
87
  const ledger = ledgerOf({ scope, installRoot });
88
88
  const mcp = harness.capabilities?.mcp;
89
89
  const row = {
@@ -91,7 +91,7 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
91
91
  catalog: mcp?.status === 'supported' ? 'taken' : 'not-taken',
92
92
  note: mcp?.note ?? mcp?.verification,
93
93
  selected: new Set((ledger?.resources || [])
94
- .filter((resource: any) => resource.harness === id && resource.kind === 'mcp-server').map((resource: any) => resource.identity)),
94
+ .filter((resource ) => resource.harness === id && resource.kind === 'mcp-server').map((resource ) => resource.identity)),
95
95
  configured: null,
96
96
  complete: false,
97
97
  unreadable: false,
@@ -104,7 +104,7 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
104
104
  row.complete = discovery.mcpComplete === true;
105
105
  const found = unreadableDetail(discovery);
106
106
  if (found) { row.unreadable = true; unreadable.push({ harness: id, scope, ...found }); }
107
- } catch (error: any) {
107
+ } catch (error ) {
108
108
  row.unreadable = true;
109
109
  unreadable.push({ harness: id, scope, detail: error.message });
110
110
  }
@@ -115,7 +115,7 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
115
115
 
116
116
  const result = {
117
117
  harnesses: rows.map((row) => {
118
- const entry: any = { id: row.id, scope: row.scope, catalog: row.catalog };
118
+ const entry = { id: row.id, scope: row.scope, catalog: row.catalog };
119
119
  if (row.catalog === 'not-taken' && row.note) entry.note = row.note;
120
120
  entry.servers = Object.fromEntries(serverIds.map((server) => [server, stateOf(row, server)]));
121
121
  return entry;
@@ -126,15 +126,15 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
126
126
  /** `true` when a server is selected or configured on some installed harness, `false` only when
127
127
  * every installed harness read every source it merges and says it is absent, `null` (unknown)
128
128
  * otherwise, including when none is installed. */
129
- const anyHarnessHas = (server: any) => {
129
+ const anyHarnessHas = (server ) => {
130
130
  const states = rows.map((row) => stateOf(row, server));
131
131
  if (states.some((state) => state === 'selected' || state === 'configured')) return true;
132
132
  return states.length > 0 && states.every((state) => state === 'not-selected' || state === 'not-taken') ? false : null;
133
133
  };
134
134
 
135
135
  /** The command that adds `serverId` for a harness at a scope, or where to configure it by hand. */
136
- const addCommand = (harnessId: any, scope: any, serverId: any) => {
137
- const harness = registry.harnesses.find((item: any) => item.id === harnessId);
136
+ const addCommand = (harnessId , scope , serverId ) => {
137
+ const harness = registry.harnesses.find((item ) => item.id === harnessId);
138
138
  const name = harness?.displayName || harnessId;
139
139
  if (harness?.capabilities?.mcp?.status !== 'supported') {
140
140
  return `configure it in ${name}'s own MCP settings; DoFlow's catalog does not reach it`;
@@ -144,7 +144,7 @@ function mcpReach({ registry, projectRoot, homeDir = os.homedir(), fsImpl = fs,
144
144
  }
145
145
  const chosen = new Set([serverId]);
146
146
  for (const row of rows) if (row.id === harnessId && row.scope === scope) for (const id of row.selected) chosen.add(id);
147
- return `doflow install${scope === 'global' ? ' -g' : ''} --target ${harnessId} --mcp ${catalogIds.filter((id: any) => chosen.has(id)).join(',')}`;
147
+ return `doflow install${scope === 'global' ? ' -g' : ''} --target ${harnessId} --mcp ${catalogIds.filter((id ) => chosen.has(id)).join(',')}`;
148
148
  };
149
149
 
150
150
  Object.defineProperties(result, {