@khoavu882/doflow 2.0.0-beta.3 → 2.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/bin/doflow.js +2 -2
  2. package/core/.antigravity-plugin/plugin.json +0 -1
  3. package/core/.claude-plugin/plugin.json +1 -1
  4. package/core/.codex-plugin/plugin.json +1 -1
  5. package/core/.plugin/plugin.json +1 -1
  6. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  7. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  8. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  9. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  10. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  11. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  12. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  13. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  14. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  15. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  16. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  17. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  18. package/core/harnesses/codex/hooks/subagent-audit.sh +17 -6
  19. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  20. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +7 -18
  21. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +7 -18
  22. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +7 -19
  23. package/core/harnesses/gemini/hooks/session-start.sh +5 -3
  24. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +20 -5
  25. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +20 -5
  26. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +20 -5
  27. package/core/harnesses/kiro/hooks/session-start.sh +11 -5
  28. package/core/harnesses/kiro/hooks/stop-check.sh +21 -30
  29. package/core/harnesses/pi/extensions/doflow-guard.js +159 -0
  30. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -11
  31. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  32. package/core/harnesses/shared/hooks/bridge/bridge.sh +184 -0
  33. package/core/harnesses/shared/hooks/bridge/envelope.jq +60 -0
  34. package/core/harnesses/shared/hooks/bridge/respond.sh +62 -0
  35. package/core/harnesses/shared/hooks/policies/capture-failure.sh +4 -2
  36. package/core/harnesses/shared/hooks/policies/contract.sh +75 -0
  37. package/core/harnesses/shared/hooks/policies/deny-json.sh +39 -4
  38. package/core/harnesses/shared/hooks/policies/lib.sh +4 -2
  39. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +46 -34
  40. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +75 -25
  41. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +67 -73
  42. package/core/harnesses/shared/hooks/policies/session-context.sh +37 -7
  43. package/core/harnesses/shared/hooks/policies/stop-check.sh +42 -15
  44. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +35 -5
  45. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +40 -7
  46. package/core/harnesses/shared/hooks/stream-hook-runner.js +69 -181
  47. package/core/registry/assets.json +19 -0
  48. package/core/registry/contracts.json +2 -2
  49. package/core/registry/harnesses.json +196 -10
  50. package/core/registry/lifecycle.json +2626 -7
  51. package/core/registry/storage.json +110 -83
  52. package/core/registry/verification.json +1 -1
  53. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
  54. package/core/shared/scripts/doflow/bin/doflow-run +10 -6
  55. package/core/shared/skills/do-design/SKILL.md +6 -6
  56. package/core/shared/skills/do-execute-plan/SKILL.md +11 -10
  57. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +2 -0
  58. package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
  59. package/core/shared/skills/do-implement/SKILL.md +3 -2
  60. package/core/shared/skills/do-plan/SKILL.md +7 -8
  61. package/package.json +4 -2
  62. package/src/adapters/antigravity/{index.ts → index.js} +141 -105
  63. package/src/adapters/claude/{index.ts → index.js} +63 -49
  64. package/src/adapters/claude/{mcp.ts → mcp.js} +16 -16
  65. package/src/adapters/codex/{agents.ts → agents.js} +24 -24
  66. package/src/adapters/codex/{config.ts → config.js} +49 -49
  67. package/src/adapters/codex/{hooks.ts → hooks.js} +62 -27
  68. package/src/adapters/codex/{index.ts → index.js} +148 -105
  69. package/src/adapters/codex/{mcp.ts → mcp.js} +38 -38
  70. package/src/adapters/codex/{native-projection.ts → native-projection.js} +5 -5
  71. package/src/adapters/copilot/{index.ts → index.js} +42 -42
  72. package/src/adapters/{copy-tree.ts → copy-tree.js} +74 -74
  73. package/src/adapters/gemini/{hooks.ts → hooks.js} +78 -37
  74. package/src/adapters/gemini/{index.ts → index.js} +96 -57
  75. package/src/adapters/{hook-commands.ts → hook-commands.js} +8 -8
  76. package/src/adapters/{index.ts → index.js} +13 -13
  77. package/src/adapters/kiro/{index.ts → index.js} +49 -35
  78. package/src/adapters/{mcp-entries.ts → mcp-entries.js} +55 -55
  79. package/src/adapters/opencode/{index.ts → index.js} +52 -52
  80. package/src/adapters/pi/hooks.js +119 -0
  81. package/src/adapters/pi/{index.ts → index.js} +64 -39
  82. package/src/adapters/pi/{json-members.ts → json-members.js} +23 -23
  83. package/src/adapters/pi/{mcp.ts → mcp.js} +70 -70
  84. package/src/adapters/{resolve-source.ts → resolve-source.js} +1 -1
  85. package/src/cli/commands/{install.ts → install.js} +25 -25
  86. package/src/cli/commands/{list-backups.ts → list-backups.js} +4 -4
  87. package/src/cli/commands/{reconcile.ts → reconcile.js} +19 -19
  88. package/src/cli/commands/{remove.ts → remove.js} +10 -10
  89. package/src/cli/commands/{rollback.ts → rollback.js} +17 -17
  90. package/src/cli/commands/{self-update.ts → self-update.js} +3 -3
  91. package/src/cli/commands/{status.ts → status.js} +24 -24
  92. package/src/cli/commands/{tools.ts → tools.js} +16 -16
  93. package/src/cli/commands/{update.ts → update.js} +20 -20
  94. package/src/cli/{index.ts → index.js} +43 -31
  95. package/src/cli/{runtime-commands.ts → runtime-commands.js} +97 -58
  96. package/src/cli/{shared.ts → shared.js} +40 -40
  97. package/src/helper/{bash-helper.ts → bash-helper.js} +7 -7
  98. package/src/helper/{git.ts → git.js} +2 -2
  99. package/src/helper/{guardrails.ts → guardrails.js} +10 -10
  100. package/src/helper/{harness-paths.ts → harness-paths.js} +24 -24
  101. package/src/helper/{marker-merge.ts → marker-merge.js} +4 -4
  102. package/src/helper/{prompt.ts → prompt.js} +5 -5
  103. package/src/helper/{repo-root.ts → repo-root.js} +2 -2
  104. package/src/helper/{settings-merge.ts → settings-merge.js} +27 -27
  105. package/src/helper/{settings-scope.ts → settings-scope.js} +3 -3
  106. package/src/helper/{toml.ts → toml.js} +48 -48
  107. package/src/install/{backup-set.ts → backup-set.js} +16 -16
  108. package/src/install/{backup.ts → backup.js} +65 -65
  109. package/src/install/{context.ts → context.js} +15 -15
  110. package/src/install/{manifest.ts → manifest.js} +27 -27
  111. package/src/install/{mcp.ts → mcp.js} +30 -30
  112. package/src/install/{paths.ts → paths.js} +15 -15
  113. package/src/install/{targets.ts → targets.js} +10 -10
  114. package/src/install/{tool-lifecycle.ts → tool-lifecycle.js} +20 -20
  115. package/src/lifecycle/{bash-availability.ts → bash-availability.js} +1 -1
  116. package/src/lifecycle/coverage.js +57 -0
  117. package/src/lifecycle/hook-step.js +61 -0
  118. package/src/lifecycle/{index.ts → index.js} +160 -146
  119. package/src/lifecycle/{mcp-index.ts → mcp-index.js} +1 -1
  120. package/src/lifecycle/{policies.ts → policies.js} +11 -11
  121. package/src/lifecycle/{view.ts → view.js} +28 -28
  122. package/src/registry/{index.ts → index.js} +195 -66
  123. package/src/release/build-package.js +91 -0
  124. package/src/release/changelog-section.js +70 -0
  125. package/src/release/{sync-plugin-versions.ts → sync-plugin-versions.js} +4 -4
  126. package/src/runtime/advice/{cli.ts → cli.js} +31 -31
  127. package/src/runtime/advice/{client.ts → client.js} +44 -44
  128. package/src/runtime/advice/{config.ts → config.js} +16 -16
  129. package/src/runtime/advice/{doctor.ts → doctor.js} +32 -32
  130. package/src/runtime/advice/{endpoint-guard.ts → endpoint-guard.js} +20 -20
  131. package/src/runtime/advice/{kinds.ts → kinds.js} +16 -16
  132. package/src/runtime/advice/providers/{ollama-systemone.ts → ollama-systemone.js} +21 -21
  133. package/src/runtime/advice/{record.ts → record.js} +19 -19
  134. package/src/runtime/advice/{registry.ts → registry.js} +16 -16
  135. package/src/runtime/advice/{strength.ts → strength.js} +7 -7
  136. package/src/runtime/{brief-tools.ts → brief-tools.js} +50 -50
  137. package/src/runtime/{c4-project.ts → c4-project.js} +27 -27
  138. package/src/runtime/candidate.js +505 -0
  139. package/src/runtime/{capability-router.ts → capability-router.js} +39 -39
  140. package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
  141. package/src/runtime/{claims.ts → claims.js} +44 -35
  142. package/src/runtime/{cli-result.ts → cli-result.js} +15 -8
  143. package/src/runtime/{cli.ts → cli.js} +59 -292
  144. package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
  145. package/src/runtime/context/budget.js +203 -0
  146. package/src/runtime/context/compose.js +1367 -0
  147. package/src/runtime/context/delivery-store.js +102 -0
  148. package/src/runtime/context/mandatory.js +594 -0
  149. package/src/runtime/context/pointer.js +142 -0
  150. package/src/runtime/context-pack.js +1277 -0
  151. package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
  152. package/src/runtime/evidence-fields.js +39 -0
  153. package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +32 -25
  154. package/src/runtime/failure/{capture.ts → capture.js} +29 -29
  155. package/src/runtime/failure/{classifier.ts → classifier.js} +4 -4
  156. package/src/runtime/failure/{cli.ts → cli.js} +30 -30
  157. package/src/runtime/failure/{home.ts → home.js} +6 -6
  158. package/src/runtime/failure/{store.ts → store.js} +32 -32
  159. package/src/runtime/{feature-resolve.ts → feature-resolve.js} +6 -6
  160. package/src/runtime/{freshness.ts → freshness.js} +59 -22
  161. package/src/runtime/{health.ts → health.js} +72 -72
  162. package/src/runtime/{history-compactor.ts → history-compactor.js} +25 -25
  163. package/src/runtime/{implementation-gate.ts → implementation-gate.js} +30 -30
  164. package/src/runtime/inventory/{coverage.ts → coverage.js} +10 -10
  165. package/src/runtime/inventory/{identity.ts → identity.js} +2 -2
  166. package/src/runtime/inventory/{index.ts → index.js} +36 -36
  167. package/src/runtime/inventory/{precedence.ts → precedence.js} +2 -2
  168. package/src/runtime/inventory/{read-scopes.ts → read-scopes.js} +9 -9
  169. package/src/runtime/inventory/{siblings.ts → siblings.js} +15 -15
  170. package/src/runtime/knowledge/{chunker.ts → chunker.js} +12 -12
  171. package/src/runtime/knowledge/{hybrid.ts → hybrid.js} +17 -17
  172. package/src/runtime/knowledge/{index-store.ts → index-store.js} +23 -23
  173. package/src/runtime/knowledge/{retrieval.ts → retrieval.js} +27 -27
  174. package/src/runtime/{leak-scan.ts → leak-scan.js} +12 -12
  175. package/src/runtime/lifecycle/{cli.ts → cli.js} +32 -32
  176. package/src/runtime/lifecycle/{event-store.ts → event-store.js} +48 -48
  177. package/src/runtime/lifecycle/{fold.ts → fold.js} +41 -41
  178. package/src/runtime/lifecycle/{followup.ts → followup.js} +54 -54
  179. package/src/runtime/lifecycle/{goal.ts → goal.js} +50 -50
  180. package/src/runtime/lifecycle/{intent-writer.ts → intent-writer.js} +5 -5
  181. package/src/runtime/lifecycle/{overview.ts → overview.js} +47 -47
  182. package/src/runtime/lifecycle/{release.ts → release.js} +29 -29
  183. package/src/runtime/lifecycle/{report-store.ts → report-store.js} +25 -25
  184. package/src/runtime/lifecycle/{retention.ts → retention.js} +37 -37
  185. package/src/runtime/lifecycle/{root.ts → root.js} +9 -9
  186. package/src/runtime/lifecycle/{status.ts → status.js} +64 -64
  187. package/src/runtime/lifecycle/{store-upkeep.ts → store-upkeep.js} +46 -46
  188. package/src/runtime/{locator-resolve.ts → locator-resolve.js} +7 -7
  189. package/src/runtime/{mask.ts → mask.js} +22 -22
  190. package/src/runtime/{mcp-consultations.ts → mcp-consultations.js} +54 -54
  191. package/src/runtime/{mcp-reach.ts → mcp-reach.js} +24 -24
  192. package/src/runtime/{model-router.ts → model-router.js} +20 -20
  193. package/src/runtime/{outcome.ts → outcome.js} +27 -27
  194. package/src/runtime/{reach.ts → reach.js} +21 -21
  195. package/src/runtime/{readiness-record.ts → readiness-record.js} +12 -12
  196. package/src/runtime/{readiness.ts → readiness.js} +113 -43
  197. package/src/runtime/{recovery.ts → recovery.js} +15 -15
  198. package/src/runtime/{research-request.ts → research-request.js} +34 -34
  199. package/src/runtime/{retrieval-plan.ts → retrieval-plan.js} +453 -104
  200. package/src/runtime/retrieval-record.js +223 -0
  201. package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +22 -19
  202. package/src/runtime/scaffold/{fingerprint.ts → fingerprint.js} +3 -3
  203. package/src/runtime/scaffold/{generate.ts → generate.js} +109 -109
  204. package/src/runtime/scaffold/{languages.ts → languages.js} +34 -34
  205. package/src/runtime/source-version.js +289 -0
  206. package/src/runtime/storage/{cli.ts → cli.js} +9 -9
  207. package/src/runtime/storage/{engine.ts → engine.js} +37 -37
  208. package/src/runtime/storage/{registry.ts → registry.js} +19 -19
  209. package/src/runtime/storage/{roots.ts → roots.js} +8 -8
  210. package/src/runtime/storage/{rules.ts → rules.js} +26 -26
  211. package/src/runtime/storage/{upkeep.ts → upkeep.js} +35 -35
  212. package/src/runtime/storage/{work-status.ts → work-status.js} +39 -39
  213. package/src/runtime/{task-attempts.ts → task-attempts.js} +62 -62
  214. package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
  215. package/src/runtime/{task-scope.ts → task-scope.js} +40 -15
  216. package/src/runtime/{task-state.ts → task-state.js} +86 -21
  217. package/src/runtime/trace/{indicators.ts → indicators.js} +22 -22
  218. package/src/runtime/trace/{ledger.ts → ledger.js} +42 -42
  219. package/src/runtime/trace/{render.ts → render.js} +7 -7
  220. package/src/runtime/trace/{views.ts → views.js} +40 -40
  221. package/src/runtime/verification/{contract-runner.ts → contract-runner.js} +23 -23
  222. package/src/runtime/verification/{engine.ts → engine.js} +143 -143
  223. package/src/runtime/verification/{registry.ts → registry.js} +6 -6
  224. package/src/runtime/verification/{scope-bound.ts → scope-bound.js} +50 -50
  225. package/src/runtime/verification/{test-selection.ts → test-selection.js} +28 -28
  226. package/src/runtime/{workflow-engine.ts → workflow-engine.js} +50 -50
  227. package/src/runtime/{workflow-orchestrator.ts → workflow-orchestrator.js} +91 -91
  228. package/src/runtime/{worktree.ts → worktree.js} +31 -31
  229. package/src/state/{index.ts → index.js} +26 -26
  230. package/src/state/{lockfile.ts → lockfile.js} +20 -20
  231. package/src/state/{run-lock.ts → run-lock.js} +44 -44
  232. package/core/.antigravity-plugin/hooks.json +0 -39
  233. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  234. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  235. package/core/harnesses/shared/hooks/hooks.json +0 -47
  236. package/src/runtime/context-pack.ts +0 -492
@@ -5,26 +5,26 @@
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
7
  const { randomBytes } = require('node:crypto');
8
- const { formatBound } = require('./registry.ts');
9
- const { resolveStorePath } = require('./roots.ts');
10
- const { selectCandidates, recordStillCandidate, protectedLogs, removableRules, ruleOrder, projectRoot } = require('./rules.ts');
11
- const { retainLocked } = require('../lifecycle/store-upkeep.ts');
12
- const { parseWindow, selectExpired } = require('../lifecycle/retention.ts');
13
- const { readEvents } = require('../lifecycle/event-store.ts');
14
- const { createWorkCache } = require('./work-status.ts');
15
- const { projectKey } = require('../lifecycle/report-store.ts');
8
+ const { formatBound } = require('./registry.js');
9
+ const { resolveStorePath } = require('./roots.js');
10
+ const { selectCandidates, recordStillCandidate, protectedLogs, removableRules, ruleOrder, projectRoot } = require('./rules.js');
11
+ const { retainLocked } = require('../lifecycle/store-upkeep.js');
12
+ const { parseWindow, selectExpired } = require('../lifecycle/retention.js');
13
+ const { readEvents } = require('../lifecycle/event-store.js');
14
+ const { createWorkCache } = require('./work-status.js');
15
+ const { projectKey } = require('../lifecycle/report-store.js');
16
16
  const SAFE_NAMESPACE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
17
17
  const TOMBSTONE = /^\.[A-Za-z0-9][A-Za-z0-9._-]*\.pruning-[0-9]+-[0-9a-f]{8}$/;
18
18
 
19
- function stat(fsImpl: any,file: any) { try { return fsImpl.lstatSync(file); } catch { return null; } }
20
- function ownedPathLinked(store: any,roots: any,fsImpl: any) {
19
+ function stat(fsImpl ,file ) { try { return fsImpl.lstatSync(file); } catch { return null; } }
20
+ function ownedPathLinked(store ,roots ,fsImpl ) {
21
21
  const root=roots[store.root]; if (!root) return false;
22
22
  const owned=path.basename(root)==='doflow' || path.basename(root)==='.doflow' ? root : path.dirname(root);
23
- for (const dir of [owned,...(store.path ? [root,...store.path.split('/').reduce((a: any,part: any)=>{a.push(path.join(a.at(-1)||root,part));return a;},[])] : [root])])
23
+ for (const dir of [owned,...(store.path ? [root,...store.path.split('/').reduce((a ,part )=>{a.push(path.join(a.at(-1)||root,part));return a;},[])] : [root])])
24
24
  if (stat(fsImpl,dir)?.isSymbolicLink()) return true;
25
25
  return false;
26
26
  }
27
- function inventory(store: any,storeDir: any,fsImpl: any,shouldStop: any) {
27
+ function inventory(store ,storeDir ,fsImpl ,shouldStop ) {
28
28
  const match=new RegExp(store.match), entries=[];
29
29
  for (const name of fsImpl.readdirSync(storeDir)) {
30
30
  if (shouldStop?.()) return null;
@@ -39,7 +39,7 @@ function inventory(store: any,storeDir: any,fsImpl: any,shouldStop: any) {
39
39
  }
40
40
  return entries;
41
41
  }
42
- function sweepTombstones(fsImpl: any,storeDir: any,row: any) {
42
+ function sweepTombstones(fsImpl ,storeDir ,row ) {
43
43
  for (const name of fsImpl.readdirSync(storeDir)) {
44
44
  if (!TOMBSTONE.test(name)) continue;
45
45
  const target=path.join(storeDir,name);
@@ -49,13 +49,13 @@ function sweepTombstones(fsImpl: any,storeDir: any,row: any) {
49
49
  // Node's recursive rm removes nested links themselves, never their referents.
50
50
  fsImpl.rmSync(target,{recursive:true});
51
51
  row.removed++;
52
- } catch (error: any) {
52
+ } catch (error ) {
53
53
  if (error.code==='ENOENT') row.removed++;
54
54
  else row.failed.push({name,code:error.code || 'EIO'});
55
55
  }
56
56
  }
57
57
  }
58
- function removalOrder(candidates: any) {
58
+ function removalOrder(candidates ) {
59
59
  const oldest=[...candidates].sort((a,b)=>a.mtimeMs-b.mtimeMs || a.name.localeCompare(b.name));
60
60
  const byName=new Map(oldest.map(candidate=>[candidate.name,candidate])), emitted=new Set(), ordered=[];
61
61
  for (const candidate of oldest) {
@@ -67,9 +67,9 @@ function removalOrder(candidates: any) {
67
67
  }
68
68
  return ordered;
69
69
  }
70
- function removeOne(fsImpl: any,storeDir: any,candidate: any,store: any,context: any) {
70
+ function removeOne(fsImpl ,storeDir ,candidate ,store ,context ) {
71
71
  const parts=candidate.name.split('/');
72
- if (parts.length>2 || parts.some((part: any)=>!part || part==='.' || part==='..')) throw Object.assign(new Error('unsafe name'),{code:'EINVAL'});
72
+ if (parts.length>2 || parts.some((part )=>!part || part==='.' || part==='..')) throw Object.assign(new Error('unsafe name'),{code:'EINVAL'});
73
73
  const target=path.join(storeDir,...parts), lock=`${target}.lock`;
74
74
  let locked=false;
75
75
  try {
@@ -79,7 +79,7 @@ function removeOne(fsImpl: any,storeDir: any,candidate: any,store: any,context:
79
79
  }
80
80
  if (store.entry==='record') {
81
81
  try { fsImpl.mkdirSync(lock); locked=true; }
82
- catch(error: any) { if (error.code==='EEXIST') return false; throw error; }
82
+ catch(error ) { if (error.code==='EEXIST') return false; throw error; }
83
83
  }
84
84
  const info=fsImpl.lstatSync(target);
85
85
  if (info.isSymbolicLink()) return false;
@@ -104,14 +104,14 @@ function removeOne(fsImpl: any,storeDir: any,candidate: any,store: any,context:
104
104
  } else if (info.isFile()) fsImpl.unlinkSync(target);
105
105
  else return false;
106
106
  return true;
107
- } catch(error: any) { if (error.code==='ENOENT') return true; throw error; }
107
+ } catch(error ) { if (error.code==='ENOENT') return true; throw error; }
108
108
  finally {
109
109
  if (locked) {
110
- try { fsImpl.rmdirSync(lock); } catch(error: any) { if (error.code!=='ENOENT') throw error; }
110
+ try { fsImpl.rmdirSync(lock); } catch(error ) { if (error.code!=='ENOENT') throw error; }
111
111
  }
112
112
  }
113
113
  }
114
- function cleanEmptyNamespace(fsImpl: any,storeDir: any,name: any,report = false) {
114
+ function cleanEmptyNamespace(fsImpl ,storeDir ,name ,report = false) {
115
115
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) return;
116
116
  const dir=path.join(storeDir,name);
117
117
  try {
@@ -119,7 +119,7 @@ function cleanEmptyNamespace(fsImpl: any,storeDir: any,name: any,report = false)
119
119
  fsImpl.rmdirSync(dir);
120
120
  } catch { /* another record, or an active writer */ }
121
121
  }
122
- function projectKeyMarker(fsImpl: any,storeDir: any,roots: any) {
122
+ function projectKeyMarker(fsImpl ,storeDir ,roots ) {
123
123
  const project=projectRoot(roots);
124
124
  if (!project) return;
125
125
  let key;
@@ -129,15 +129,15 @@ function projectKeyMarker(fsImpl: any,storeDir: any,roots: any) {
129
129
  try { fsImpl.writeFileSync(path.join(dir,'.root'),`${fsImpl.realpathSync(project)}\n`,{flag:'wx'}); } catch { /* best effort */ }
130
130
  }
131
131
  /** A bounded pass over registry-declared stores; report mode never writes. */
132
- function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,maxRemovals,env=process.env,fsImpl=fs}: any) {
132
+ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,maxRemovals,env=process.env,fsImpl=fs} ) {
133
133
  if (mode!=='report' && mode!=='prune') throw new Error('Storage pass mode must be report or prune');
134
134
  const started=performance.now(), budget=budgetMs===undefined?(mode==='report'?Infinity:registry.settings.passBudgetMs):budgetMs;
135
135
  const cap=maxRemovals===undefined?registry.settings.maxRemovalsPerPass:maxRemovals;
136
- const requested=new Set(stores || registry.stores.filter((s: any)=>removableRules.has(s.rule)).map((s: any)=>s.id));
136
+ const requested=new Set(stores || registry.stores.filter((s )=>removableRules.has(s.rule)).map((s )=>s.id));
137
137
  const ordered=[...registry.stores].filter(s=>requested.has(s.id) && removableRules.has(s.rule))
138
138
  .sort((a,b)=>ruleOrder.indexOf(a.id)-ruleOrder.indexOf(b.id));
139
- const result: any={mode,partial:false,durationMs:0,stores:[]};
140
- let removals=0, protectedSet: any=null;
139
+ const result ={mode,partial:false,durationMs:0,stores:[]};
140
+ let removals=0, protectedSet =null;
141
141
  const shouldStop=()=>mode==='prune' && (removals>=cap || performance.now()-started>=budget);
142
142
  const project=projectRoot(roots);
143
143
  const workCache=project && ordered.some(s=>s.rule==='work' || s.protect==='open-work')
@@ -148,7 +148,7 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
148
148
  for (const store of ordered) {
149
149
  const root=roots[store.root], storeSetting=typeof setting[store.root]==='string'?setting[store.root]:setting[store.root]?.setting || 'on';
150
150
  const location=root?path.join(root,...(store.path?store.path.split('/'):[])):'';
151
- const row: any={id:store.id,root:root || '',location,bound:formatBound(store),setting:storeSetting,entries:0,bytes:0,selected:[],removed:0,protected:0,failed:[]};
151
+ const row ={id:store.id,root:root || '',location,bound:formatBound(store),setting:storeSetting,entries:0,bytes:0,selected:[],removed:0,protected:0,failed:[]};
152
152
  result.stores.push(row);
153
153
  if (!root) { row.skipped='absent'; continue; }
154
154
  if (ownedPathLinked(store,roots,fsImpl) || resolveStorePath({store,roots,fsImpl})===null) { row.skipped='link'; continue; }
@@ -158,7 +158,7 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
158
158
  if (mode==='prune' && storeSetting==='off' && explicitWindow.state!=='on') { row.skipped='setting-off'; continue; }
159
159
  if (mode==='prune') {
160
160
  try { sweepTombstones(fsImpl,location,row); }
161
- catch(error: any) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
161
+ catch(error ) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
162
162
  }
163
163
  ready.push({store,row,location,explicitWindow,storeSetting});
164
164
  }
@@ -166,7 +166,7 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
166
166
  if (shouldStop()) { result.partial=true; break; }
167
167
  let entries;
168
168
  try { entries=inventory(store,location,fsImpl,shouldStop); }
169
- catch(error: any) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
169
+ catch(error ) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
170
170
  if (entries===null) { result.partial=true; break; }
171
171
  row.entries=entries.length;
172
172
  for (const entry of entries) {
@@ -184,17 +184,17 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
184
184
  if (mode==='report') {
185
185
  let snapshot;
186
186
  try { snapshot=readEvents(project,{fsImpl,lockFallback:false,shouldStop}); }
187
- catch(error: any) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
187
+ catch(error ) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
188
188
  if (snapshot.incomplete) { result.partial=true; break; }
189
189
  if (snapshot.unreadable.length) { row.failed.push({name:store.id,code:'EIO'}); continue; }
190
190
  const selection=selectExpired(snapshot.events,{now:new Date(now),windowMs:window.ms,shouldStop});
191
191
  if (selection.incomplete) { result.partial=true; break; }
192
- row.selected=selection.files.map((name: any)=>({name,reason:'settled',bytes:stat(fsImpl,path.join(location,name))?.size || 0}));
192
+ row.selected=selection.files.map((name )=>({name,reason:'settled',bytes:stat(fsImpl,path.join(location,name))?.size || 0}));
193
193
  } else {
194
194
  let output;
195
195
  try { output=retainLocked(project,{fsImpl,now:new Date(now),window,maxFiles:Math.max(0,cap-removals),shouldStop}); }
196
- catch(error: any) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
197
- row.selected=output.selected.map(({name,bytes}: any)=>({name,reason:'settled',bytes}));
196
+ catch(error ) { row.failed.push({name:store.id,code:error.code || 'EIO'}); continue; }
197
+ row.selected=output.selected.map(({name,bytes} )=>({name,reason:'settled',bytes}));
198
198
  row.removed=output.removed; removals+=row.removed;
199
199
  if (output.warning.length) row.failed.push({name:store.id,code:output.code || 'EIO'});
200
200
  if (output.partial) { result.partial=true; break; }
@@ -205,7 +205,7 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
205
205
  }
206
206
  let candidates;
207
207
  try { candidates=selectCandidates(store,entries,{registry,roots,fsImpl,storeDir:location,now,settings:registry.settings,shouldStop,cache:workCache}); }
208
- catch(error: any) {
208
+ catch(error ) {
209
209
  if (error.partial) { result.partial=true; break; }
210
210
  row.failed.push({name:store.id,code:error.code || 'EIO'}); continue;
211
211
  }
@@ -219,8 +219,8 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
219
219
  }
220
220
  protectedSet=protection.names;
221
221
  }
222
- row.protected=candidates.filter((c: any)=>protectedSet.has(c.name)).length;
223
- candidates=candidates.filter((c: any)=>!protectedSet.has(c.name));
222
+ row.protected=candidates.filter((c )=>protectedSet.has(c.name)).length;
223
+ candidates=candidates.filter((c )=>!protectedSet.has(c.name));
224
224
  }
225
225
  const orderedCandidates=store.entry==='record' ? removalOrder(candidates)
226
226
  : [...candidates].sort((a,b)=>a.mtimeMs-b.mtimeMs || a.name.localeCompare(b.name));
@@ -238,7 +238,7 @@ function runPass({registry,roots,stores,mode,setting={},now=Date.now(),budgetMs,
238
238
  if (store.entry==='record' && candidate.name.includes('/')) cleanEmptyNamespace(fsImpl,location,candidate.name.split('/')[0]);
239
239
  if (store.rule==='report-orphan' && candidate.name.includes('/')) cleanEmptyNamespace(fsImpl,location,candidate.name.split('/')[0],true);
240
240
  }
241
- } catch(error: any) { row.failed.push({name:candidate.name,code:error.code || 'EIO'}); }
241
+ } catch(error ) { row.failed.push({name:candidate.name,code:error.code || 'EIO'}); }
242
242
  }
243
243
  if (store.rule==='report-orphan' && !result.partial) projectKeyMarker(fsImpl,location,roots);
244
244
  if (result.partial) break;
@@ -7,7 +7,7 @@ const path = require('node:path');
7
7
 
8
8
  const ROOT_BASES = new Set(['project', 'home', 'xdg-config']);
9
9
  const ENTRIES = new Set(['file', 'dir', 'record']);
10
- const RULES: Map<string, string[]> = new Map([
10
+ const RULES = new Map([
11
11
  ['count-and-age', ['keepNewest', 'maxAgeDays']],
12
12
  ['work', ['finishedDays']],
13
13
  ['date-partition', ['maxAgeDays']],
@@ -21,13 +21,13 @@ const RULES: Map<string, string[]> = new Map([
21
21
  const MOMENTS = new Set(['verb', 'session', 'verify', 'install', 'lifecycle-verb', 'uninstall']);
22
22
  const STORE_ID = /^[a-z][a-z0-9-]*$/;
23
23
 
24
- function isObject(value: any): boolean { return value !== null && typeof value === 'object' && !Array.isArray(value); }
25
- function positiveInteger(value: any): boolean { return Number.isInteger(value) && value > 0; }
26
- function error(errors: string[], where: string, message: string): void { errors.push(`${where}: ${message}`); }
24
+ function isObject(value ) { return value !== null && typeof value === 'object' && !Array.isArray(value); }
25
+ function positiveInteger(value ) { return Number.isInteger(value) && value > 0; }
26
+ function error(errors , where , message ) { errors.push(`${where}: ${message}`); }
27
27
 
28
28
  /** Validates the closed IC-001 storage declaration document without touching the filesystem. */
29
- function validateStorageRegistry(registry: any): { ok: boolean; errors: string[] } {
30
- const errors: string[] = [];
29
+ function validateStorageRegistry(registry ) {
30
+ const errors = [];
31
31
  if (!isObject(registry)) return { ok: false, errors: ['registry: must be an object'] };
32
32
  if (registry.version !== 1) error(errors, 'version', 'must be 1');
33
33
  if (typeof registry.description !== 'string' || !registry.description.trim()) error(errors, 'description', 'must be a non-empty string');
@@ -39,28 +39,28 @@ function validateStorageRegistry(registry: any): { ok: boolean; errors: string[]
39
39
  if (!positiveInteger(settings[field])) error(errors, `settings.${field}`, 'must be a positive integer');
40
40
  }
41
41
  if (!isObject(settings.ignoreFile) || settings.ignoreFile.name !== '.gitignore'
42
- || !Array.isArray(settings.ignoreFile.lines) || settings.ignoreFile.lines.some((line: any) => typeof line !== 'string')) {
42
+ || !Array.isArray(settings.ignoreFile.lines) || settings.ignoreFile.lines.some((line ) => typeof line !== 'string')) {
43
43
  error(errors, 'settings.ignoreFile', 'must name .gitignore and contain string lines');
44
44
  }
45
45
  }
46
46
  const roots = registry.roots;
47
47
  if (!isObject(roots) || Object.keys(roots).length === 0) error(errors, 'roots', 'must be a non-empty object');
48
- else for (const [id, root] of Object.entries(roots) as [string, any][]) {
48
+ else for (const [id, root] of Object.entries(roots) ) {
49
49
  if (!isObject(root) || !ROOT_BASES.has(root.base) || !Array.isArray(root.segments)
50
- || root.segments.some((segment: any) => typeof segment !== 'string' || !segment || segment === '.' || segment === '..' || segment.includes('/') || segment.includes('\\'))) {
50
+ || root.segments.some((segment ) => typeof segment !== 'string' || !segment || segment === '.' || segment === '..' || segment.includes('/') || segment.includes('\\'))) {
51
51
  error(errors, `roots.${id}`, 'must have a known base and safe path segments');
52
52
  }
53
53
  }
54
54
  if (!Array.isArray(registry.stores)) error(errors, 'stores', 'must be an array');
55
55
  else {
56
56
  const ids = new Set();
57
- registry.stores.forEach((store: any, index: number) => {
57
+ registry.stores.forEach((store , index ) => {
58
58
  const where = `stores[${index}]`;
59
59
  if (!isObject(store)) { error(errors, where, 'must be an object'); return; }
60
60
  if (typeof store.id !== 'string' || !STORE_ID.test(store.id)) error(errors, `${where}.id`, 'must match ^[a-z][a-z0-9-]*$');
61
61
  else if (ids.has(store.id)) error(errors, `${where}.id`, `duplicate id '${store.id}'`); else ids.add(store.id);
62
62
  if (typeof store.root !== 'string' || !roots?.[store.root]) error(errors, `${where}.root`, 'must name a declared root');
63
- if (typeof store.path !== 'string' || store.path.startsWith('/') || store.path.split('/').some((part: string) => part === '..' || !part && store.path !== '')) error(errors, `${where}.path`, 'must be relative, slash-separated, and contain no ..');
63
+ if (typeof store.path !== 'string' || store.path.startsWith('/') || store.path.split('/').some((part ) => part === '..' || !part && store.path !== '')) error(errors, `${where}.path`, 'must be relative, slash-separated, and contain no ..');
64
64
  if (!ENTRIES.has(store.entry)) error(errors, `${where}.entry`, 'must be file, dir, or record');
65
65
  if (typeof store.match !== 'string' || !store.match.startsWith('^') || !store.match.endsWith('$')) error(errors, `${where}.match`, 'must be an anchored regular expression');
66
66
  else { try { new RegExp(store.match); } catch { error(errors, `${where}.match`, 'must compile'); } }
@@ -72,9 +72,9 @@ function validateStorageRegistry(registry: any): { ok: boolean; errors: string[]
72
72
  if (store.rule === 'existing' && store.bound.value !== undefined && !positiveInteger(store.bound.value)) error(errors, `${where}.bound.value`, 'must be a positive integer when present');
73
73
  }
74
74
  if (store.protect !== null && store.protect !== 'open-work') error(errors, `${where}.protect`, 'must be open-work or null');
75
- if (!Array.isArray(store.moments) || store.moments.some((moment: any) => !MOMENTS.has(moment)) || new Set(store.moments).size !== store.moments.length) error(errors, `${where}.moments`, 'must be a unique subset of known moments');
75
+ if (!Array.isArray(store.moments) || store.moments.some((moment ) => !MOMENTS.has(moment)) || new Set(store.moments).size !== store.moments.length) error(errors, `${where}.moments`, 'must be a unique subset of known moments');
76
76
  if (store.rule === 'existing' && store.moments?.length) error(errors, `${where}.moments`, 'must be empty for existing stores');
77
- if (!Array.isArray(store.writers) || store.writers.some((writer: any) => typeof writer !== 'string' || !writer)) error(errors, `${where}.writers`, 'must be an array of repository-relative paths');
77
+ if (!Array.isArray(store.writers) || store.writers.some((writer ) => typeof writer !== 'string' || !writer)) error(errors, `${where}.writers`, 'must be an array of repository-relative paths');
78
78
  else if (!store.writers.length && store.rule !== 'control' && !store.id.startsWith('user-settings-')) error(errors, `${where}.writers`, 'may be empty only for control or user-settings stores');
79
79
  if (store.rule === 'existing') {
80
80
  if (!isObject(store.source) || typeof store.source.file !== 'string' || !store.source.file
@@ -87,17 +87,17 @@ function validateStorageRegistry(registry: any): { ok: boolean; errors: string[]
87
87
  });
88
88
  }
89
89
  if (!Array.isArray(registry.externalWriters)) error(errors, 'externalWriters', 'must be an array');
90
- else registry.externalWriters.forEach((writer: any, index: number) => {
90
+ else registry.externalWriters.forEach((writer , index ) => {
91
91
  if (!isObject(writer) || typeof writer.file !== 'string' || !writer.file || typeof writer.reason !== 'string' || !writer.reason.trim()) error(errors, `externalWriters[${index}]`, 'requires a file and non-empty reason');
92
92
  });
93
93
  return { ok: errors.length === 0, errors };
94
94
  }
95
95
 
96
96
  /** Loads and fails closed on an IC-001 storage registry. */
97
- function loadStorageRegistry({ repoRoot, file, fsImpl = fs }: any = {}): any {
97
+ function loadStorageRegistry({ repoRoot, file, fsImpl = fs } = {}) {
98
98
  const target = file || path.join(path.resolve(repoRoot || process.cwd()), 'core', 'registry', 'storage.json');
99
- let registry: any;
100
- try { registry = JSON.parse(fsImpl.readFileSync(target, 'utf8')); } catch (cause: any) { throw new Error(`Could not load storage registry '${target}': ${cause.message}`); }
99
+ let registry ;
100
+ try { registry = JSON.parse(fsImpl.readFileSync(target, 'utf8')); } catch (cause ) { throw new Error(`Could not load storage registry '${target}': ${cause.message}`); }
101
101
  const validation = validateStorageRegistry(registry);
102
102
  if (!validation.ok) throw new Error(`Invalid storage registry:\n- ${validation.errors.join('\n- ')}`);
103
103
  return registry;
@@ -105,13 +105,13 @@ function loadStorageRegistry({ repoRoot, file, fsImpl = fs }: any = {}): any {
105
105
 
106
106
  /** Renders IC-001's canonical human-readable bound for a store. */
107
107
  /** Renders an existing-store source pattern for G26's literal source check. */
108
- function renderSourcePattern(store: any): string {
108
+ function renderSourcePattern(store ) {
109
109
  const pattern = store?.source?.pattern;
110
110
  if (typeof pattern !== 'string') throw new Error('Existing store has no source pattern');
111
111
  return pattern.includes('{value}') ? pattern.replaceAll('{value}', String(store.bound.value)) : pattern;
112
112
  }
113
113
 
114
- function formatBound(store: any): string {
114
+ function formatBound(store ) {
115
115
  const bound = store.bound;
116
116
  switch (store.rule) {
117
117
  case 'count-and-age': return `keep newest ${bound.keepNewest}; prune entries older than ${bound.maxAgeDays} days`;
@@ -6,22 +6,22 @@ const fs = require('node:fs');
6
6
  const os = require('node:os');
7
7
  const path = require('node:path');
8
8
 
9
- function absolute(value: any): string | null { return typeof value === 'string' && path.isAbsolute(value) ? value : null; }
9
+ function absolute(value ) { return typeof value === 'string' && path.isAbsolute(value) ? value : null; }
10
10
 
11
11
  /** Resolves IC-001's five physical roots; -g/global deliberately omits project roots. */
12
- function resolveRoots({ registry, projectRoot, global = false, env = process.env }: any = {}): Record<string, string | null> {
12
+ function resolveRoots({ registry, projectRoot, global = false, env = process.env } = {}) {
13
13
  const home = absolute(env.HOME) || os.homedir();
14
14
  const xdgBase = env.XDG_CONFIG_HOME === undefined || env.XDG_CONFIG_HOME === ''
15
15
  ? path.join(home, '.config') : absolute(env.XDG_CONFIG_HOME);
16
16
  const project = global ? null : absolute(projectRoot);
17
- const bases: Record<string, string | null> = { project, home, 'xdg-config': xdgBase };
18
- return Object.fromEntries(Object.entries(registry.roots).map(([id, root]: [string, any]) => {
17
+ const bases = { project, home, 'xdg-config': xdgBase };
18
+ return Object.fromEntries(Object.entries(registry.roots).map(([id, root] ) => {
19
19
  const base = bases[root.base];
20
20
  return [id, base ? path.join(base, ...root.segments) : null];
21
21
  }));
22
22
  }
23
23
 
24
- function readSetting(file: string, fsImpl: any): string {
24
+ function readSetting(file , fsImpl ) {
25
25
  try {
26
26
  const first = fsImpl.readFileSync(file, 'utf8').split(/\r?\n/, 1)[0].trim().toLowerCase();
27
27
  return first === 'on' || first === 'off' ? first : 'off';
@@ -29,7 +29,7 @@ function readSetting(file: string, fsImpl: any): string {
29
29
  }
30
30
 
31
31
  /** Reads IC-014 and reports exactly which present file made the decision, if any. */
32
- function readPruneSetting({ registry, roots, rootId, fsImpl = fs }: any = {}): { setting: string; decidedBy: string | null } {
32
+ function readPruneSetting({ registry, roots, rootId, fsImpl = fs } = {}) {
33
33
  const projectFile = roots['project-doflow'] ? path.join(roots['project-doflow'], registry.settings.optOutFile) : null;
34
34
  const userFile = roots['config-home'] ? path.join(roots['config-home'], registry.settings.optOutFile) : null;
35
35
  const usesProject = rootId === 'project-doflow' || rootId === 'project-state';
@@ -38,7 +38,7 @@ function readPruneSetting({ registry, roots, rootId, fsImpl = fs }: any = {}): {
38
38
  return { setting: 'on', decidedBy: null };
39
39
  }
40
40
 
41
- function linked(file: string, fsImpl: any): boolean {
41
+ function linked(file , fsImpl ) {
42
42
  try { return fsImpl.lstatSync(file).isSymbolicLink(); } catch { return false; }
43
43
  }
44
44
 
@@ -46,7 +46,7 @@ function linked(file: string, fsImpl: any): boolean {
46
46
  * Returns the physical directory for a declared store, or null when a DoFlow-owned component is a
47
47
  * link. The engine treats null as a refuse-to-touch result, never as a path to repair.
48
48
  */
49
- function resolveStorePath({ store, roots, fsImpl = fs }: any = {}): string | null {
49
+ function resolveStorePath({ store, roots, fsImpl = fs } = {}) {
50
50
  const root = roots[store.root];
51
51
  if (!root) return null;
52
52
  if (linked(root, fsImpl)) return null;
@@ -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': {