@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
@@ -14,7 +14,7 @@
14
14
  // the same reason a file DoFlow cannot read is described by a fixed reason, never parser output.
15
15
  const fs = require('node:fs');
16
16
  const path = require('node:path');
17
- const { fingerprint } = require('./copy-tree.ts');
17
+ const { fingerprint } = require('./copy-tree.js');
18
18
 
19
19
  const REASONS = Object.freeze({
20
20
  json: 'invalid JSON',
@@ -22,29 +22,29 @@ const REASONS = Object.freeze({
22
22
  container: 'server container is not an object',
23
23
  });
24
24
 
25
- function isObject(value: any): boolean { return Boolean(value) && typeof value === 'object' && !Array.isArray(value); }
25
+ function isObject(value ) { return Boolean(value) && typeof value === 'object' && !Array.isArray(value); }
26
26
 
27
- function entryFingerprint(value: any): string { return fingerprint(value); }
27
+ function entryFingerprint(value ) { return fingerprint(value); }
28
28
 
29
- function fingerprintOrNull(value: any): string | null { return value === undefined ? null : entryFingerprint(value); }
29
+ function fingerprintOrNull(value ) { return value === undefined ? null : entryFingerprint(value); }
30
30
 
31
31
  /** Deep equality that ignores key order, so a reformatted entry still equals DoFlow's rendering. */
32
- function sameValue(a: any, b: any): boolean { return a !== undefined && b !== undefined && entryFingerprint(a) === entryFingerprint(b); }
32
+ function sameValue(a , b ) { return a !== undefined && b !== undefined && entryFingerprint(a) === entryFingerprint(b); }
33
33
 
34
- function shortId(id: any): string { const text = String(id); return text.length > 40 ? `${text.slice(0, 37)}...` : text; }
34
+ function shortId(id ) { const text = String(id); return text.length > 40 ? `${text.slice(0, 37)}...` : text; }
35
35
 
36
- function shortPath(file: string): string { return file.length > 80 ? `...${file.slice(-77)}` : file; }
36
+ function shortPath(file ) { return file.length > 80 ? `...${file.slice(-77)}` : file; }
37
37
 
38
38
  const NOTICES = Object.freeze({
39
- collision: (id: any, file: string) => `MCP: kept your own entry '${shortId(id)}' in ${path.basename(file)} and did not register DoFlow's; rename or remove yours to let DoFlow manage it.`,
40
- released: (id: any, file: string) => `MCP: entry '${shortId(id)}' in ${path.basename(file)} was changed outside DoFlow; it is yours now and DoFlow no longer updates or removes it.`,
41
- untouched: (file: string) => `MCP: left ${shortPath(file)} untouched because it cannot be edited safely; DoFlow no longer manages the entries in it.`,
39
+ collision: (id , file ) => `MCP: kept your own entry '${shortId(id)}' in ${path.basename(file)} and did not register DoFlow's; rename or remove yours to let DoFlow manage it.`,
40
+ released: (id , file ) => `MCP: entry '${shortId(id)}' in ${path.basename(file)} was changed outside DoFlow; it is yours now and DoFlow no longer updates or removes it.`,
41
+ untouched: (file ) => `MCP: left ${shortPath(file)} untouched because it cannot be edited safely; DoFlow no longer manages the entries in it.`,
42
42
  });
43
43
 
44
- function refusal(label: string, file: string, reason: string): string { return `${label}: ${file}: ${reason}; DoFlow did not change the file`; }
44
+ function refusal(label , file , reason ) { return `${label}: ${file}: ${reason}; DoFlow did not change the file`; }
45
45
 
46
46
  /** Read one MCP file as a JSON object. `servers` is null when the file or its container is absent. */
47
- function readMcpFile(file: string, container: string, { fsImpl = fs }: { fsImpl?: any } = {}): any {
47
+ function readMcpFile(file , container , { fsImpl = fs } = {}) {
48
48
  if (!fsImpl.existsSync(file)) return { ok: true, doc: null, servers: null };
49
49
  let doc;
50
50
  try { doc = JSON.parse(fsImpl.readFileSync(file, 'utf8')); } catch { return { ok: false, reason: REASONS.json }; }
@@ -55,52 +55,52 @@ function readMcpFile(file: string, container: string, { fsImpl = fs }: { fsImpl?
55
55
  }
56
56
 
57
57
  /** The `files` map plan and verify take: the scope's MCP file and every file an own row names. */
58
- function readMcpFiles({ file, ownRows = [], container, fsImpl = fs }: any): any {
59
- const targets = new Set([file, ...ownRows.map((row: any) => row.target)]);
58
+ function readMcpFiles({ file, ownRows = [], container, fsImpl = fs } ) {
59
+ const targets = new Set([file, ...ownRows.map((row ) => row.target)]);
60
60
  return Object.fromEntries([...targets].map((target) => {
61
61
  const read = readMcpFile(target, container, { fsImpl });
62
62
  return [target, read.ok ? { ok: true, servers: read.servers } : read];
63
63
  }));
64
64
  }
65
65
 
66
- function renderedById(selected: any[], adoptable: any[]): Map<string, any> {
67
- const rendered = new Map<string, any>();
66
+ function renderedById(selected , adoptable ) {
67
+ const rendered = new Map ();
68
68
  for (const { id, entry } of [...selected, ...adoptable]) if (!rendered.has(id)) rendered.set(id, entry);
69
69
  return rendered;
70
70
  }
71
71
 
72
72
  /** Shared by plan, verify and ownedMcpIds, so the three read one entry the same way. */
73
- function ownershipView({ file, files, selected = [], adoptable = [], ownRows = [], foreignRows = [] }: any): any {
73
+ function ownershipView({ file, files, selected = [], adoptable = [], ownRows = [], foreignRows = [] } ) {
74
74
  const rendered = renderedById(selected, adoptable);
75
- const valueOf = (target: string, id: string) => (files[target]?.ok ? files[target].servers?.[id] : undefined);
76
- const matches = (row: any, value: any) => {
75
+ const valueOf = (target , id ) => (files[target]?.ok ? files[target].servers?.[id] : undefined);
76
+ const matches = (row , value ) => {
77
77
  if (value === undefined) return false;
78
78
  const recorded = row.fingerprint ?? null;
79
79
  return recorded !== null ? entryFingerprint(value) === recorded : sameValue(value, rendered.get(row.identity));
80
80
  };
81
- const rowsFor = (id: string) => ownRows.filter((row: any) => row.identity === id && row.target === file);
81
+ const rowsFor = (id ) => ownRows.filter((row ) => row.identity === id && row.target === file);
82
82
  // A legacy row is consumed alongside the current one, but never preferred over it.
83
- const rowFor = (id: string) => { const rows = rowsFor(id); return rows.find((row: any) => !row.legacy) ?? rows[0] ?? null; };
83
+ const rowFor = (id ) => { const rows = rowsFor(id); return rows.find((row ) => !row.legacy) ?? rows[0] ?? null; };
84
84
  const adoptionOpen = ownRows.length === 0;
85
- const adoptableIds = new Set(adoptable.map((server: any) => server.id));
86
- const selectedIds = new Set(selected.map((server: any) => server.id));
85
+ const adoptableIds = new Set(adoptable.map((server ) => server.id));
86
+ const selectedIds = new Set(selected.map((server ) => server.id));
87
87
  /** An equal entry no own row claims is DoFlow's when another harness's row claims it, or when it
88
88
  * may be adopted. */
89
- const claimable = (id: string, entry: any) => {
89
+ const claimable = (id , entry ) => {
90
90
  const value = valueOf(file, id);
91
- return sameValue(value, entry) && (foreignRows.some((row: any) => row.identity === id && row.target === file)
91
+ return sameValue(value, entry) && (foreignRows.some((row ) => row.identity === id && row.target === file)
92
92
  || (adoptionOpen && adoptableIds.has(id)));
93
93
  };
94
94
  /** Adoptable entries DoFlow takes out because nothing selects them any more. */
95
95
  const adoptedRemovals = () => (adoptionOpen && files[file]?.ok
96
- ? adoptable.filter(({ id, entry }: any) => !selectedIds.has(id) && sameValue(valueOf(file, id), entry)) : []);
96
+ ? adoptable.filter(({ id, entry } ) => !selectedIds.has(id) && sameValue(valueOf(file, id), entry)) : []);
97
97
  return { rendered, valueOf, matches, rowsFor, rowFor, claimable, adoptedRemovals };
98
98
  }
99
99
 
100
- function orderOf(selected: any[], adoptable: any[]): (a: any, b: any) => number {
100
+ function orderOf(selected , adoptable ) {
101
101
  const ids = [...renderedById(selected, adoptable).keys()];
102
- const rank = (id: string) => { const index = ids.indexOf(id); return index < 0 ? ids.length : index; };
103
- return (a: any, b: any) => (a.target < b.target ? -1 : a.target > b.target ? 1
102
+ const rank = (id ) => { const index = ids.indexOf(id); return index < 0 ? ids.length : index; };
103
+ return (a , b ) => (a.target < b.target ? -1 : a.target > b.target ? 1
104
104
  : rank(a.identity) - rank(b.identity) || (a.identity < b.identity ? -1 : a.identity > b.identity ? 1 : 0));
105
105
  }
106
106
 
@@ -110,17 +110,17 @@ function orderOf(selected: any[], adoptable: any[]): (a: any, b: any) => number
110
110
  * `foreignRows` other harnesses' rows; `identityFor` composes the adapter's ownership identity.
111
111
  */
112
112
  function planMcpEntries({ file, files, selected = [], adoptable = [], ownRows = [], foreignRows = [], removing = false,
113
- identityFor, assetId, renderer, label }: any): any {
113
+ identityFor, assetId, renderer, label } ) {
114
114
  const view = ownershipView({ file, files, selected, adoptable, ownRows, foreignRows });
115
- const changes: any[] = [];
116
- const conflicts: string[] = [];
117
- const notices: string[] = [];
118
- const base = (fields: any) => ({ assetId, kind: 'mcp-server', sourceVersion: 'registry-v1', projection: { renderer }, ...fields });
119
- const write = (operation: string, id: string, entry: any) => base({
115
+ const changes = [];
116
+ const conflicts = [];
117
+ const notices = [];
118
+ const base = (fields ) => ({ assetId, kind: 'mcp-server', sourceVersion: 'registry-v1', projection: { renderer }, ...fields });
119
+ const write = (operation , id , entry ) => base({
120
120
  target: file, operation, identity: id, ownershipIdentity: identityFor(id),
121
121
  before: fingerprintOrNull(view.valueOf(file, id)), entry, fingerprint: entryFingerprint(entry), afterFingerprint: entryFingerprint(entry),
122
122
  });
123
- const drop = (row: any, release: boolean) => base({
123
+ const drop = (row , release ) => base({
124
124
  target: row.target, operation: 'remove', identity: row.identity, ownershipIdentity: row.ownershipIdentity,
125
125
  before: fingerprintOrNull(view.valueOf(row.target, row.identity)), fingerprint: row.fingerprint ?? null,
126
126
  ...(release ? { release: true } : {}),
@@ -132,7 +132,7 @@ function planMcpEntries({ file, files, selected = [], adoptable = [], ownRows =
132
132
  else conflicts.push(refusal(label, target, files[target].reason));
133
133
  }
134
134
 
135
- const consumed = new Set<any>();
135
+ const consumed = new Set ();
136
136
  if (!removing && files[file]?.ok) {
137
137
  for (const { id, entry } of selected) {
138
138
  const rows = view.rowsFor(id);
@@ -184,7 +184,7 @@ function planMcpEntries({ file, files, selected = [], adoptable = [], ownRows =
184
184
  /** Apply one file's planned changes to the server map read now. Each change goes ahead only while
185
185
  * its entry still holds what plan saw, or already holds the change's end state, which makes two
186
186
  * harnesses' changes to one shared entry in one run idempotent. Release changes touch nothing. */
187
- function applyMcpEntries(servers: any, changes: any[]): any {
187
+ function applyMcpEntries(servers , changes ) {
188
188
  const next = { ...(servers || {}) };
189
189
  for (const change of changes) {
190
190
  if (change.release) continue;
@@ -205,13 +205,13 @@ function applyMcpEntries(servers: any, changes: any[]): any {
205
205
  * whatever it holds now.
206
206
  */
207
207
  function verifyMcpEntries({ file, files, snapshot, selected = [], adoptable = [], ownRows = [], foreignRows = [], removing = false,
208
- identityFor, assetId, renderer, label, harness, sourceVersion = 'unknown' }: any): any {
208
+ identityFor, assetId, renderer, label, harness, sourceVersion = 'unknown' } ) {
209
209
  const now = ownershipView({ file, files, selected, adoptable, ownRows, foreignRows });
210
210
  const then = ownershipView({ file, files: snapshot, selected, adoptable, ownRows, foreignRows });
211
- const statuses: any[] = [];
212
- const resources: any[] = [];
213
- const conflicts: string[] = [];
214
- const report = (id: string, target: string, ownershipIdentity: any, status: string) => statuses.push({
211
+ const statuses = [];
212
+ const resources = [];
213
+ const conflicts = [];
214
+ const report = (id , target , ownershipIdentity , status ) => statuses.push({
215
215
  harness, assetId, capability: 'mcp', identity: id, target, ownershipIdentity, status,
216
216
  });
217
217
 
@@ -219,7 +219,7 @@ function verifyMcpEntries({ file, files, snapshot, selected = [], adoptable = []
219
219
  for (const target of Object.keys(files).filter((item) => !files[item].ok).sort()) conflicts.push(refusal(label, target, files[target].reason));
220
220
  }
221
221
 
222
- const consumed = new Set<any>();
222
+ const consumed = new Set ();
223
223
  if (!removing) {
224
224
  for (const { id, entry } of selected) {
225
225
  for (const row of now.rowsFor(id)) consumed.add(row);
@@ -239,7 +239,7 @@ function verifyMcpEntries({ file, files, snapshot, selected = [], adoptable = []
239
239
  }
240
240
  }
241
241
 
242
- const leftover = (value: any, matching: boolean, target: string) => {
242
+ const leftover = (value , matching , target ) => {
243
243
  if (!files[target]?.ok) return 'not-managed';
244
244
  if (value === undefined) return 'absent';
245
245
  return matching ? 'retained' : 'not-managed';
@@ -261,29 +261,29 @@ function verifyMcpEntries({ file, files, snapshot, selected = [], adoptable = []
261
261
  /** The ids DoFlow owns in this harness's MCP file now, in rendering order: those an own row matches,
262
262
  * and, while the harness holds no row, adoptable entries equal to DoFlow's rendering. A file that
263
263
  * cannot be read contributes none. */
264
- function ownedMcpIds({ file, files, selected = [], adoptable = [], ownRows = [] }: any): string[] {
264
+ function ownedMcpIds({ file, files, selected = [], adoptable = [], ownRows = [] } ) {
265
265
  const view = ownershipView({ file, files, selected, adoptable, ownRows });
266
- const owned = new Set<string>(ownRows.filter((row: any) => view.matches(row, view.valueOf(row.target, row.identity))).map((row: any) => row.identity));
266
+ const owned = new Set (ownRows.filter((row ) => view.matches(row, view.valueOf(row.target, row.identity))).map((row ) => row.identity));
267
267
  if (!ownRows.length) {
268
268
  for (const { id, entry } of adoptable) if (sameValue(view.valueOf(file, id), entry)) owned.add(id);
269
269
  }
270
- const order: string[] = [...view.rendered.keys()];
270
+ const order = [...view.rendered.keys()];
271
271
  return [...order.filter((id) => owned.has(id)), ...[...owned].filter((id) => !order.includes(id)).sort()];
272
272
  }
273
273
 
274
- function isSymlink(file: string, fsImpl: any): boolean {
274
+ function isSymlink(file , fsImpl ) {
275
275
  try { return fsImpl.lstatSync(file).isSymbolicLink(); } catch { return false; }
276
276
  }
277
277
 
278
278
  /** A symlinked MCP file is written through to the file it points at, so the link stays a link. */
279
- function writePath(file: string, fsImpl: any): string {
279
+ function writePath(file , fsImpl ) {
280
280
  if (!isSymlink(file, fsImpl)) return file;
281
281
  try { return fsImpl.realpathSync(file); } catch { return path.resolve(path.dirname(file), fsImpl.readlinkSync(file)); }
282
282
  }
283
283
 
284
284
  /** Write a JSON document atomically, keeping the existing file's permission bits: an MCP file kept
285
285
  * private for its tokens stays so. Creates missing directories; never deletes a file. */
286
- function writeMcpJson(file: string, doc: any, { fsImpl = fs }: { fsImpl?: any } = {}): string {
286
+ function writeMcpJson(file , doc , { fsImpl = fs } = {}) {
287
287
  const dest = writePath(file, fsImpl);
288
288
  fsImpl.mkdirSync(path.dirname(dest), { recursive: true });
289
289
  const mode = fsImpl.existsSync(dest) ? fsImpl.statSync(dest).mode & 0o7777 : null;
@@ -303,14 +303,14 @@ function writeMcpJson(file: string, doc: any, { fsImpl = fs }: { fsImpl?: any }
303
303
  * every file's next document computed before the first write. An emptied container is kept as `{}`
304
304
  * or its member deleted, as the harness expects. Returns the number of files written.
305
305
  */
306
- function writeMcpEntries(changes: any[], { container, keepEmptyContainer = false, fsImpl = fs }: { container?: any, keepEmptyContainer?: boolean, fsImpl?: any } = {}): number {
307
- const byFile = new Map<string, any[]>();
306
+ function writeMcpEntries(changes , { container, keepEmptyContainer = false, fsImpl = fs } = {}) {
307
+ const byFile = new Map ();
308
308
  for (const change of changes) {
309
309
  if (change.kind !== 'mcp-server' || change.release) continue;
310
310
  if (!byFile.has(change.target)) byFile.set(change.target, []);
311
- byFile.get(change.target)!.push(change);
311
+ byFile.get(change.target) .push(change);
312
312
  }
313
- const writes: [string, any][] = [];
313
+ const writes = [];
314
314
  for (const [file, group] of byFile) {
315
315
  const read = readMcpFile(file, container, { fsImpl });
316
316
  if (!read.ok) throw new Error(`MCP: ${file} changed after planning; nothing was written, re-run the command`);
@@ -16,15 +16,15 @@
16
16
  // https://opencode.ai/docs/rules
17
17
  const fs = require('node:fs');
18
18
  const path = require('node:path');
19
- const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, copyTreeDestDir, sharedTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor, resolveTransform } = require('../copy-tree.ts');
20
- const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.ts');
19
+ const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, copyTreeDestDir, sharedTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor, resolveTransform } = require('../copy-tree.js');
20
+ const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.js');
21
21
 
22
22
  // Only the marker constants: marker-merge.js reads and writes files itself, which cannot be used
23
23
  // from plan(), whose contract is to compute changes without touching disk. The gemini adapter
24
24
  // solves this the same way, with a pure managedInstruction() over strings.
25
- const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.ts');
26
- const { destructiveCommandGlobs } = require('../../helper/guardrails.ts');
27
- const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.ts');
25
+ const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.js');
26
+ const { destructiveCommandGlobs } = require('../../helper/guardrails.js');
27
+ const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
28
28
 
29
29
  const HARNESS = 'opencode';
30
30
  /**
@@ -48,7 +48,7 @@ const MCP_RENDERER = 'opencode-mcp';
48
48
  * historical shape.
49
49
  */
50
50
  function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS] } = {}) {
51
- function nativePaths({ scope, scopeRoot, homeDir }: any) {
51
+ function nativePaths({ scope, scopeRoot, homeDir } ) {
52
52
  return resolveHarnessPaths(declaredPaths, { scope, scopeRoot, homeDir });
53
53
  }
54
54
 
@@ -57,20 +57,20 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
57
57
  * `opencode.json` are read from the repo root, but the skills tree is namespaced under
58
58
  * `.opencode/` per design.md's native-surfaces table. Global scope has no such split —
59
59
  * `~/.config/opencode` already IS the skills root. Declared as `treeRoot` in harnesses.json. */
60
- function copyTreeConfigDir(paths: any) {
60
+ function copyTreeConfigDir(paths ) {
61
61
  return paths.treeRoot;
62
62
  }
63
63
 
64
64
  /** Agents live under `.opencode/agents/` at project scope and `~/.config/opencode/agents/`
65
65
  * globally — a different root from the skills tree in both scopes, so they get their own
66
66
  * destination resolution rather than reusing copyTreeConfigDir. Declared as `agentsDirectory`. */
67
- function agentsDestDir(paths: any) {
67
+ function agentsDestDir(paths ) {
68
68
  return paths.agentsDirectory;
69
69
  }
70
70
 
71
71
  /** Discovery keeps opencode.json as plan read it (`mcpSnapshot`), which verify compares against,
72
72
  * and reports the servers DoFlow owns in its `mcp` object now (`mcpOwned`). */
73
- function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, context = {}, fsImpl = fs }: any) {
73
+ function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, context = {}, fsImpl = fs } ) {
74
74
  const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir });
75
75
  const instruction = fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
76
76
  const entries = mcpEntriesInput({ paths, mcp, mcpAdoptable, ledger });
@@ -81,7 +81,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
81
81
  return { paths, instruction, config: readJson(paths.config, { fsImpl }), mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
82
82
  }
83
83
 
84
- function render({ content = '' }: any = {}) {
84
+ function render({ content = '' } = {}) {
85
85
  return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
86
86
  }
87
87
 
@@ -90,17 +90,17 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
90
90
  * every config it discovers — replacing would silently drop a user's own entries. Skills are
91
91
  * deliberately absent here: they are a materialised directory now, discovered natively, not a
92
92
  * registered path. The `mcp` object is left to the entry changes. */
93
- function mergeConfig(existing: any) {
93
+ function mergeConfig(existing ) {
94
94
  const next = { ...(existing || {}) };
95
- const union = (current: any, add: any) => [...new Set([...(Array.isArray(current) ? current : []), ...add])];
95
+ const union = (current , add ) => [...new Set([...(Array.isArray(current) ? current : []), ...add])];
96
96
  next.instructions = union(next.instructions, [INSTRUCTION_FILE]);
97
97
  return next;
98
98
  }
99
99
 
100
100
  /** Remove only what mergeConfig added, leaving every user key and every unrelated array entry. */
101
- function unmergeConfig(existing: any) {
101
+ function unmergeConfig(existing ) {
102
102
  const next = { ...(existing || {}) };
103
- const without = (current: any, drop: any) => (Array.isArray(current) ? current.filter((v) => !drop.includes(v)) : []);
103
+ const without = (current , drop ) => (Array.isArray(current) ? current.filter((v) => !drop.includes(v)) : []);
104
104
  next.instructions = without(next.instructions, [INSTRUCTION_FILE]);
105
105
  if (!next.instructions.length) delete next.instructions;
106
106
  return next;
@@ -116,12 +116,12 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
116
116
  * comment-free glob we can re-derive) are touched; a user's own bash rules survive untouched.
117
117
  * Entries are namespaced by value, not by key, so ownership is decided by re-deriving the list
118
118
  * from the single authored source rather than by trusting whatever happens to be present. */
119
- function guardrailBashRules(context: any) {
119
+ function guardrailBashRules(context ) {
120
120
  const globs = destructiveCommandGlobs({ repoRoot: context.repoRoot });
121
- return Object.fromEntries(globs.map((glob: any) => [glob, 'deny']));
121
+ return Object.fromEntries(globs.map((glob ) => [glob, 'deny']));
122
122
  }
123
123
 
124
- function mergeGuardrails(existing: any, context: any) {
124
+ function mergeGuardrails(existing , context ) {
125
125
  const next = { ...(existing || {}) };
126
126
  const bash = { ...guardrailBashRules(context), ...((next.permission?.bash ?? {})) };
127
127
  // Keep user rules, but make sure ours win for identical globs (they are the stricter value).
@@ -129,7 +129,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
129
129
  return next;
130
130
  }
131
131
 
132
- function stripGuardrails(existing: any, context: any) {
132
+ function stripGuardrails(existing , context ) {
133
133
  if (!existing?.permission?.bash) return existing;
134
134
  const ours = new Set(Object.keys(guardrailBashRules(context)));
135
135
  const bash = Object.fromEntries(Object.entries(existing.permission.bash).filter(([glob]) => !ours.has(glob)));
@@ -141,7 +141,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
141
141
  return rest;
142
142
  }
143
143
 
144
- function managedInstruction(existing: any, rendered: any) {
144
+ function managedInstruction(existing , rendered ) {
145
145
  if (existing === null) return { ok: true, operation: 'create', content: rendered };
146
146
  const start = existing.indexOf(MARKER_START);
147
147
  const end = existing.indexOf(MARKER_END);
@@ -153,7 +153,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
153
153
 
154
154
  /** Strip DoFlow's span, leaving the rest of a shared AGENTS.md intact. Returns null when there is
155
155
  * nothing to do, so remove() can skip the write entirely. */
156
- function strippedInstruction(existing: any) {
156
+ function strippedInstruction(existing ) {
157
157
  if (typeof existing !== 'string') return null;
158
158
  const start = existing.indexOf(MARKER_START);
159
159
  const end = existing.indexOf(MARKER_END);
@@ -168,11 +168,11 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
168
168
  /** `agents.shared` projects onto OpenCode through its own renderer name (its frontmatter is
169
169
  * transformed into OpenCode's markdown-agent vocabulary) but materialises with exactly the same
170
170
  * engine and change records as every other copy-tree asset. */
171
- function opencodeTreeAssets(assets: any) {
172
- return [...copyTreeAssets(assets), ...(assets || []).filter((asset: any) => asset.renderer === 'opencode-agents')];
171
+ function opencodeTreeAssets(assets ) {
172
+ return [...copyTreeAssets(assets), ...(assets || []).filter((asset ) => asset.renderer === 'opencode-agents')];
173
173
  }
174
174
 
175
- function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl = fs }: any) {
175
+ function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl = fs } ) {
176
176
  const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir });
177
177
  const treeConfigDir = copyTreeConfigDir(paths);
178
178
  const changes = [];
@@ -190,10 +190,10 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
190
190
  // is never deleted on removal, forced or not.
191
191
  force: !removing && context?.force === true, });
192
192
  treeResults.push(result);
193
- conflicts.push(...result.conflicts.map((reason: any) => `${asset.id}: ${reason}`));
193
+ conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
194
194
  // A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
195
195
  // ownership row is released.
196
- notices.push(...result.kept.map((item: any) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
196
+ notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
197
197
  for (const change of result.changes) {
198
198
  changes.push({
199
199
  assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
@@ -209,7 +209,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
209
209
  return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
210
210
  }
211
211
 
212
- function applyCopyTreeAssets(changes: any, { fsImpl = fs }: any = {}) {
212
+ function applyCopyTreeAssets(changes , { fsImpl = fs } = {}) {
213
213
  let applied = 0;
214
214
  const grouped = new Map();
215
215
  for (const change of changes) {
@@ -224,13 +224,13 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
224
224
  return applied;
225
225
  }
226
226
 
227
- function removeCopyTreeAssets(changes: any, { fsImpl = fs }: any = {}) {
228
- const treeChanges = changes.filter((change: any) => change.kind === 'copy-tree-file' && change.operation === 'remove' && !change.retained)
229
- .map((change: any) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
227
+ function removeCopyTreeAssets(changes , { fsImpl = fs } = {}) {
228
+ const treeChanges = changes.filter((change ) => change.kind === 'copy-tree-file' && change.operation === 'remove' && !change.retained)
229
+ .map((change ) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
230
230
  return removeTree({ changes: treeChanges, fsImpl }).removed;
231
231
  }
232
232
 
233
- function verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl = fs }: any) {
233
+ function verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl = fs } ) {
234
234
  const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir });
235
235
  const treeConfigDir = copyTreeConfigDir(paths);
236
236
  const statuses = [];
@@ -240,7 +240,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
240
240
  const destDir = asset.renderer === 'opencode-agents' ? agentsDestDir(paths) : sharedTreeDestDir(paths.root, asset.nativeDir) ?? copyTreeDestDir(treeConfigDir, asset);
241
241
  const sourceDir = sourceDirFor(asset, context, fsImpl, 'OpenCode');
242
242
  const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
243
- conflicts.push(...result.conflicts.map((reason: any) => `${asset.id}: ${reason}`));
243
+ conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
244
244
  for (const resource of result.resources) {
245
245
  resources.push({
246
246
  assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${resource.relPath}`,
@@ -259,45 +259,45 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
259
259
  /** OpenCode's settings-merge change has no asset of its own in core/registry/assets.json (it's a
260
260
  * registration side-effect of the instructions/mcp assets, not a projected asset), so it piggybacks
261
261
  * on a real asset id already routed to this harness — the same "pseudo-component" technique
262
- * src/adapters/gemini/index.ts#hooksAssetId and src/adapters/kiro/index.ts#pseudoAssetId use. The
262
+ * src/adapters/gemini/index.js#hooksAssetId and src/adapters/kiro/index.js#pseudoAssetId use. The
263
263
  * lifecycle layer validates every change's assetId against the harness's actual asset list, so an
264
264
  * invented id like the literal string 'opencode.config' is rejected as unknown. */
265
- function pseudoAssetId(assets: any) {
266
- return assets.find((asset: any) => asset.capability === 'instructions')?.id ?? assets[0]?.id;
265
+ function pseudoAssetId(assets ) {
266
+ return assets.find((asset ) => asset.capability === 'instructions')?.id ?? assets[0]?.id;
267
267
  }
268
268
 
269
269
  // ---- MCP entries (opencode.json `mcp`) ----
270
270
 
271
271
  /** OpenCode's own server shape: a local server whose command and arguments form one array. */
272
- function buildServerEntry(server: any) {
272
+ function buildServerEntry(server ) {
273
273
  return { type: 'local', command: [server.command, ...(server.args || [])], enabled: true };
274
274
  }
275
275
 
276
- function ownershipIdentity(id: any) { return `doflow:${HARNESS}:mcp-server:${id}`; }
276
+ function ownershipIdentity(id ) { return `doflow:${HARNESS}:mcp-server:${id}`; }
277
277
 
278
278
  /** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. */
279
- function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] }: any) {
280
- const rendered = (servers: any) => servers.map((server: any) => ({ id: server.id, entry: buildServerEntry(server) }));
281
- const rows = (ledger?.resources || []).filter((row: any) => row.kind === 'mcp-server');
279
+ function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] } ) {
280
+ const rendered = (servers ) => servers.map((server ) => ({ id: server.id, entry: buildServerEntry(server) }));
281
+ const rows = (ledger?.resources || []).filter((row ) => row.kind === 'mcp-server');
282
282
  return {
283
283
  file: paths.config, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
284
- ownRows: rows.filter((row: any) => row.harness === HARNESS).map((row: any) => ({
284
+ ownRows: rows.filter((row ) => row.harness === HARNESS).map((row ) => ({
285
285
  identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false,
286
286
  })),
287
- foreignRows: rows.filter((row: any) => row.harness !== HARNESS).map((row: any) => ({ harness: row.harness, identity: row.identity, target: row.target })),
287
+ foreignRows: rows.filter((row ) => row.harness !== HARNESS).map((row ) => ({ harness: row.harness, identity: row.identity, target: row.target })),
288
288
  identityFor: ownershipIdentity, assetId: pseudoAssetId(assets), renderer: MCP_RENDERER, label: 'OpenCode MCP',
289
289
  };
290
290
  }
291
291
 
292
292
  /** opencode.json cannot be edited safely while removing: its registration row is released with
293
293
  * the entry rows, so the removal completes and leaves the file as it is. */
294
- function releasedConfigRow({ assets, paths, ledger }: any) {
295
- const owned = (ledger?.resources || []).some((row: any) => row.harness === HARNESS && row.ownershipIdentity === `${HARNESS}:config:registration` && row.target === paths.config);
294
+ function releasedConfigRow({ assets, paths, ledger } ) {
295
+ const owned = (ledger?.resources || []).some((row ) => row.harness === HARNESS && row.ownershipIdentity === `${HARNESS}:config:registration` && row.target === paths.config);
296
296
  return owned ? [{ assetId: pseudoAssetId(assets), target: paths.config, operation: 'remove', release: true,
297
297
  ownershipIdentity: `${HARNESS}:config:registration`, harness: HARNESS, projection: { renderer: 'opencode-config' } }] : [];
298
298
  }
299
299
 
300
- function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs }: any) {
300
+ function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs } ) {
301
301
  const found = discovery || discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, context, fsImpl });
302
302
  const changes = [];
303
303
  const conflicts = [];
@@ -306,7 +306,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
306
306
  // below, under a fixed reason that never quotes the file.
307
307
  const configReadable = found.mcpSnapshot[found.paths.config].ok;
308
308
 
309
- const guidance = assets.find((asset: any) => asset.capability === 'instructions');
309
+ const guidance = assets.find((asset ) => asset.capability === 'instructions');
310
310
  if (guidance) {
311
311
  const rendered = render({ content: fsImpl.readFileSync(path.resolve(context.repoRoot, guidance.source), 'utf8') });
312
312
  const outcome = removing
@@ -333,7 +333,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
333
333
  // Tagged 'remove' during a remove operation (rather than always 'update'/'create') so this
334
334
  // adapter's own apply()/remove() dispatch — which routes strictly on `operation` — writes
335
335
  // the unmerged file during removal instead of silently skipping it (the same fix
336
- // src/adapters/copilot/index.ts's analogous mcp-merge change already carries).
336
+ // src/adapters/copilot/index.js's analogous mcp-merge change already carries).
337
337
  operation: removing ? 'remove' : (found.config.exists ? 'update' : 'create'), content: `${JSON.stringify(next, null, 2)}\n`,
338
338
  ownershipIdentity: `${HARNESS}:config:registration`, fingerprint: fingerprint(next),
339
339
  harness: HARNESS, projection: { renderer: 'opencode-config' } });
@@ -355,14 +355,14 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
355
355
  return { changes, conflicts, notices: [...copyTree.notices, ...mcpPlan.notices], paths: found.paths };
356
356
  }
357
357
 
358
- function writeChange(change: any, fsImpl: any) {
358
+ function writeChange(change , fsImpl ) {
359
359
  fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
360
360
  fsImpl.writeFileSync(change.target, change.content, 'utf8');
361
361
  }
362
362
 
363
363
  // The config change is written first; the entry changes then go to a fresh read of the same file,
364
364
  // so they apply on top of it.
365
- function apply({ changes = [], fsImpl = fs }: any) {
365
+ function apply({ changes = [], fsImpl = fs } ) {
366
366
  let applied = 0;
367
367
  for (const change of changes) {
368
368
  if (change.operation === 'remove') continue;
@@ -378,7 +378,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
378
378
  return { applied };
379
379
  }
380
380
 
381
- function remove({ changes = [], fsImpl = fs }: any) {
381
+ function remove({ changes = [], fsImpl = fs } ) {
382
382
  let removed = 0;
383
383
  for (const change of changes) {
384
384
  if (change.operation !== 'remove') continue;
@@ -392,13 +392,13 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
392
392
  return { removed };
393
393
  }
394
394
 
395
- function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs }: any) {
395
+ function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs } ) {
396
396
  const found = discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, context, fsImpl });
397
397
  const removing = (operation ?? context.operation) === 'remove';
398
398
  const statuses = [];
399
399
  const resources = [];
400
400
  const conflicts = [];
401
- const instructionsAssetId = assets.find((asset: any) => asset.capability === 'instructions')?.id ?? pseudoAssetId(assets);
401
+ const instructionsAssetId = assets.find((asset ) => asset.capability === 'instructions')?.id ?? pseudoAssetId(assets);
402
402
 
403
403
  const hasSection = typeof found.instruction === 'string'
404
404
  && found.instruction.includes(MARKER_START) && found.instruction.includes(MARKER_END);
@@ -445,7 +445,7 @@ function createOpenCodeAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
445
445
 
446
446
  const copyTree = verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl });
447
447
  resources.push(...copyTree.resources);
448
- statuses.push(...copyTree.statuses.map((status: any) => ({ harness: HARNESS, ...status })));
448
+ statuses.push(...copyTree.statuses.map((status ) => ({ harness: HARNESS, ...status })));
449
449
  conflicts.push(...copyTree.conflicts);
450
450
 
451
451
  return { ok: conflicts.length === 0 && !statuses.some((s) => s.status === 'invalid' || s.status === 'conflict'), resources, statuses, conflicts };