@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.
- package/bin/doflow.js +2 -2
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/registry/storage.json +87 -83
- package/core/registry/verification.json +1 -1
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -2
- package/core/shared/skills/do-execute-plan/references/scaffold.md +2 -2
- package/package.json +4 -2
- package/src/adapters/antigravity/{index.ts → index.js} +60 -60
- package/src/adapters/claude/{index.ts → index.js} +48 -48
- package/src/adapters/claude/{mcp.ts → mcp.js} +16 -16
- package/src/adapters/codex/{agents.ts → agents.js} +24 -24
- package/src/adapters/codex/{config.ts → config.js} +49 -49
- package/src/adapters/codex/{hooks.ts → hooks.js} +23 -23
- package/src/adapters/codex/{index.ts → index.js} +98 -98
- package/src/adapters/codex/{mcp.ts → mcp.js} +38 -38
- package/src/adapters/codex/{native-projection.ts → native-projection.js} +5 -5
- package/src/adapters/copilot/{index.ts → index.js} +42 -42
- package/src/adapters/{copy-tree.ts → copy-tree.js} +70 -70
- package/src/adapters/gemini/{hooks.ts → hooks.js} +24 -24
- package/src/adapters/gemini/{index.ts → index.js} +41 -41
- package/src/adapters/{hook-commands.ts → hook-commands.js} +8 -8
- package/src/adapters/{index.ts → index.js} +13 -13
- package/src/adapters/kiro/{index.ts → index.js} +34 -34
- package/src/adapters/{mcp-entries.ts → mcp-entries.js} +55 -55
- package/src/adapters/opencode/{index.ts → index.js} +52 -52
- package/src/adapters/pi/{index.ts → index.js} +30 -30
- package/src/adapters/pi/{json-members.ts → json-members.js} +23 -23
- package/src/adapters/pi/{mcp.ts → mcp.js} +70 -70
- package/src/adapters/{resolve-source.ts → resolve-source.js} +1 -1
- package/src/cli/commands/{install.ts → install.js} +24 -24
- package/src/cli/commands/{list-backups.ts → list-backups.js} +4 -4
- package/src/cli/commands/{reconcile.ts → reconcile.js} +19 -19
- package/src/cli/commands/{remove.ts → remove.js} +10 -10
- package/src/cli/commands/{rollback.ts → rollback.js} +17 -17
- package/src/cli/commands/{self-update.ts → self-update.js} +3 -3
- package/src/cli/commands/{status.ts → status.js} +24 -24
- package/src/cli/commands/{tools.ts → tools.js} +16 -16
- package/src/cli/commands/{update.ts → update.js} +19 -19
- package/src/cli/{index.ts → index.js} +26 -26
- package/src/cli/{runtime-commands.ts → runtime-commands.js} +48 -48
- package/src/cli/{shared.ts → shared.js} +40 -40
- package/src/helper/{bash-helper.ts → bash-helper.js} +7 -7
- package/src/helper/{git.ts → git.js} +2 -2
- package/src/helper/{guardrails.ts → guardrails.js} +10 -10
- package/src/helper/{harness-paths.ts → harness-paths.js} +24 -24
- package/src/helper/{marker-merge.ts → marker-merge.js} +4 -4
- package/src/helper/{prompt.ts → prompt.js} +5 -5
- package/src/helper/{repo-root.ts → repo-root.js} +2 -2
- package/src/helper/{settings-merge.ts → settings-merge.js} +27 -27
- package/src/helper/{settings-scope.ts → settings-scope.js} +3 -3
- package/src/helper/{toml.ts → toml.js} +48 -48
- package/src/install/{backup-set.ts → backup-set.js} +16 -16
- package/src/install/{backup.ts → backup.js} +65 -65
- package/src/install/{context.ts → context.js} +15 -15
- package/src/install/{manifest.ts → manifest.js} +27 -27
- package/src/install/{mcp.ts → mcp.js} +30 -30
- package/src/install/{paths.ts → paths.js} +15 -15
- package/src/install/{targets.ts → targets.js} +10 -10
- package/src/install/{tool-lifecycle.ts → tool-lifecycle.js} +20 -20
- package/src/lifecycle/{bash-availability.ts → bash-availability.js} +1 -1
- package/src/lifecycle/{index.ts → index.js} +140 -140
- package/src/lifecycle/{mcp-index.ts → mcp-index.js} +1 -1
- package/src/lifecycle/{policies.ts → policies.js} +11 -11
- package/src/lifecycle/{view.ts → view.js} +28 -28
- package/src/registry/{index.ts → index.js} +60 -60
- package/src/release/build-package.js +91 -0
- package/src/release/changelog-section.js +70 -0
- package/src/release/{sync-plugin-versions.ts → sync-plugin-versions.js} +4 -4
- package/src/runtime/advice/{cli.ts → cli.js} +31 -31
- package/src/runtime/advice/{client.ts → client.js} +44 -44
- package/src/runtime/advice/{config.ts → config.js} +16 -16
- package/src/runtime/advice/{doctor.ts → doctor.js} +32 -32
- package/src/runtime/advice/{endpoint-guard.ts → endpoint-guard.js} +20 -20
- package/src/runtime/advice/{kinds.ts → kinds.js} +16 -16
- package/src/runtime/advice/providers/{ollama-systemone.ts → ollama-systemone.js} +21 -21
- package/src/runtime/advice/{record.ts → record.js} +19 -19
- package/src/runtime/advice/{registry.ts → registry.js} +16 -16
- package/src/runtime/advice/{strength.ts → strength.js} +7 -7
- package/src/runtime/{brief-tools.ts → brief-tools.js} +50 -50
- package/src/runtime/{c4-project.ts → c4-project.js} +27 -27
- package/src/runtime/{capability-router.ts → capability-router.js} +39 -39
- package/src/runtime/{checkouts.ts → checkouts.js} +21 -21
- package/src/runtime/{claims.ts → claims.js} +30 -30
- package/src/runtime/{cli-result.ts → cli-result.js} +4 -4
- package/src/runtime/{cli.ts → cli.js} +37 -37
- package/src/runtime/{command-detect.ts → command-detect.js} +47 -47
- package/src/runtime/{context-pack.ts → context-pack.js} +20 -20
- package/src/runtime/{decision-register.ts → decision-register.js} +67 -67
- package/src/runtime/{evidence-ledger.ts → evidence-ledger.js} +25 -25
- package/src/runtime/failure/{capture.ts → capture.js} +29 -29
- package/src/runtime/failure/{classifier.ts → classifier.js} +4 -4
- package/src/runtime/failure/{cli.ts → cli.js} +30 -30
- package/src/runtime/failure/{home.ts → home.js} +6 -6
- package/src/runtime/failure/{store.ts → store.js} +32 -32
- package/src/runtime/{feature-resolve.ts → feature-resolve.js} +6 -6
- package/src/runtime/{freshness.ts → freshness.js} +15 -15
- package/src/runtime/{health.ts → health.js} +72 -72
- package/src/runtime/{history-compactor.ts → history-compactor.js} +25 -25
- package/src/runtime/{implementation-gate.ts → implementation-gate.js} +30 -30
- package/src/runtime/inventory/{coverage.ts → coverage.js} +10 -10
- package/src/runtime/inventory/{identity.ts → identity.js} +2 -2
- package/src/runtime/inventory/{index.ts → index.js} +36 -36
- package/src/runtime/inventory/{precedence.ts → precedence.js} +2 -2
- package/src/runtime/inventory/{read-scopes.ts → read-scopes.js} +9 -9
- package/src/runtime/inventory/{siblings.ts → siblings.js} +15 -15
- package/src/runtime/knowledge/{chunker.ts → chunker.js} +12 -12
- package/src/runtime/knowledge/{hybrid.ts → hybrid.js} +17 -17
- package/src/runtime/knowledge/{index-store.ts → index-store.js} +23 -23
- package/src/runtime/knowledge/{retrieval.ts → retrieval.js} +27 -27
- package/src/runtime/{leak-scan.ts → leak-scan.js} +12 -12
- package/src/runtime/lifecycle/{cli.ts → cli.js} +32 -32
- package/src/runtime/lifecycle/{event-store.ts → event-store.js} +48 -48
- package/src/runtime/lifecycle/{fold.ts → fold.js} +41 -41
- package/src/runtime/lifecycle/{followup.ts → followup.js} +54 -54
- package/src/runtime/lifecycle/{goal.ts → goal.js} +50 -50
- package/src/runtime/lifecycle/{intent-writer.ts → intent-writer.js} +5 -5
- package/src/runtime/lifecycle/{overview.ts → overview.js} +47 -47
- package/src/runtime/lifecycle/{release.ts → release.js} +29 -29
- package/src/runtime/lifecycle/{report-store.ts → report-store.js} +25 -25
- package/src/runtime/lifecycle/{retention.ts → retention.js} +37 -37
- package/src/runtime/lifecycle/{root.ts → root.js} +9 -9
- package/src/runtime/lifecycle/{status.ts → status.js} +64 -64
- package/src/runtime/lifecycle/{store-upkeep.ts → store-upkeep.js} +46 -46
- package/src/runtime/{locator-resolve.ts → locator-resolve.js} +7 -7
- package/src/runtime/{mask.ts → mask.js} +22 -22
- package/src/runtime/{mcp-consultations.ts → mcp-consultations.js} +54 -54
- package/src/runtime/{mcp-reach.ts → mcp-reach.js} +24 -24
- package/src/runtime/{model-router.ts → model-router.js} +20 -20
- package/src/runtime/{outcome.ts → outcome.js} +27 -27
- package/src/runtime/{reach.ts → reach.js} +21 -21
- package/src/runtime/{readiness-record.ts → readiness-record.js} +12 -12
- package/src/runtime/{readiness.ts → readiness.js} +35 -35
- package/src/runtime/{recovery.ts → recovery.js} +15 -15
- package/src/runtime/{research-request.ts → research-request.js} +34 -34
- package/src/runtime/{retrieval-plan.ts → retrieval-plan.js} +40 -40
- package/src/runtime/scaffold/{artifacts.ts → artifacts.js} +19 -19
- package/src/runtime/scaffold/{fingerprint.ts → fingerprint.js} +3 -3
- package/src/runtime/scaffold/{generate.ts → generate.js} +109 -109
- package/src/runtime/scaffold/{languages.ts → languages.js} +34 -34
- package/src/runtime/storage/{cli.ts → cli.js} +9 -9
- package/src/runtime/storage/{engine.ts → engine.js} +37 -37
- package/src/runtime/storage/{registry.ts → registry.js} +19 -19
- package/src/runtime/storage/{roots.ts → roots.js} +8 -8
- package/src/runtime/storage/{rules.ts → rules.js} +26 -26
- package/src/runtime/storage/{upkeep.ts → upkeep.js} +35 -35
- package/src/runtime/storage/{work-status.ts → work-status.js} +39 -39
- package/src/runtime/{task-attempts.ts → task-attempts.js} +61 -61
- package/src/runtime/{task-classifier.ts → task-classifier.js} +34 -34
- package/src/runtime/{task-scope.ts → task-scope.js} +13 -13
- package/src/runtime/{task-state.ts → task-state.js} +15 -15
- package/src/runtime/trace/{indicators.ts → indicators.js} +22 -22
- package/src/runtime/trace/{ledger.ts → ledger.js} +42 -42
- package/src/runtime/trace/{render.ts → render.js} +7 -7
- package/src/runtime/trace/{views.ts → views.js} +40 -40
- package/src/runtime/verification/{contract-runner.ts → contract-runner.js} +23 -23
- package/src/runtime/verification/{engine.ts → engine.js} +143 -143
- package/src/runtime/verification/{registry.ts → registry.js} +6 -6
- package/src/runtime/verification/{scope-bound.ts → scope-bound.js} +50 -50
- package/src/runtime/verification/{test-selection.ts → test-selection.js} +28 -28
- package/src/runtime/{workflow-engine.ts → workflow-engine.js} +50 -50
- package/src/runtime/{workflow-orchestrator.ts → workflow-orchestrator.js} +91 -91
- package/src/runtime/{worktree.ts → worktree.js} +31 -31
- package/src/state/{index.ts → index.js} +26 -26
- package/src/state/{lockfile.ts → lockfile.js} +20 -20
- package/src/state/{run-lock.ts → run-lock.js} +44 -44
|
@@ -20,10 +20,10 @@ const fs = require('node:fs');
|
|
|
20
20
|
const os = require('node:os');
|
|
21
21
|
const path = require('node:path');
|
|
22
22
|
|
|
23
|
-
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.
|
|
24
|
-
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor } = require('../copy-tree.
|
|
25
|
-
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.
|
|
26
|
-
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.
|
|
23
|
+
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.js');
|
|
24
|
+
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor } = require('../copy-tree.js');
|
|
25
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
|
|
26
|
+
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.js');
|
|
27
27
|
|
|
28
28
|
const HARNESS = 'antigravity';
|
|
29
29
|
const MCP_CONTAINER = 'mcpServers';
|
|
@@ -31,7 +31,7 @@ const MCP_RENDERER = 'antigravity-mcp';
|
|
|
31
31
|
|
|
32
32
|
/** copy-tree's readJson distinguishes absent/unparseable via an {exists,value,error} envelope;
|
|
33
33
|
* every caller here wants the plain object or {}. */
|
|
34
|
-
function readJsonObject(file
|
|
34
|
+
function readJsonObject(file , { fsImpl = fs } = {}) {
|
|
35
35
|
const result = readJson(file, { fsImpl });
|
|
36
36
|
if (!result || !result.exists || result.error) return {};
|
|
37
37
|
return result.value ?? {};
|
|
@@ -54,20 +54,20 @@ const GATE_MATCHER = 'write_to_file|replace_file_content|multi_replace_file_cont
|
|
|
54
54
|
/** Build DoFlow's hooks.json groups from the projected scripts' on-disk locations. Absolute command
|
|
55
55
|
* path: the docs' own examples use relative ./scripts paths whose resolution base is not stated,
|
|
56
56
|
* and an absolute path is unambiguous for a per-workspace install. */
|
|
57
|
-
function hookGroups({ gateCommand, stopCommand }
|
|
57
|
+
function hookGroups({ gateCommand, stopCommand } ) {
|
|
58
58
|
return {
|
|
59
59
|
[HOOKS_GROUP]: { PreToolUse: [{ matcher: GATE_MATCHER, hooks: [{ type: 'command', command: gateCommand }] }] },
|
|
60
60
|
[STOP_HOOKS_GROUP]: { Stop: [{ type: 'command', command: stopCommand }] },
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
function hookScriptTarget(identity
|
|
64
|
+
function hookScriptTarget(identity , paths ) {
|
|
65
65
|
return identity === 'pre-implementation-gate.sh' ? paths.hookScript : paths.stopHookScript;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl = fs }
|
|
69
|
-
const changes
|
|
70
|
-
const conflicts
|
|
68
|
+
function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl = fs } ) {
|
|
69
|
+
const changes = [];
|
|
70
|
+
const conflicts = [];
|
|
71
71
|
if (scope !== 'project') {
|
|
72
72
|
// The shims resolve the workspace via git/transcriptPath; a user-scope hooks.json would fire
|
|
73
73
|
// against every project including non-git ones. Project-only until a documented user story exists.
|
|
@@ -76,9 +76,9 @@ function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl
|
|
|
76
76
|
const target = paths.hooksJson;
|
|
77
77
|
const scriptSource = sourceDirFor({ source: 'core/harnesses/antigravity/hooks' }, { repoRoot }, fsImpl, HARNESS);
|
|
78
78
|
|
|
79
|
-
const previousHookRows = (neutralResources || []).filter((r
|
|
80
|
-
const previousScriptRows = (neutralResources || []).filter((r
|
|
81
|
-
const docRow = previousHookRows.find((r
|
|
79
|
+
const previousHookRows = (neutralResources || []).filter((r ) => r.harness === HARNESS && r.assetId === HOOKS_ASSET_ID && r.kind === 'hooks-json');
|
|
80
|
+
const previousScriptRows = (neutralResources || []).filter((r ) => r.harness === HARNESS && r.assetId === HOOKS_ASSET_ID && r.kind === 'copy-tree-file');
|
|
81
|
+
const docRow = previousHookRows.find((r ) => r.target === target);
|
|
82
82
|
|
|
83
83
|
if (removing) {
|
|
84
84
|
if (docRow || fsImpl.existsSync(target)) {
|
|
@@ -89,7 +89,7 @@ function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl
|
|
|
89
89
|
}
|
|
90
90
|
for (const identity of HOOK_SCRIPTS) {
|
|
91
91
|
const scriptTarget = hookScriptTarget(identity, paths);
|
|
92
|
-
const scriptRow = previousScriptRows.find((r
|
|
92
|
+
const scriptRow = previousScriptRows.find((r ) => r.identity === identity);
|
|
93
93
|
if (scriptRow && fsImpl.existsSync(scriptTarget)) {
|
|
94
94
|
const current = sha256File(fsImpl, scriptTarget);
|
|
95
95
|
if (current === scriptRow.fingerprint) {
|
|
@@ -130,7 +130,7 @@ function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl
|
|
|
130
130
|
return { changes, conflicts };
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
function sha256File(fsImpl
|
|
133
|
+
function sha256File(fsImpl , file ) {
|
|
134
134
|
return require('node:crypto').createHash('sha256').update(fsImpl.readFileSync(file)).digest('hex');
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -138,7 +138,7 @@ function sha256File(fsImpl: any, file: any) {
|
|
|
138
138
|
* ("paths"): project customization lives at <root>/.agents, global config at ~/.gemini/config
|
|
139
139
|
* (the shared-customization root); instructions and skills are project-only surfaces, so no user
|
|
140
140
|
* rule is declared for them and they resolve to null there. */
|
|
141
|
-
function resolveNativePaths(declaredPaths
|
|
141
|
+
function resolveNativePaths(declaredPaths , { scope, scopeRoot, homeDir } = {}) {
|
|
142
142
|
if (scope !== 'project' && scope !== 'global') throw new Error(`Unsupported Antigravity scope '${scope}'`);
|
|
143
143
|
const resolved = resolveHarnessPaths(declaredPaths, { scope, scopeRoot, homeDir });
|
|
144
144
|
return {
|
|
@@ -168,33 +168,33 @@ function nativePaths(options = {}) {
|
|
|
168
168
|
* keeps its planners module-level (they already thread resolved `paths` explicitly), so injection
|
|
169
169
|
* flows through an optional `impl.nativePaths` seam instead of a full closure rewrite.
|
|
170
170
|
*/
|
|
171
|
-
function createAntigravityAdapter({ declaredPaths = DEFAULT_DECLARED_PATHS }
|
|
172
|
-
const nativePathsFor = (options
|
|
171
|
+
function createAntigravityAdapter({ declaredPaths = DEFAULT_DECLARED_PATHS } = {}) {
|
|
172
|
+
const nativePathsFor = (options ) => resolveNativePaths(declaredPaths, options);
|
|
173
173
|
return {
|
|
174
174
|
nativePaths: nativePathsFor,
|
|
175
|
-
discover: (options
|
|
175
|
+
discover: (options , impl = {}) => discover(options, { ...impl, nativePaths: nativePathsFor }),
|
|
176
176
|
render,
|
|
177
|
-
plan: (options
|
|
177
|
+
plan: (options , impl = {}) => plan(options, { ...impl, nativePaths: nativePathsFor }),
|
|
178
178
|
apply,
|
|
179
179
|
remove,
|
|
180
|
-
verify: (options
|
|
180
|
+
verify: (options , impl = {}) => verify(options, { ...impl, nativePaths: nativePathsFor }),
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const singleton = createAntigravityAdapter();
|
|
185
185
|
|
|
186
186
|
/** The scope's paths exactly as plan() and verify() resolve them, so discovery reads the same files. */
|
|
187
|
-
function scopePaths(options
|
|
187
|
+
function scopePaths(options , resolvePaths = singleton.nativePaths) {
|
|
188
188
|
return resolvePaths({ ...options, scope: options.scope ?? 'project', homeDir: options.context?.homeDir });
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
function ledgerResources(options
|
|
191
|
+
function ledgerResources(options ) {
|
|
192
192
|
return options.ledger?.resources ?? options.managedResources ?? [];
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/** Discovery keeps the MCP files as plan read them (`mcpSnapshot`), which verify compares against,
|
|
196
196
|
* and reports the servers DoFlow owns in mcp_config.json now (`mcpOwned`). */
|
|
197
|
-
function discover(options
|
|
197
|
+
function discover(options , { fsImpl = fs, nativePaths: resolvePaths = singleton.nativePaths } = {}) {
|
|
198
198
|
const paths = scopePaths(options, resolvePaths);
|
|
199
199
|
const instruction = paths.instruction && fsImpl.existsSync(paths.instruction)
|
|
200
200
|
? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
@@ -206,11 +206,11 @@ function discover(options: any, { fsImpl = fs, nativePaths: resolvePaths = singl
|
|
|
206
206
|
return { paths, instruction, mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
function render({ content = '' }
|
|
209
|
+
function render({ content = '' } = {}) {
|
|
210
210
|
return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
function managedInstruction(existing
|
|
213
|
+
function managedInstruction(existing , rendered ) {
|
|
214
214
|
if (existing === null) return { ok: true, operation: 'create', content: rendered };
|
|
215
215
|
const start = existing.indexOf(MARKER_START);
|
|
216
216
|
const end = existing.indexOf(MARKER_END);
|
|
@@ -224,7 +224,7 @@ function managedInstruction(existing: any, rendered: any) {
|
|
|
224
224
|
return { ok: true, operation: content === existing ? 'none' : 'merge', content };
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
function strippedInstruction(existing
|
|
227
|
+
function strippedInstruction(existing ) {
|
|
228
228
|
if (typeof existing !== 'string') return null;
|
|
229
229
|
const start = existing.indexOf(MARKER_START);
|
|
230
230
|
const end = existing.indexOf(MARKER_END);
|
|
@@ -239,7 +239,7 @@ function strippedInstruction(existing: any) {
|
|
|
239
239
|
/** Scope policy mirrors the registry notes, resolved from each asset's own flat nativeDir:
|
|
240
240
|
* ../x or .agents/x or .doflow/x → rooted at the install root (project scope)
|
|
241
241
|
* plain names (bin, agents) → inside the scope's config dir (.agents | ~/.gemini/config) */
|
|
242
|
-
function treeDestFor(asset
|
|
242
|
+
function treeDestFor(asset , paths , scope ) {
|
|
243
243
|
const nativeDir = asset.nativeDir;
|
|
244
244
|
if (!nativeDir) return null;
|
|
245
245
|
if (asset.id === 'skills.doflow') {
|
|
@@ -263,7 +263,7 @@ function treeDestFor(asset: any, paths: any, scope: any) {
|
|
|
263
263
|
return path.join(paths.configDir, nativeDir);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
-
function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot, force = false, fsImpl = fs }
|
|
266
|
+
function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot, force = false, fsImpl = fs } ) {
|
|
267
267
|
const changes = [];
|
|
268
268
|
const conflicts = [];
|
|
269
269
|
const treeResults = [];
|
|
@@ -285,10 +285,10 @@ function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot,
|
|
|
285
285
|
// planTrees as well, since its signature did not carry the context the others already had.
|
|
286
286
|
force: !removing && force === true });
|
|
287
287
|
treeResults.push(result);
|
|
288
|
-
conflicts.push(...result.conflicts.map((reason
|
|
288
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
289
289
|
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
290
290
|
// ownership row is released.
|
|
291
|
-
notices.push(...result.kept.map((item
|
|
291
|
+
notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
|
|
292
292
|
for (const change of result.changes) {
|
|
293
293
|
changes.push({
|
|
294
294
|
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
@@ -303,15 +303,15 @@ function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot,
|
|
|
303
303
|
return { changes, conflicts, targets, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
function runTreeChanges(changes
|
|
306
|
+
function runTreeChanges(changes , mode ) {
|
|
307
307
|
// Route by what each change IS, not by which verb invoked us: remove() delegates here with a
|
|
308
308
|
// plan full of operation:'remove' changes, and applyTree deliberately skips those — so routing
|
|
309
309
|
// everything through one engine call silently deleted nothing (verification then correctly
|
|
310
310
|
// refused to journal the no-op). Writes go to applyTree, removals to removeTree, always.
|
|
311
311
|
void mode;
|
|
312
312
|
const treeChanges = changes
|
|
313
|
-
.filter((c
|
|
314
|
-
.map((c
|
|
313
|
+
.filter((c ) => c.projection?.renderer === 'copy-tree' || c.kind === 'copy-tree-file')
|
|
314
|
+
.map((c ) => ({ relPath: c.identity ?? c.relPath, target: c.target,
|
|
315
315
|
source: c._text ? undefined : c.source, operation: c.operation,
|
|
316
316
|
fingerprint: c.fingerprint, pruneGuard: c.pruneGuard, ...(c._text ? { _text: c._text } : {}) }));
|
|
317
317
|
// Content-managed tree files (hook scripts): write rendered text with +x, not a byte copy.
|
|
@@ -324,17 +324,17 @@ function runTreeChanges(changes: any, mode: any) {
|
|
|
324
324
|
}
|
|
325
325
|
return {
|
|
326
326
|
applied: 0, removed: 0,
|
|
327
|
-
...(function ()
|
|
328
|
-
const plain = treeChanges.filter((t
|
|
329
|
-
const writes = plain.filter((c
|
|
330
|
-
const removals = plain.filter((c
|
|
327
|
+
...(function () {
|
|
328
|
+
const plain = treeChanges.filter((t ) => t._text === undefined);
|
|
329
|
+
const writes = plain.filter((c ) => c.operation !== 'remove');
|
|
330
|
+
const removals = plain.filter((c ) => c.operation === 'remove');
|
|
331
331
|
const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
|
|
332
332
|
const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
|
|
333
333
|
return { applied, removed };
|
|
334
334
|
})(),
|
|
335
335
|
};
|
|
336
|
-
const writes = treeChanges.filter((c
|
|
337
|
-
const removals = treeChanges.filter((c
|
|
336
|
+
const writes = treeChanges.filter((c ) => c.operation !== 'remove');
|
|
337
|
+
const removals = treeChanges.filter((c ) => c.operation === 'remove');
|
|
338
338
|
const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
|
|
339
339
|
const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
|
|
340
340
|
return { applied, removed };
|
|
@@ -342,7 +342,7 @@ function runTreeChanges(changes: any, mode: any) {
|
|
|
342
342
|
|
|
343
343
|
// ---- instructions component ----
|
|
344
344
|
|
|
345
|
-
function planInstructions({ paths, assets, removing, repoRoot, fsImpl = fs }
|
|
345
|
+
function planInstructions({ paths, assets, removing, repoRoot, fsImpl = fs } ) {
|
|
346
346
|
if (scopeOf(paths) !== 'project') return { changes: [], conflicts: [] };
|
|
347
347
|
void repoRoot;
|
|
348
348
|
if (removing) {
|
|
@@ -380,7 +380,7 @@ function planInstructions({ paths, assets, removing, repoRoot, fsImpl = fs }: an
|
|
|
380
380
|
};
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
-
function pointerBody(fsImpl
|
|
383
|
+
function pointerBody(fsImpl ) {
|
|
384
384
|
// The shared pointer prose ships once; read it through the same repo-relative anchor the other
|
|
385
385
|
// AGENTS-style adapters use.
|
|
386
386
|
try {
|
|
@@ -388,11 +388,11 @@ function pointerBody(fsImpl: any) {
|
|
|
388
388
|
} catch { return null; }
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
function scopeOf(paths
|
|
391
|
+
function scopeOf(paths ) { return paths.scope; }
|
|
392
392
|
|
|
393
393
|
// ---- MCP component ----
|
|
394
394
|
|
|
395
|
-
function mcpDefinitionFor(server
|
|
395
|
+
function mcpDefinitionFor(server ) {
|
|
396
396
|
// Remote transports project url/httpUrl -> serverUrl per the current Antigravity schema.
|
|
397
397
|
if (server.transport === 'stdio') {
|
|
398
398
|
return { command: server.command, ...(server.args?.length ? { args: server.args } : {}) };
|
|
@@ -400,27 +400,27 @@ function mcpDefinitionFor(server: any) {
|
|
|
400
400
|
return { serverUrl: server.url ?? server.httpUrl };
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
function ownershipIdentity(id
|
|
403
|
+
function ownershipIdentity(id ) { return `doflow:${HARNESS}:mcp-server:${id}`; }
|
|
404
404
|
|
|
405
405
|
/** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. Rows
|
|
406
406
|
* recorded before entries were fingerprinted carry `fingerprint: null`; such a row owns its entry
|
|
407
407
|
* only while the entry still equals DoFlow's rendering. */
|
|
408
|
-
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], resources = [] }
|
|
409
|
-
const rendered = (servers
|
|
410
|
-
const rows = resources.filter((row
|
|
408
|
+
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], resources = [] } ) {
|
|
409
|
+
const rendered = (servers ) => servers.map((server ) => ({ id: server.id, entry: mcpDefinitionFor(server) }));
|
|
410
|
+
const rows = resources.filter((row ) => row.kind === 'mcp-server');
|
|
411
411
|
return {
|
|
412
412
|
file: paths.mcpFile, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
|
|
413
|
-
ownRows: rows.filter((row
|
|
413
|
+
ownRows: rows.filter((row ) => row.harness === HARNESS).map((row ) => ({
|
|
414
414
|
identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false,
|
|
415
415
|
})),
|
|
416
|
-
foreignRows: rows.filter((row
|
|
416
|
+
foreignRows: rows.filter((row ) => row.harness !== HARNESS).map((row ) => ({ harness: row.harness, identity: row.identity, target: row.target })),
|
|
417
417
|
identityFor: ownershipIdentity, assetId: POINTER_ASSET_ID, renderer: MCP_RENDERER, label: 'Antigravity MCP',
|
|
418
418
|
};
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
// ---- required six-function surface ----
|
|
422
422
|
|
|
423
|
-
function plan(options
|
|
423
|
+
function plan(options = {}, impl = {}) {
|
|
424
424
|
const fsImpl = impl.fsImpl || fs;
|
|
425
425
|
const context = options.context ?? {};
|
|
426
426
|
const scope = options.scope ?? 'project';
|
|
@@ -449,7 +449,7 @@ function plan(options: any = {}, impl: any = {}) {
|
|
|
449
449
|
};
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
-
function apply(options
|
|
452
|
+
function apply(options = {}, impl = {}) {
|
|
453
453
|
const fsImpl = impl.fsImpl || fs;
|
|
454
454
|
// apply()/verify() are reached through the lifecycle with the same scope inputs plan() saw, so
|
|
455
455
|
// they re-derive paths instead of trusting plan-private state. `paths` itself is unused here —
|
|
@@ -458,7 +458,7 @@ function apply(options: any = {}, impl: any = {}) {
|
|
|
458
458
|
(impl.nativePaths ?? singleton.nativePaths)(options);
|
|
459
459
|
const changes = options.changes ?? [];
|
|
460
460
|
|
|
461
|
-
for (const change of changes.filter((c
|
|
461
|
+
for (const change of changes.filter((c ) => c.projection?.renderer === 'antigravity-instructions')) {
|
|
462
462
|
if (change.operation === 'remove') {
|
|
463
463
|
// pi precedent: strip only the managed span; the file survives even when nothing remains.
|
|
464
464
|
if (!fsImpl.existsSync(change.target)) continue;
|
|
@@ -469,7 +469,7 @@ function apply(options: any = {}, impl: any = {}) {
|
|
|
469
469
|
fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
|
|
470
470
|
fsImpl.writeFileSync(change.target, change._content ?? render({ content: '' }), 'utf8');
|
|
471
471
|
}
|
|
472
|
-
for (const change of changes.filter((c
|
|
472
|
+
for (const change of changes.filter((c ) => c.projection?.renderer === 'antigravity-hooks')) {
|
|
473
473
|
if (change.kind === 'copy-tree-file') continue; // handled by runTreeChanges below
|
|
474
474
|
if (change.operation === 'remove') {
|
|
475
475
|
// Unmerge only DoFlow's groups (one per policy); a user's own hook groups survive.
|
|
@@ -502,11 +502,11 @@ function apply(options: any = {}, impl: any = {}) {
|
|
|
502
502
|
// Removal flows through apply(): plan(context.operation='remove') emits operation:'remove'
|
|
503
503
|
// changes, and the branches above already know how to execute each kind. The six-function
|
|
504
504
|
// contract still requires the verb itself.
|
|
505
|
-
function remove(options
|
|
505
|
+
function remove(options = {}, impl = {}) {
|
|
506
506
|
return apply(options, impl);
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
-
function verify(options
|
|
509
|
+
function verify(options = {}, impl = {}) {
|
|
510
510
|
const fsImpl = impl.fsImpl || fs;
|
|
511
511
|
const context = options.context ?? {};
|
|
512
512
|
const scope = options.scope ?? 'project';
|
|
@@ -565,7 +565,7 @@ function verify(options: any = {}, impl: any = {}) {
|
|
|
565
565
|
// Hooks projection (project scope): the shims' bytes and the registered groups.
|
|
566
566
|
if (scope === 'project') {
|
|
567
567
|
const hooksTarget = paths.hooksJson;
|
|
568
|
-
const scriptTargets
|
|
568
|
+
const scriptTargets = {
|
|
569
569
|
'pre-implementation-gate.sh': paths.hookScript,
|
|
570
570
|
'stop-check.sh': paths.stopHookScript,
|
|
571
571
|
};
|
|
@@ -573,7 +573,7 @@ function verify(options: any = {}, impl: any = {}) {
|
|
|
573
573
|
// projection, not an install destination — the destination is declared as the paths above).
|
|
574
574
|
const scriptSourceDir = path.join(path.resolve(registryRepoRoot(options)), 'core', 'harnesses', 'antigravity', 'hooks');
|
|
575
575
|
const removingOp = (context.operation ?? options.operation ?? '') === 'remove';
|
|
576
|
-
const fingerprints
|
|
576
|
+
const fingerprints = {};
|
|
577
577
|
let scriptsOk = true;
|
|
578
578
|
let anyPresent = false;
|
|
579
579
|
for (const identity of HOOK_SCRIPTS) {
|
|
@@ -617,11 +617,11 @@ function verify(options: any = {}, impl: any = {}) {
|
|
|
617
617
|
return { ok: conflicts.length === 0, statuses, resources, conflicts };
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
function registryRepoRoot(options
|
|
620
|
+
function registryRepoRoot(options ) {
|
|
621
621
|
return options.registry?.repoRoot ?? process.cwd();
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
-
function conflictsToStatuses(conflicts
|
|
624
|
+
function conflictsToStatuses(conflicts , assetId , statuses ) {
|
|
625
625
|
for (const reason of conflicts) statuses.push({ assetId, capability: 'scripts', status: 'conflict', reason });
|
|
626
626
|
}
|
|
627
627
|
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
const crypto = require('node:crypto');
|
|
8
8
|
const fs = require('node:fs');
|
|
9
9
|
const path = require('node:path');
|
|
10
|
-
const { mergeMarkedSection, removeMarkedSection, MARKER_START, MARKER_END } = require('../../helper/marker-merge.
|
|
11
|
-
const { selectMcpServers } = require('../../registry/index.
|
|
12
|
-
const { GLOBAL_HOOK_PREFIX, PROJECT_HOOK_PREFIX } = require('../../helper/settings-scope.
|
|
13
|
-
const { mergeSettings, settingsContains, settingsContainsAny, stripManagedSettings } = require('../../helper/settings-merge.
|
|
14
|
-
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, resolveTransform } = require('../copy-tree.
|
|
15
|
-
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.
|
|
16
|
-
const { discoverMcp, planMcp, writeMcp, verifyMcp } = require('./mcp.
|
|
10
|
+
const { mergeMarkedSection, removeMarkedSection, MARKER_START, MARKER_END } = require('../../helper/marker-merge.js');
|
|
11
|
+
const { selectMcpServers } = require('../../registry/index.js');
|
|
12
|
+
const { GLOBAL_HOOK_PREFIX, PROJECT_HOOK_PREFIX } = require('../../helper/settings-scope.js');
|
|
13
|
+
const { mergeSettings, settingsContains, settingsContainsAny, stripManagedSettings } = require('../../helper/settings-merge.js');
|
|
14
|
+
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, resolveTransform } = require('../copy-tree.js');
|
|
15
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
|
|
16
|
+
const { discoverMcp, planMcp, writeMcp, verifyMcp } = require('./mcp.js');
|
|
17
17
|
|
|
18
18
|
const INSTRUCTION_RENDERER = 'claude-instructions';
|
|
19
19
|
const SETTINGS_RENDERER = 'claude-settings';
|
|
@@ -30,11 +30,11 @@ const SETTINGS_RENDERER = 'claude-settings';
|
|
|
30
30
|
*/
|
|
31
31
|
const SETTINGS_FILES = ['settings.json', 'keybindings.json'];
|
|
32
32
|
|
|
33
|
-
function sha256(value
|
|
33
|
+
function sha256(value ) {
|
|
34
34
|
return crypto.createHash('sha256').update(value).digest('hex');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function sourcePath(asset
|
|
37
|
+
function sourcePath(asset , context = {}) {
|
|
38
38
|
if (!asset || typeof asset.source !== 'string') throw new Error('Claude asset requires a source path');
|
|
39
39
|
const repoRoot = context.repoRoot ? path.resolve(context.repoRoot) : process.cwd();
|
|
40
40
|
const source = path.resolve(repoRoot, asset.source);
|
|
@@ -44,7 +44,7 @@ function sourcePath(asset: any, context: any = {}) {
|
|
|
44
44
|
return source;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function markerState(file
|
|
47
|
+
function markerState(file ) {
|
|
48
48
|
if (!fs.existsSync(file)) return { exists: false, managed: false, malformed: false };
|
|
49
49
|
const text = fs.readFileSync(file, 'utf8');
|
|
50
50
|
const starts = text.split(MARKER_START).length - 1;
|
|
@@ -53,8 +53,8 @@ function markerState(file: any) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** Single serialization form for every settings write, so repeated runs are byte-stable. */
|
|
56
|
-
const serializeSettings = (value
|
|
57
|
-
const settingsChangeExtras = (fileName
|
|
56
|
+
const serializeSettings = (value ) => `${JSON.stringify(value, null, 2)}\n`;
|
|
57
|
+
const settingsChangeExtras = (fileName ) => ({ kind: 'settings-file', identity: fileName });
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Native path facts live in core/registry/harnesses.json under this harness's "paths" section and
|
|
@@ -67,18 +67,18 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
67
67
|
// Parity note: Claude's historical nativePaths() resolved BOTH scopes' root from scopeRoot (the
|
|
68
68
|
// CLI passes $HOME there for -g installs) and never consulted homeDir — so the resolver is fed
|
|
69
69
|
// no homeDir and "root" keeps resolving exactly as before.
|
|
70
|
-
function nativePaths({ scope, scopeRoot }
|
|
70
|
+
function nativePaths({ scope, scopeRoot } = {}) {
|
|
71
71
|
return resolveHarnessPaths(declaredPaths, { scope, scopeRoot });
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, registry, homeDir, context = {} }
|
|
74
|
+
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, registry, homeDir, context = {} } ) {
|
|
75
75
|
const paths = nativePaths({ scope, scopeRoot });
|
|
76
76
|
return {
|
|
77
77
|
paths,
|
|
78
78
|
instructions: markerState(paths.instructions),
|
|
79
79
|
settingsExists: fs.existsSync(paths.settings),
|
|
80
80
|
mcpExists: fs.existsSync(paths.mcp),
|
|
81
|
-
knownMcpServers: registry ? selectMcpServers(registry).map((server
|
|
81
|
+
knownMcpServers: registry ? selectMcpServers(registry).map((server ) => server.id) : [],
|
|
82
82
|
...discoverMcp({ paths, mcp, mcpAdoptable, ledger, scope, scopeRoot, homeDir: context.homeDir || homeDir || undefined }),
|
|
83
83
|
};
|
|
84
84
|
}
|
|
@@ -88,11 +88,11 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
88
88
|
/** Every asset materialised through the copy-tree engine, whatever its declared renderer:
|
|
89
89
|
* verbatim mirrors declare 'copy-tree', transformed projections (output styles) declare their
|
|
90
90
|
* own name so the registry can tell the shapes apart. Routing is on `kind`, which both share. */
|
|
91
|
-
function claudeTreeAssets(assets
|
|
92
|
-
return [...copyTreeAssets(assets), ...(assets || []).filter((asset
|
|
91
|
+
function claudeTreeAssets(assets ) {
|
|
92
|
+
return [...copyTreeAssets(assets), ...(assets || []).filter((asset ) => asset.renderer === 'claude-output-styles')];
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing }
|
|
95
|
+
function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing } ) {
|
|
96
96
|
const paths = nativePaths({ scope, scopeRoot });
|
|
97
97
|
const changes = [];
|
|
98
98
|
const conflicts = [];
|
|
@@ -109,10 +109,10 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
109
109
|
// is never deleted on removal, forced or not.
|
|
110
110
|
force: !removing && context?.force === true, });
|
|
111
111
|
treeResults.push(result);
|
|
112
|
-
conflicts.push(...result.conflicts.map((reason
|
|
112
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
113
113
|
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
114
114
|
// ownership row is released.
|
|
115
|
-
notices.push(...result.kept.map((item
|
|
115
|
+
notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
|
|
116
116
|
for (const change of result.changes) {
|
|
117
117
|
changes.push({
|
|
118
118
|
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
@@ -128,7 +128,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
128
128
|
return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
function applyCopyTreeAssets(changes
|
|
131
|
+
function applyCopyTreeAssets(changes ) {
|
|
132
132
|
let applied = 0;
|
|
133
133
|
const grouped = new Map();
|
|
134
134
|
for (const change of changes) {
|
|
@@ -143,13 +143,13 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
143
143
|
return applied;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
function removeCopyTreeAssets(changes
|
|
147
|
-
const treeChanges = changes.filter((change
|
|
148
|
-
.map((change
|
|
146
|
+
function removeCopyTreeAssets(changes ) {
|
|
147
|
+
const treeChanges = changes.filter((change ) => change.kind === 'copy-tree-file' && change.operation === 'remove' && !change.retained)
|
|
148
|
+
.map((change ) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
|
|
149
149
|
return removeTree({ changes: treeChanges }).removed;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
function verifyCopyTreeAssets({ assets, scope, scopeRoot, context }
|
|
152
|
+
function verifyCopyTreeAssets({ assets, scope, scopeRoot, context } ) {
|
|
153
153
|
const paths = nativePaths({ scope, scopeRoot });
|
|
154
154
|
const statuses = [];
|
|
155
155
|
const resources = [];
|
|
@@ -158,7 +158,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
158
158
|
const destDir = copyTreeDestDir(paths.configDir, asset);
|
|
159
159
|
const sourceDir = sourcePath(asset, context);
|
|
160
160
|
const result = verifyTree({ sourceDir, destDir, layout: asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
|
|
161
|
-
conflicts.push(...result.conflicts.map((reason
|
|
161
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
162
162
|
for (const resource of result.resources) {
|
|
163
163
|
resources.push({
|
|
164
164
|
assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:claude:copy-tree:${asset.id}:${resource.relPath}`,
|
|
@@ -174,16 +174,16 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
174
174
|
|
|
175
175
|
// ---- claude-settings asset (settings.json + keybindings.json) ----
|
|
176
176
|
|
|
177
|
-
function settingsAsset(assets
|
|
178
|
-
function settingsTarget(fileName
|
|
177
|
+
function settingsAsset(assets ) { return (assets || []).find((asset ) => asset?.renderer === SETTINGS_RENDERER); }
|
|
178
|
+
function settingsTarget(fileName , paths ) {
|
|
179
179
|
// Per-file dispatch across the two DECLARED settings surfaces (paths.settings / paths.keybindings):
|
|
180
180
|
// residue because the authored file list is content-shaped, not a single declarable destination.
|
|
181
181
|
return fileName === 'settings.json' ? paths.settings : paths.keybindings;
|
|
182
182
|
}
|
|
183
|
-
function settingsContent(fileName
|
|
183
|
+
function settingsContent(fileName , raw , scope ) {
|
|
184
184
|
return fileName === 'settings.json' && scope !== 'global' ? raw.split(GLOBAL_HOOK_PREFIX).join(PROJECT_HOOK_PREFIX) : raw;
|
|
185
185
|
}
|
|
186
|
-
function settingsLedgerResources(ledger
|
|
186
|
+
function settingsLedgerResources(ledger , assetId ) {
|
|
187
187
|
const byFile = new Map();
|
|
188
188
|
for (const resource of ledger?.resources || []) {
|
|
189
189
|
if (resource.harness === 'claude' && resource.assetId === assetId && resource.kind === 'settings-file') byFile.set(resource.identity, resource);
|
|
@@ -194,7 +194,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
194
194
|
|
|
195
195
|
/** Inject (or leave untouched) the statusLine key pointing at the projected script. Refuses to
|
|
196
196
|
* overwrite a user's existing custom status line unless forced: their script is theirs. */
|
|
197
|
-
function withStatusLineKey(rawSettingsJson
|
|
197
|
+
function withStatusLineKey(rawSettingsJson , scriptPath , force ) {
|
|
198
198
|
let parsed;
|
|
199
199
|
try {
|
|
200
200
|
parsed = JSON.parse(rawSettingsJson);
|
|
@@ -207,10 +207,10 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
207
207
|
return serializeSettings(parsed);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
function planSettingsAsset({ assets, scope, scopeRoot, context, ledger, removing }
|
|
210
|
+
function planSettingsAsset({ assets, scope, scopeRoot, context, ledger, removing } ) {
|
|
211
211
|
const asset = settingsAsset(assets);
|
|
212
|
-
const changes
|
|
213
|
-
const conflicts
|
|
212
|
+
const changes = [];
|
|
213
|
+
const conflicts = [];
|
|
214
214
|
if (!asset) return { changes, conflicts };
|
|
215
215
|
const paths = nativePaths({ scope, scopeRoot });
|
|
216
216
|
const sourceDir = sourcePath(asset, context);
|
|
@@ -311,7 +311,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
311
311
|
// other copy-tree/settings write in this codebase — planSettingsAsset's own change detection is
|
|
312
312
|
// fingerprint(sha256)-based, not mtime-based, so this is a consistency convention, not a
|
|
313
313
|
// correctness requirement.
|
|
314
|
-
function applySettingsAsset(changes
|
|
314
|
+
function applySettingsAsset(changes ) {
|
|
315
315
|
let applied = 0;
|
|
316
316
|
for (const change of changes) {
|
|
317
317
|
if (change.projection?.renderer !== SETTINGS_RENDERER || change.operation === 'remove') continue;
|
|
@@ -328,7 +328,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
328
328
|
// is deleted outright only when nothing but schema pointers remains — i.e. DoFlow created it.
|
|
329
329
|
// Previously this rmSync'd unconditionally, which on a user-maintained settings.json would have
|
|
330
330
|
// destroyed their model, permissions, env, and every foreign tool's hooks along with ours.
|
|
331
|
-
function removeSettingsAsset(changes
|
|
331
|
+
function removeSettingsAsset(changes ) {
|
|
332
332
|
let removed = 0;
|
|
333
333
|
for (const change of changes) {
|
|
334
334
|
if (change.projection?.renderer !== SETTINGS_RENDERER || change.operation !== 'remove') continue;
|
|
@@ -347,11 +347,11 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
347
347
|
return removed;
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
function verifySettingsAsset({ assets, scope, scopeRoot, context }
|
|
350
|
+
function verifySettingsAsset({ assets, scope, scopeRoot, context } ) {
|
|
351
351
|
const asset = settingsAsset(assets);
|
|
352
|
-
const statuses
|
|
353
|
-
const resources
|
|
354
|
-
const conflicts
|
|
352
|
+
const statuses = [];
|
|
353
|
+
const resources = [];
|
|
354
|
+
const conflicts = [];
|
|
355
355
|
if (!asset) return { statuses, resources, conflicts };
|
|
356
356
|
const paths = nativePaths({ scope, scopeRoot });
|
|
357
357
|
const sourceDir = sourcePath(asset, context);
|
|
@@ -424,9 +424,9 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
424
424
|
|
|
425
425
|
/** Render native Claude input without writing it.
|
|
426
426
|
* `asset` is the lifecycle-projected shape (flat `renderer`/`capability` fields — see
|
|
427
|
-
* src/adapters/index.
|
|
427
|
+
* src/adapters/index.js#projectAdapterInput), not the raw registry asset's nested
|
|
428
428
|
* `asset.projection.claude`. Every adapter method below shares that same expectation. */
|
|
429
|
-
function render({ asset, scope, scopeRoot, context = {} }
|
|
429
|
+
function render({ asset, scope, scopeRoot, context = {} } ) {
|
|
430
430
|
const paths = nativePaths({ scope, scopeRoot });
|
|
431
431
|
if (asset?.renderer === INSTRUCTION_RENDERER) {
|
|
432
432
|
const source = sourcePath(asset, context);
|
|
@@ -444,7 +444,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
444
444
|
return { type: 'unsupported', assetId: asset?.id, renderer: asset?.renderer ?? null };
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
function plan({ assets, scope, scopeRoot, mcp = [], mcpAdoptable = [], discovery, context = {}, ledger }
|
|
447
|
+
function plan({ assets, scope, scopeRoot, mcp = [], mcpAdoptable = [], discovery, context = {}, ledger } ) {
|
|
448
448
|
const changes = [];
|
|
449
449
|
const conflicts = [];
|
|
450
450
|
const paths = nativePaths({ scope, scopeRoot });
|
|
@@ -480,13 +480,13 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
480
480
|
return { changes, conflicts, prerequisites: [], notices: [...copyTree.notices, ...mcpPlan.notices] };
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
function apply({ changes, scope, scopeRoot, context = {} }
|
|
483
|
+
function apply({ changes, scope, scopeRoot, context = {} } ) {
|
|
484
484
|
for (const change of changes) {
|
|
485
485
|
if (change.projection?.renderer !== INSTRUCTION_RENDERER) continue;
|
|
486
486
|
// A plan records the resolved source. This keeps apply self-contained when
|
|
487
487
|
// the lifecycle supplies normalized changes rather than the original asset
|
|
488
488
|
// array, while still avoiding any implicit source discovery at write time.
|
|
489
|
-
const source = change.source ?? sourcePath((context.assets || []).find((item
|
|
489
|
+
const source = change.source ?? sourcePath((context.assets || []).find((item ) => item.id === change.assetId), context);
|
|
490
490
|
mergeMarkedSection(source, change.target ?? nativePaths({ scope, scopeRoot }).instructions);
|
|
491
491
|
}
|
|
492
492
|
applyCopyTreeAssets(changes);
|
|
@@ -498,7 +498,7 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
498
498
|
return { applied: changes.length };
|
|
499
499
|
}
|
|
500
500
|
|
|
501
|
-
function remove({ changes }
|
|
501
|
+
function remove({ changes } ) {
|
|
502
502
|
let removed = 0;
|
|
503
503
|
for (const change of changes) {
|
|
504
504
|
if (change.projection?.renderer === INSTRUCTION_RENDERER && removeMarkedSection(change.target)) removed += 1;
|
|
@@ -509,11 +509,11 @@ function createClaudeAdapter({ declaredPaths = declaredHarnessPaths().claude } =
|
|
|
509
509
|
return { removed };
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
-
function verify({ assets, scope, scopeRoot, mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {} }
|
|
512
|
+
function verify({ assets, scope, scopeRoot, mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {} } ) {
|
|
513
513
|
const paths = nativePaths({ scope, scopeRoot });
|
|
514
514
|
const statuses = [];
|
|
515
515
|
const resources = [];
|
|
516
|
-
const instruction = assets.find((asset
|
|
516
|
+
const instruction = assets.find((asset ) => asset?.renderer === INSTRUCTION_RENDERER);
|
|
517
517
|
const state = markerState(paths.instructions);
|
|
518
518
|
if (instruction) {
|
|
519
519
|
statuses.push({ assetId: instruction.id, status: state.managed ? 'managed' : 'absent', target: paths.instructions });
|