@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
@@ -4,9 +4,9 @@
4
4
 
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
- const { workStatus, createWorkCache, refreshedWorkCache } = require('./work-status.ts');
8
- const { projectKey } = require('../lifecycle/report-store.ts');
9
- const { readEvents } = require('../lifecycle/event-store.ts');
7
+ const { workStatus, createWorkCache, refreshedWorkCache } = require('./work-status.js');
8
+ const { projectKey } = require('../lifecycle/report-store.js');
9
+ const { readEvents } = require('../lifecycle/event-store.js');
10
10
 
11
11
  const DAY = 86400000;
12
12
  const HOUR = 3600000;
@@ -18,12 +18,12 @@ const removableRules = new Set(['count-and-age','work','date-partition','recover
18
18
  const SAFE_NAMESPACE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
19
19
  // Open-log protection cannot vouch for a record store that holds a link, so the pass fails closed.
20
20
  const LINKED = 'link-in-record-store';
21
- function stopped(context: any) { return Boolean(context.shouldStop?.()); }
21
+ function stopped(context ) { return Boolean(context.shouldStop?.()); }
22
22
  function budgetError() { return Object.assign(new Error('storage pass budget exhausted'), { code: 'EBUDGET', partial: true }); }
23
- function projectRoot(roots: any) { return roots['project-state'] ? path.dirname(path.dirname(roots['project-state'])) : null; }
24
- function safeStat(fsImpl: any, file: any) { try { return fsImpl.lstatSync(file); } catch { return null; } }
25
- function names(fsImpl: any, dir: any) { return fsImpl.readdirSync(dir); }
26
- function ageReason(store: any, entry: any, now: any, fsImpl: any, storeDir: any, shouldStop: any) {
23
+ function projectRoot(roots ) { return roots['project-state'] ? path.dirname(path.dirname(roots['project-state'])) : null; }
24
+ function safeStat(fsImpl , file ) { try { return fsImpl.lstatSync(file); } catch { return null; } }
25
+ function names(fsImpl , dir ) { return fsImpl.readdirSync(dir); }
26
+ function ageReason(store , entry , now , fsImpl , storeDir , shouldStop ) {
27
27
  const limit = store.bound.maxAgeDays * DAY;
28
28
  if (store.rule === 'date-partition') {
29
29
  const date = entry.name.slice(0, 10);
@@ -45,13 +45,13 @@ function ageReason(store: any, entry: any, now: any, fsImpl: any, storeDir: any,
45
45
  }
46
46
  return now - newest > limit ? 'age' : null;
47
47
  }
48
- function workCandidates(store: any, entries: any, context: any) {
48
+ function workCandidates(store , entries , context ) {
49
49
  const { fsImpl, storeDir, now, roots, settings, shouldStop } = context;
50
50
  const project = projectRoot(roots);
51
51
  if (!project) return [];
52
52
  const cache = context.cache || createWorkCache({ projectRoot: project, fsImpl });
53
- const recordMatch = new RegExp(store.match), selected: any[] = [];
54
- const visit = (dir: any, namespace: any = null) => {
53
+ const recordMatch = new RegExp(store.match), selected = [];
54
+ const visit = (dir , namespace = null) => {
55
55
  let children;
56
56
  try { children = names(fsImpl, dir); } catch { return true; }
57
57
  for (const name of children) {
@@ -77,7 +77,7 @@ function workCandidates(store: any, entries: any, context: any) {
77
77
  return selected;
78
78
  }
79
79
  /** Revalidate the subject under its try-lock against its current run and plan, not the selection snapshot. */
80
- function recordStillCandidate(store: any, candidate: any, info: any, context: any) {
80
+ function recordStillCandidate(store , candidate , info , context ) {
81
81
  const { fsImpl, roots, now, settings, cache, shouldStop, storeDir } = context;
82
82
  const before = candidate.recordStat;
83
83
  if (!info.isFile() || !before || ['mtimeMs', 'ctimeMs', 'size', 'ino', 'dev'].some(key => info[key] !== before[key])) return false;
@@ -96,7 +96,7 @@ function recordStillCandidate(store: any, candidate: any, info: any, context: an
96
96
  return !status.incomplete && !shouldStop?.() && status.state === 'finished'
97
97
  && status.since === candidate.mtimeMs && now - status.since > store.bound.finishedDays * DAY;
98
98
  }
99
- function workStorePathStatus(store: any, roots: any, fsImpl: any) {
99
+ function workStorePathStatus(store , roots , fsImpl ) {
100
100
  const project = projectRoot(roots), root = roots[store.root];
101
101
  if (!project || !root) return 'missing';
102
102
  const paths = [path.join(project, '.doflow'), root];
@@ -105,16 +105,16 @@ function workStorePathStatus(store: any, roots: any, fsImpl: any) {
105
105
  for (const candidate of paths) {
106
106
  let info;
107
107
  try { info = fsImpl.lstatSync(candidate); }
108
- catch (error: any) { return error.code === 'ENOENT' || error.code === 'ENOTDIR' ? 'missing' : 'inaccessible'; }
108
+ catch (error ) { return error.code === 'ENOENT' || error.code === 'ENOTDIR' ? 'missing' : 'inaccessible'; }
109
109
  if (info.isSymbolicLink()) return 'linked';
110
110
  }
111
111
  return 'safe';
112
112
  }
113
- function protectedLogs({ registry, roots, fsImpl, cache, shouldStop }: any) {
113
+ function protectedLogs({ registry, roots, fsImpl, cache, shouldStop } ) {
114
114
  const project = projectRoot(roots), protectedNames = new Set();
115
115
  if (!project) return { names: protectedNames, incomplete: false };
116
116
  const workCache = cache || createWorkCache({ projectRoot: project, fsImpl });
117
- for (const store of registry.stores.filter((s: any) => s.root === 'project-state' && s.entry === 'record' && s.rule === 'work')) {
117
+ for (const store of registry.stores.filter((s ) => s.root === 'project-state' && s.entry === 'record' && s.rule === 'work')) {
118
118
  if (shouldStop?.()) return { names: protectedNames, incomplete: true };
119
119
  const pathStatus = workStorePathStatus(store, roots, fsImpl);
120
120
  if (pathStatus === 'missing') continue;
@@ -122,16 +122,16 @@ function protectedLogs({ registry, roots, fsImpl, cache, shouldStop }: any) {
122
122
  const dir = path.join(roots[store.root], ...store.path.split('/'));
123
123
  const recordMatch = new RegExp(store.match);
124
124
  let linked = false;
125
- const visit = (folder: any, namespace: any = null) => {
125
+ const visit = (folder , namespace = null) => {
126
126
  let list;
127
127
  try { list = names(fsImpl, folder); }
128
- catch (error: any) { return error.code === 'ENOENT' || error.code === 'ENOTDIR'; }
128
+ catch (error ) { return error.code === 'ENOENT' || error.code === 'ENOTDIR'; }
129
129
  for (const name of list) {
130
130
  if (shouldStop?.()) return false;
131
131
  const file = path.join(folder, name);
132
132
  let stat;
133
133
  try { stat = fsImpl.lstatSync(file); }
134
- catch (error: any) { if (error.code === 'ENOENT' || error.code === 'ENOTDIR') continue; return false; }
134
+ catch (error ) { if (error.code === 'ENOENT' || error.code === 'ENOTDIR') continue; return false; }
135
135
  if (stat.isSymbolicLink()) { linked = true; return false; }
136
136
  if (namespace === null && stat.isDirectory() && SAFE_NAMESPACE.test(name) && !name.includes('..')) {
137
137
  if (!visit(file, name)) return false;
@@ -158,18 +158,18 @@ function protectedLogs({ registry, roots, fsImpl, cache, shouldStop }: any) {
158
158
  }
159
159
  return { names: protectedNames, incomplete: false };
160
160
  }
161
- function lifecyclePathsSafe(project: any, fsImpl: any) {
161
+ function lifecyclePathsSafe(project , fsImpl ) {
162
162
  for (const rel of [path.join('.doflow'), path.join('.doflow', 'state'), path.join('.doflow', 'state', 'lifecycle'), path.join('.doflow', 'state', 'lifecycle', 'events')]) {
163
163
  try { if (fsImpl.lstatSync(path.join(project, rel)).isSymbolicLink()) return false; }
164
- catch (error: any) { if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') return false; if (rel !== path.join('.doflow', 'state', 'lifecycle', 'events')) return false; }
164
+ catch (error ) { if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') return false; if (rel !== path.join('.doflow', 'state', 'lifecycle', 'events')) return false; }
165
165
  }
166
166
  return true;
167
167
  }
168
- function definitelyMissing(fsImpl: any, target: any) {
168
+ function definitelyMissing(fsImpl , target ) {
169
169
  try { fsImpl.lstatSync(target); return false; }
170
- catch (error: any) { return error.code === 'ENOENT' || error.code === 'ENOTDIR'; }
170
+ catch (error ) { return error.code === 'ENOENT' || error.code === 'ENOTDIR'; }
171
171
  }
172
- function reportCandidates(store: any, entries: any, context: any) {
172
+ function reportCandidates(store , entries , context ) {
173
173
  const { fsImpl, storeDir, roots, now, settings, shouldStop } = context;
174
174
  const project = projectRoot(roots);
175
175
  const key = project && projectKey(project, fsImpl), selected = [];
@@ -183,7 +183,7 @@ function reportCandidates(store: any, entries: any, context: any) {
183
183
  if (shouldStop?.()) throw budgetError();
184
184
  if (BODY.test(name) && safeStat(fsImpl, path.join(folder, name))?.isFile()) bodyNames.push(name);
185
185
  }
186
- } catch (error: any) { if (error.partial) throw error; continue; }
186
+ } catch (error ) { if (error.partial) throw error; continue; }
187
187
  if (entry.name === key) {
188
188
  const lifecycle = path.join(project, '.doflow/state/lifecycle');
189
189
  if (!safeStat(fsImpl, path.join(lifecycle, 'migrated.json'))?.isFile() || !lifecyclePathsSafe(project, fsImpl)) continue;
@@ -232,7 +232,7 @@ function reportCandidates(store: any, entries: any, context: any) {
232
232
  }
233
233
  return selected;
234
234
  }
235
- function selectCandidates(store: any, entries: any, context: any) {
235
+ function selectCandidates(store , entries , context ) {
236
236
  const { now, fsImpl, storeDir, roots, shouldStop } = context;
237
237
  switch (store.rule) {
238
238
  case 'count-and-age': {
@@ -5,39 +5,39 @@
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
7
  const { randomBytes } = require('node:crypto');
8
- const { REPO_ROOT } = require('../../helper/repo-root.ts');
9
- const { loadStorageRegistry } = require('./registry.ts');
10
- const { resolveRoots, readPruneSetting } = require('./roots.ts');
11
- const engine = require('./engine.ts');
12
- const { RunLedger } = require('../trace/ledger.ts');
8
+ const { REPO_ROOT } = require('../../helper/repo-root.js');
9
+ const { loadStorageRegistry } = require('./registry.js');
10
+ const { resolveRoots, readPruneSetting } = require('./roots.js');
11
+ const engine = require('./engine.js');
12
+ const { RunLedger } = require('../trace/ledger.js');
13
13
 
14
14
  // Load once: a not-due moment only reads the three small markers, never the catalogue again.
15
- let registry: any;
15
+ let registry ;
16
16
  try { registry = loadStorageRegistry({ repoRoot: REPO_ROOT }); } catch { /* fail closed */ }
17
17
  const MOMENT_ROOTS = ['project-state', 'user-state', 'config-home'];
18
18
 
19
- function silently(fn: any) {
19
+ function silently(fn ) {
20
20
  const exitCode = process.exitCode;
21
21
  try { if (registry) return fn(); } catch { /* upkeep must never affect its caller */ }
22
22
  finally { process.exitCode = exitCode; }
23
23
  }
24
- function stat(file: any, fsImpl: any) {
24
+ function stat(file , fsImpl ) {
25
25
  try { return fsImpl.lstatSync(file); }
26
- catch (error: any) { if (error.code === 'ENOENT') return null; throw error; }
26
+ catch (error ) { if (error.code === 'ENOENT') return null; throw error; }
27
27
  }
28
- function usableRoot(root: any, fsImpl: any) {
28
+ function usableRoot(root , fsImpl ) {
29
29
  if (!root) return false;
30
30
  const owned = path.basename(root) === 'state' ? path.dirname(root) : root;
31
31
  const parent = stat(owned, fsImpl), info = stat(root, fsImpl);
32
32
  return !!parent?.isDirectory() && !parent.isSymbolicLink() && !!info?.isDirectory() && !info.isSymbolicLink();
33
33
  }
34
- function atomicWrite(file: any, text: any, fsImpl: any, { preserveExisting = false }: any = {}) {
34
+ function atomicWrite(file , text , fsImpl , { preserveExisting = false } = {}) {
35
35
  const temp = `${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
36
36
  try {
37
37
  fsImpl.writeFileSync(temp, text, { flag: 'wx' });
38
38
  if (preserveExisting) {
39
39
  // IC-016: a link never replaces a name, so a file created since the caller's check stays.
40
- try { fsImpl.linkSync(temp, file); } catch (error: any) { if (error.code === 'EEXIST') return false; throw error; }
40
+ try { fsImpl.linkSync(temp, file); } catch (error ) { if (error.code === 'EEXIST') return false; throw error; }
41
41
  return true;
42
42
  }
43
43
  fsImpl.renameSync(temp, file);
@@ -47,7 +47,7 @@ function atomicWrite(file: any, text: any, fsImpl: any, { preserveExisting = fal
47
47
  }
48
48
  }
49
49
  function ignoreBytes() { return `${registry.settings.ignoreFile.lines.join('\n')}\n`; }
50
- function ensureIgnore({ roots, rootId, projectRoot, fsImpl }: any) {
50
+ function ensureIgnore({ roots, rootId, projectRoot, fsImpl } ) {
51
51
  const root = roots[rootId];
52
52
  if (!usableRoot(root, fsImpl)) return;
53
53
  const file = path.join(root, registry.settings.ignoreFile.name);
@@ -64,7 +64,7 @@ function ensureIgnore({ roots, rootId, projectRoot, fsImpl }: any) {
64
64
  * never appended. Its own pass (at most daily) adds it once user state exists, so a global
65
65
  * uninstall can still find its controls (IC-019).
66
66
  */
67
- function registerProject(roots: any, fsImpl: any) {
67
+ function registerProject(roots , fsImpl ) {
68
68
  const projectState = roots['project-state'], userState = roots['user-state'];
69
69
  if (!usableRoot(projectState, fsImpl) || !usableRoot(userState, fsImpl)) return;
70
70
  if (!stat(path.join(projectState, registry.settings.ignoreFile.name), fsImpl)?.isFile()) return;
@@ -75,31 +75,31 @@ function registerProject(roots: any, fsImpl: any) {
75
75
  if ((indexedRoots(index, fsImpl) || []).includes(project)) return;
76
76
  fsImpl.appendFileSync(index, `${project}\n`, 'utf8');
77
77
  }
78
- function indexedRoots(file: any, fsImpl: any) {
78
+ function indexedRoots(file , fsImpl ) {
79
79
  const info = stat(file, fsImpl);
80
80
  if (!info || info.isSymbolicLink() || !info.isFile()) return null;
81
- return fsImpl.readFileSync(file, 'utf8').split('\n').filter((root: any) => path.isAbsolute(root));
81
+ return fsImpl.readFileSync(file, 'utf8').split('\n').filter((root ) => path.isAbsolute(root));
82
82
  }
83
- function rewriteRoots(roots: any, fsImpl: any, forget: any = null) {
83
+ function rewriteRoots(roots , fsImpl , forget = null) {
84
84
  const file = path.join(roots['user-state'], 'upkeep-roots');
85
85
  if (!usableRoot(roots['user-state'], fsImpl)) return;
86
86
  const lines = indexedRoots(file, fsImpl);
87
87
  if (!lines) return;
88
88
  const kept = forget === null
89
89
  ? [...new Set(lines)].filter(root => stat(path.join(root, '.doflow/state/.gitignore'), fsImpl))
90
- : lines.filter((root: any) => root !== forget);
90
+ : lines.filter((root ) => root !== forget);
91
91
  atomicWrite(file, kept.length ? `${kept.join('\n')}\n` : '', fsImpl);
92
92
  }
93
- function due(root: any, now: any, fsImpl: any) {
93
+ function due(root , now , fsImpl ) {
94
94
  try {
95
95
  const text = fsImpl.readFileSync(path.join(root, 'upkeep-due'), 'utf8').trim();
96
96
  return !/^\d+$/.test(text) || !Number.isFinite(Number(text)) || Number(text) * 1000 <= now;
97
97
  } catch { return true; }
98
98
  }
99
- function takeLock(root: any, now: any, fsImpl: any) {
99
+ function takeLock(root , now , fsImpl ) {
100
100
  const lock = path.join(root, 'upkeep.lock');
101
101
  try { fsImpl.mkdirSync(lock); return true; }
102
- catch (error: any) {
102
+ catch (error ) {
103
103
  if (error.code !== 'EEXIST') throw error;
104
104
  const info = stat(lock, fsImpl);
105
105
  if (info?.isDirectory() && !info.isSymbolicLink() && now - info.mtimeMs > registry.settings.passLockStaleSeconds * 1000) {
@@ -108,12 +108,12 @@ function takeLock(root: any, now: any, fsImpl: any) {
108
108
  return false;
109
109
  }
110
110
  }
111
- function writeDue(root: any, time: any, fsImpl: any) {
111
+ function writeDue(root , time , fsImpl ) {
112
112
  const file = path.join(root, 'upkeep-due');
113
113
  if (stat(file, fsImpl)?.isSymbolicLink()) throw new Error('linked upkeep marker');
114
114
  atomicWrite(file, `${Math.floor(time / 1000)}\n`, fsImpl);
115
115
  }
116
- function passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled = false }: any) {
116
+ function passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled = false } ) {
117
117
  const root = roots[rootId];
118
118
  if (!usableRoot(root, fsImpl)) return;
119
119
  const setting = readPruneSetting({ registry, roots, rootId, fsImpl });
@@ -124,7 +124,7 @@ function passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled = fals
124
124
  if (throttled) writeDue(root, now + registry.settings.upkeepIntervalHours * 3600000, fsImpl);
125
125
  ran = true;
126
126
  result = engine.runPass({ registry, roots, stores, mode: 'prune', setting: { [rootId]: 'on' }, now, env, fsImpl });
127
- outcome = result.partial ? 'partial' : result.stores.some((store: any) => store.failed.length) ? 'error' : 'ok';
127
+ outcome = result.partial ? 'partial' : result.stores.some((store ) => store.failed.length) ? 'error' : 'ok';
128
128
  if (rootId === 'user-state') rewriteRoots(roots, fsImpl);
129
129
  if (rootId === 'project-state') { try { registerProject(roots, fsImpl); } catch { /* the index is best effort */ } }
130
130
  } catch { outcome = 'error'; /* the record never includes failure content */ }
@@ -146,7 +146,7 @@ function passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled = fals
146
146
  }
147
147
 
148
148
  /** IC-009: silent throttled upkeep after a verb, using that verb's resolved store root. */
149
- function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs }: any = {}) {
149
+ function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
150
150
  return silently(() => {
151
151
  const roots = resolveRoots({ registry, projectRoot, env });
152
152
  for (const rootId of ['project-state', 'user-state']) {
@@ -156,7 +156,7 @@ function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsI
156
156
  try {
157
157
  const root = roots[rootId];
158
158
  if (!usableRoot(root, fsImpl) || !due(root, now, fsImpl)) continue;
159
- const stores = registry.stores.filter((store: any) => store.root === rootId && store.moments.includes('verb')).map((store: any) => store.id);
159
+ const stores = registry.stores.filter((store ) => store.root === rootId && store.moments.includes('verb')).map((store ) => store.id);
160
160
  passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled: true });
161
161
  } catch { /* one inaccessible root cannot stop the others */ }
162
162
  }
@@ -164,7 +164,7 @@ function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsI
164
164
  }
165
165
 
166
166
  /** IC-010: the verify moment is project-only and unthrottled. Wiring belongs to D.3. */
167
- function upkeepAfterVerify({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs }: any = {}) {
167
+ function upkeepAfterVerify({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
168
168
  return silently(() => {
169
169
  const roots = resolveRoots({ registry, projectRoot, env });
170
170
  return passForRoot({ roots, rootId: 'project-state', stores: ['verification-logs'], now, env, fsImpl });
@@ -172,7 +172,7 @@ function upkeepAfterVerify({ projectRoot, now = Date.now(), env = process.env, f
172
172
  }
173
173
 
174
174
  /** IC-011: only this scope's recovery store; install/update call sites belong to D.4. */
175
- function storageAfterInstall({ scope, scopeRoot, now = Date.now(), env = process.env, fsImpl = fs }: any = {}) {
175
+ function storageAfterInstall({ scope, scopeRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
176
176
  return silently(() => {
177
177
  if (!['project', 'global'].includes(scope)) return;
178
178
  const global = scope === 'global';
@@ -184,20 +184,20 @@ function storageAfterInstall({ scope, scopeRoot, now = Date.now(), env = process
184
184
  }
185
185
 
186
186
  /** IC-019: user-initiated cleanup removes owned controls, never state or user settings. */
187
- function storageForgetScope({ scope, scopeRoot, env = process.env, fsImpl = fs }: any = {}) {
187
+ function storageForgetScope({ scope, scopeRoot, env = process.env, fsImpl = fs } = {}) {
188
188
  const exitCode = process.exitCode;
189
189
  let removed = 0;
190
- const failures: any = [];
191
- const attempt = (file: any, fn: any) => {
192
- try { fn(); } catch (error: any) { if (error.code !== 'ENOENT') failures.push(`${file}: ${error.code || error.message}`); }
190
+ const failures = [];
191
+ const attempt = (file , fn ) => {
192
+ try { fn(); } catch (error ) { if (error.code !== 'ENOENT') failures.push(`${file}: ${error.code || error.message}`); }
193
193
  };
194
- const removeFile = (file: any, exact = false) => attempt(file, () => {
194
+ const removeFile = (file , exact = false) => attempt(file, () => {
195
195
  const info = stat(file, fsImpl);
196
196
  if (!info?.isFile() || info.isSymbolicLink()) return;
197
197
  if (exact && fsImpl.readFileSync(file, 'utf8') !== ignoreBytes()) return;
198
198
  fsImpl.unlinkSync(file); removed++;
199
199
  });
200
- const removeControls = (root: any, ignore = true) => {
200
+ const removeControls = (root , ignore = true) => {
201
201
  if (!usableRoot(root, fsImpl)) return;
202
202
  if (ignore) removeFile(path.join(root, '.gitignore'), true);
203
203
  removeFile(path.join(root, 'upkeep-due'));
@@ -235,7 +235,7 @@ function storageForgetScope({ scope, scopeRoot, env = process.env, fsImpl = fs }
235
235
  }
236
236
  if (failures.length) for (const failure of failures) console.error(`[WARN] Storage: ${failure}`);
237
237
  else if (removed > 0) console.log(`[INFO] Storage: removed ${removed} DoFlow control file(s)`);
238
- } catch (error: any) {
238
+ } catch (error ) {
239
239
  try { console.error(`[WARN] Storage: ${error.code || error.message}`); } catch { /* no exit change */ }
240
240
  } finally { process.exitCode = exitCode; }
241
241
  }
@@ -4,8 +4,8 @@
4
4
 
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
- const { REPO_ROOT } = require('../../helper/repo-root.ts');
8
- const { loadStorageRegistry } = require('./registry.ts');
7
+ const { REPO_ROOT } = require('../../helper/repo-root.js');
8
+ const { loadStorageRegistry } = require('./registry.js');
9
9
 
10
10
  const RUN_STATES = new Set(['RUNNING', 'AWAITING_GATE', 'COMPLETED', 'REJECTED']);
11
11
  const RUN_OPEN_STATES = Object.freeze(['RUNNING', 'AWAITING_GATE']);
@@ -13,18 +13,18 @@ const UNCHECKED = /^\s*- \[ \] /m;
13
13
  const UNCHECKED_TASK = /^\s*- \[ \] (\S+)/gm;
14
14
  const SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15
15
 
16
- function recordStorePaths(fsImpl: any): Map<string, string> {
16
+ function recordStorePaths(fsImpl ) {
17
17
  try {
18
18
  const registry = loadStorageRegistry({ repoRoot: REPO_ROOT, fsImpl });
19
19
  return new Map(registry.stores
20
- .filter((store: any) => store.root === 'project-state' && store.entry === 'record' && store.rule === 'work')
21
- .map((store: any): [string, string] => [store.id, store.path]));
20
+ .filter((store ) => store.root === 'project-state' && store.entry === 'record' && store.rule === 'work')
21
+ .map((store ) => [store.id, store.path]));
22
22
  } catch {
23
23
  return new Map();
24
24
  }
25
25
  }
26
26
 
27
- function createWorkCache({ projectRoot, fsImpl = fs }: { projectRoot: string; fsImpl?: any }): any {
27
+ function createWorkCache({ projectRoot, fsImpl = fs } ) {
28
28
  return {
29
29
  projectRoot: path.resolve(projectRoot),
30
30
  fsImpl,
@@ -43,38 +43,38 @@ function createWorkCache({ projectRoot, fsImpl = fs }: { projectRoot: string; fs
43
43
  * plan and listing, so the recheck reads the work's current run and plan rather than the snapshot
44
44
  * taken at selection. A run reopened or a plan task unchecked after selection keeps the record.
45
45
  */
46
- function refreshedWorkCache(cache: any): any {
46
+ function refreshedWorkCache(cache ) {
47
47
  return { ...cache, runNames: null, runListError: false, featureNames: null, featureListError: false,
48
48
  runs: new Map(), plans: new Map() };
49
49
  }
50
50
 
51
- function cacheFor({ projectRoot, fsImpl, cache }: { projectRoot: string; fsImpl: any; cache?: any }): any {
51
+ function cacheFor({ projectRoot, fsImpl, cache } ) {
52
52
  const resolved = path.resolve(projectRoot);
53
53
  if (cache && cache.projectRoot === resolved && cache.fsImpl === fsImpl
54
54
  && cache.recordStorePaths instanceof Map && cache.runs instanceof Map && cache.plans instanceof Map) return cache;
55
55
  return createWorkCache({ projectRoot: resolved, fsImpl });
56
56
  }
57
57
 
58
- function stateRoot(projectRoot: string): string {
58
+ function stateRoot(projectRoot ) {
59
59
  return path.join(projectRoot, '.doflow', 'state');
60
60
  }
61
61
 
62
- function safeSegment(value: any): boolean {
62
+ function safeSegment(value ) {
63
63
  return typeof value === 'string' && SAFE_SEGMENT.test(value) && !value.includes('..');
64
64
  }
65
65
 
66
- function listRunNames(cache: any, shouldStop?: () => boolean): { names: string[]; incomplete: boolean } {
66
+ function listRunNames(cache , shouldStop ) {
67
67
  if (shouldStop?.()) return { names: [], incomplete: true };
68
68
  if (cache.runNames !== null) return { names: cache.runNames, incomplete: false };
69
69
  const dir = path.join(stateRoot(cache.projectRoot), 'orchestration');
70
- let entries: any[];
70
+ let entries ;
71
71
  try { entries = cache.fsImpl.readdirSync(dir, { withFileTypes: true }); }
72
- catch (error: any) {
72
+ catch (error ) {
73
73
  if (error?.code === 'ENOENT') entries = [];
74
74
  else { cache.runNames = []; cache.runListError = true; return { names: cache.runNames, incomplete: false }; }
75
75
  }
76
76
  if (shouldStop?.()) return { names: [], incomplete: true };
77
- const names: string[] = [];
77
+ const names = [];
78
78
  for (const entry of entries) {
79
79
  if (shouldStop?.()) return { names: [], incomplete: true };
80
80
  if (entry.name.endsWith('.json')) names.push(entry.name.slice(0, -5));
@@ -84,10 +84,10 @@ function listRunNames(cache: any, shouldStop?: () => boolean): { names: string[]
84
84
  return { names, incomplete: false };
85
85
  }
86
86
 
87
- function readRun(cache: any, runId: string): any {
87
+ function readRun(cache , runId ) {
88
88
  if (cache.runs.has(runId)) return cache.runs.get(runId);
89
89
  const file = path.join(stateRoot(cache.projectRoot), 'orchestration', `${runId}.json`);
90
- let result: any;
90
+ let result ;
91
91
  try {
92
92
  const value = JSON.parse(cache.fsImpl.readFileSync(file, 'utf8'));
93
93
  result = value && typeof value === 'object' && !Array.isArray(value) && RUN_STATES.has(value.state)
@@ -100,11 +100,11 @@ function readRun(cache: any, runId: string): any {
100
100
  return result;
101
101
  }
102
102
 
103
- function resolveRun(cache: any, taskId: string, namespace: any, shouldStop?: () => boolean): any {
103
+ function resolveRun(cache , taskId , namespace , shouldStop ) {
104
104
  const listed = listRunNames(cache, shouldStop);
105
105
  if (listed.incomplete) return { id: null, unreadable: false, incomplete: true };
106
106
  if (cache.runListError) return { id: null, unreadable: true };
107
- let exact = false, namespaced = false, prefix: string | null = null;
107
+ let exact = false, namespaced = false, prefix = null;
108
108
  for (const candidate of listed.names) {
109
109
  if (shouldStop?.()) return { id: null, unreadable: false, incomplete: true };
110
110
  if (candidate === taskId) exact = true;
@@ -120,9 +120,9 @@ function resolveRun(cache: any, taskId: string, namespace: any, shouldStop?: ()
120
120
  return read.ok ? { id, value: read.value, unreadable: false } : { id, value: null, unreadable: true };
121
121
  }
122
122
 
123
- function readRecord({ projectRoot, storePath, recordId, namespace, mtimeMs, fsImpl }: any): any {
123
+ function readRecord({ projectRoot, storePath, recordId, namespace, mtimeMs, fsImpl } ) {
124
124
  const storeSegments = typeof storePath === 'string' && storePath !== '' ? storePath.split('/') : [];
125
- if (typeof storePath !== 'string' || storeSegments.some((segment: string) => !safeSegment(segment))
125
+ if (typeof storePath !== 'string' || storeSegments.some((segment ) => !safeSegment(segment))
126
126
  || !safeSegment(recordId)
127
127
  || (namespace !== null && namespace !== undefined && !safeSegment(namespace))) {
128
128
  return { ok: false };
@@ -138,18 +138,18 @@ function readRecord({ projectRoot, storePath, recordId, namespace, mtimeMs, fsIm
138
138
  }
139
139
  }
140
140
 
141
- function listFeatureNames(cache: any, shouldStop?: () => boolean): { names: string[]; incomplete: boolean } {
141
+ function listFeatureNames(cache , shouldStop ) {
142
142
  if (shouldStop?.()) return { names: [], incomplete: true };
143
143
  if (cache.featureNames !== null) return { names: cache.featureNames, incomplete: false };
144
144
  const dir = path.join(cache.projectRoot, 'agent-docs', 'doflow');
145
- let entries: any[];
145
+ let entries ;
146
146
  try { entries = cache.fsImpl.readdirSync(dir, { withFileTypes: true }); }
147
- catch (error: any) {
147
+ catch (error ) {
148
148
  if (error?.code === 'ENOENT') entries = [];
149
149
  else { cache.featureNames = []; cache.featureListError = true; return { names: cache.featureNames, incomplete: false }; }
150
150
  }
151
151
  if (shouldStop?.()) return { names: [], incomplete: true };
152
- const names: string[] = [];
152
+ const names = [];
153
153
  for (const entry of entries) {
154
154
  if (shouldStop?.()) return { names: [], incomplete: true };
155
155
  if (entry.isDirectory() && safeSegment(entry.name)) names.push(entry.name);
@@ -159,10 +159,10 @@ function listFeatureNames(cache: any, shouldStop?: () => boolean): { names: stri
159
159
  return { names, incomplete: false };
160
160
  }
161
161
 
162
- function featureFromFolders(cache: any, taskId: string, shouldStop?: () => boolean): { feature: string | null; incomplete: boolean } {
162
+ function featureFromFolders(cache , taskId , shouldStop ) {
163
163
  const listed = listFeatureNames(cache, shouldStop);
164
164
  if (listed.incomplete) return { feature: null, incomplete: true };
165
- let best: string | null = null;
165
+ let best = null;
166
166
  for (const name of listed.names) {
167
167
  if (shouldStop?.()) return { feature: null, incomplete: true };
168
168
  if ((taskId === name || taskId.startsWith(`${name}-`) || taskId.startsWith(`${name}.`))
@@ -171,18 +171,18 @@ function featureFromFolders(cache: any, taskId: string, shouldStop?: () => boole
171
171
  return { feature: best, incomplete: false };
172
172
  }
173
173
 
174
- function stringField(record: any, field: string): string | null {
174
+ function stringField(record , field ) {
175
175
  const value = record && typeof record === 'object' ? record[field] : null;
176
176
  return typeof value === 'string' && value !== '' ? value : null;
177
177
  }
178
178
 
179
179
  /** true, false when the folder is definitely absent, or null when it cannot be told. */
180
- function folderExists(fsImpl: any, folder: string): boolean | null {
180
+ function folderExists(fsImpl , folder ) {
181
181
  try { fsImpl.lstatSync(folder); return true; }
182
- catch (error: any) { return error?.code === 'ENOENT' || error?.code === 'ENOTDIR' ? false : null; }
182
+ catch (error ) { return error?.code === 'ENOENT' || error?.code === 'ENOTDIR' ? false : null; }
183
183
  }
184
184
 
185
- function readPlan(cache: any, feature: string, shouldStop?: () => boolean): any {
185
+ function readPlan(cache , feature , shouldStop ) {
186
186
  if (shouldStop?.()) return { exists: false, ok: false, text: null, incomplete: true };
187
187
  if (cache.plans.has(feature)) return cache.plans.get(feature);
188
188
  if (!safeSegment(feature)) {
@@ -191,10 +191,10 @@ function readPlan(cache: any, feature: string, shouldStop?: () => boolean): any
191
191
  return invalid;
192
192
  }
193
193
  const folder = path.join(cache.projectRoot, 'agent-docs', 'doflow', feature);
194
- let result: any;
194
+ let result ;
195
195
  try {
196
196
  result = { exists: true, ok: true, text: cache.fsImpl.readFileSync(path.join(folder, 'plan.md'), 'utf8'), folder: true };
197
- } catch (error: any) {
197
+ } catch (error ) {
198
198
  result = error?.code === 'ENOENT'
199
199
  ? { exists: false, ok: true, text: null, folder: folderExists(cache.fsImpl, folder) }
200
200
  : { exists: true, ok: false, text: null };
@@ -205,7 +205,7 @@ function readPlan(cache: any, feature: string, shouldStop?: () => boolean): any
205
205
  return result;
206
206
  }
207
207
 
208
- function planWithUncheckedTask(cache: any, taskId: string, shouldStop?: () => boolean): any {
208
+ function planWithUncheckedTask(cache , taskId , shouldStop ) {
209
209
  const listed = listFeatureNames(cache, shouldStop);
210
210
  if (listed.incomplete) return { found: false, unreadable: false, incomplete: true };
211
211
  if (cache.featureListError) return { found: false, unreadable: true };
@@ -216,7 +216,7 @@ function planWithUncheckedTask(cache: any, taskId: string, shouldStop?: () => bo
216
216
  if (!plan.ok) return { found: false, unreadable: true };
217
217
  if (!plan.exists) continue;
218
218
  UNCHECKED_TASK.lastIndex = 0;
219
- let match: RegExpExecArray | null;
219
+ let match ;
220
220
  while ((match = UNCHECKED_TASK.exec(plan.text)) !== null) {
221
221
  if (shouldStop?.()) return { found: false, unreadable: false, incomplete: true };
222
222
  if (match[1] === taskId) return { found: true, unreadable: false };
@@ -226,11 +226,11 @@ function planWithUncheckedTask(cache: any, taskId: string, shouldStop?: () => bo
226
226
  return { found: false, unreadable: false };
227
227
  }
228
228
 
229
- function answer(state: string, reason: string, run: any, feature: any, since: number | null = null): any {
229
+ function answer(state , reason , run , feature , since = null) {
230
230
  return { state, since, reason, run, feature };
231
231
  }
232
232
 
233
- function incompleteAnswer(run: any = null, feature: any = null): any {
233
+ function incompleteAnswer(run = null, feature = null) {
234
234
  return { ...answer('undecidable', 'pass-budget-exhausted', run, feature), incomplete: true };
235
235
  }
236
236
 
@@ -242,7 +242,7 @@ function incompleteAnswer(run: any = null, feature: any = null): any {
242
242
  */
243
243
  function workStatus({
244
244
  projectRoot, store, taskId, namespace = null, mtimeMs, cache, fsImpl, shouldStop,
245
- }: any): any {
245
+ } ) {
246
246
  const project = path.resolve(projectRoot);
247
247
  const fileSystem = fsImpl || cache?.fsImpl || fs;
248
248
  const pass = cacheFor({ projectRoot: project, fsImpl: fileSystem, cache });
@@ -262,7 +262,7 @@ function workStatus({
262
262
  // path. An orchestration record is also its exact run file, so reuse the cached parse rather than
263
263
  // reading that file twice.
264
264
  const storePath = pass.recordStorePaths.get(store);
265
- let record: any;
265
+ let record ;
266
266
  if (storePath === 'orchestration' && !namespace && recordId === workId && resolvedRun.id === workId && run) {
267
267
  try {
268
268
  const file = path.join(stateRoot(project), storePath, `${recordId}.json`);
@@ -285,7 +285,7 @@ function workStatus({
285
285
  }
286
286
 
287
287
  // W5: feature metadata is ordered; folder-name inference is the final fallback.
288
- let feature: string | null = stringField(run, 'featureSlug')
288
+ let feature = stringField(run, 'featureSlug')
289
289
  || stringField(record.value, 'featureSlug')
290
290
  || stringField(record.value, 'slug')
291
291
  || (safeSegment(namespace) ? namespace : null);