@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
|
@@ -13,24 +13,24 @@ const {
|
|
|
13
13
|
parseToml,
|
|
14
14
|
newViolation,
|
|
15
15
|
atomicWrite,
|
|
16
|
-
} = require('./config.
|
|
17
|
-
const { selectMcpServers, nativeMcpCatalog } = require('../../registry/index.
|
|
18
|
-
const { NOTICES } = require('../mcp-entries.
|
|
19
|
-
const { stripComment } = require('../../helper/toml.
|
|
16
|
+
} = require('./config.js');
|
|
17
|
+
const { selectMcpServers, nativeMcpCatalog } = require('../../registry/index.js');
|
|
18
|
+
const { NOTICES } = require('../mcp-entries.js');
|
|
19
|
+
const { stripComment } = require('../../helper/toml.js');
|
|
20
20
|
|
|
21
21
|
const MCP_KIND = 'mcp-server';
|
|
22
22
|
const MCP_PREFIX = 'mcp_servers.';
|
|
23
23
|
|
|
24
24
|
/** @param {object} registry a loaded registry (src/registry#loadRegistry) */
|
|
25
|
-
function readCodexMcpCatalog(registry
|
|
25
|
+
function readCodexMcpCatalog(registry ) {
|
|
26
26
|
return nativeMcpCatalog(selectMcpServers(registry));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function isSafeServerName(name
|
|
29
|
+
function isSafeServerName(name ) {
|
|
30
30
|
return /^[A-Za-z0-9_-]+$/.test(name);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function tomlValue(value
|
|
33
|
+
function tomlValue(value ) {
|
|
34
34
|
if (typeof value === 'string') return JSON.stringify(value);
|
|
35
35
|
if (typeof value === 'boolean' || typeof value === 'number') return String(value);
|
|
36
36
|
if (Array.isArray(value)) return `[${value.map(tomlValue).join(', ')}]`;
|
|
@@ -40,7 +40,7 @@ function tomlValue(value: any): string {
|
|
|
40
40
|
throw new Error('Codex MCP definitions may only contain TOML-compatible values');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function renderServer(name
|
|
43
|
+
function renderServer(name , definition ) {
|
|
44
44
|
if (!isSafeServerName(name)) throw new Error(`Unsupported Codex MCP server name '${name}'`);
|
|
45
45
|
if (!definition || typeof definition !== 'object' || Array.isArray(definition)) {
|
|
46
46
|
throw new Error(`Codex MCP server '${name}' requires an object definition`);
|
|
@@ -56,7 +56,7 @@ function renderServer(name: any, definition: any) {
|
|
|
56
56
|
return `${lines.join('\n')}\n`;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function resourceFor({ name, scope, definition, sourceVersion, recoveryPoint }
|
|
59
|
+
function resourceFor({ name, scope, definition, sourceVersion, recoveryPoint } ) {
|
|
60
60
|
return {
|
|
61
61
|
target: 'codex', scope, kind: MCP_KIND, identity: name,
|
|
62
62
|
sourceVersion, selection: true, recoveryPoint,
|
|
@@ -64,12 +64,12 @@ function resourceFor({ name, scope, definition, sourceVersion, recoveryPoint }:
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
function isOwnedRecord(resource
|
|
67
|
+
function isOwnedRecord(resource , scope ) {
|
|
68
68
|
return resource && resource.target === 'codex' && resource.scope === scope &&
|
|
69
69
|
resource.kind === MCP_KIND && typeof resource.identity === 'string';
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
function tableRanges(text
|
|
72
|
+
function tableRanges(text ) {
|
|
73
73
|
const lines = text.split(/\r?\n/);
|
|
74
74
|
const tables = [];
|
|
75
75
|
for (let index = 0; index < lines.length; index++) {
|
|
@@ -96,25 +96,25 @@ function tableRanges(text: any) {
|
|
|
96
96
|
return { lines, tables };
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
function fullServerRange(tables
|
|
100
|
-
return tables.find((table
|
|
99
|
+
function fullServerRange(tables , name ) {
|
|
100
|
+
return tables.find((table ) => table.name === name) ?? null;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/** One table's text as its fingerprint is taken. */
|
|
104
|
-
function tableText(lines
|
|
104
|
+
function tableText(lines , range ) {
|
|
105
105
|
return `${lines.slice(range.start, range.end).join('\n').replace(/\n*$/, '\n')}`;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** Whether config.toml defines server `name` in any form: a bare `[mcp_servers.<name>]` header, a
|
|
109
109
|
* quoted header, a sub-table, or dotted keys and inline tables under `mcp_servers`. */
|
|
110
|
-
function definedInFile(name
|
|
111
|
-
const own = (key
|
|
112
|
-
return tables.some((table
|
|
110
|
+
function definedInFile(name , { tables, parsed } ) {
|
|
111
|
+
const own = (key ) => key === `${MCP_PREFIX}${name}` || key.startsWith(`${MCP_PREFIX}${name}.`);
|
|
112
|
+
return tables.some((table ) => table.name === name) || parsed.headers.some((header ) => own(header.table))
|
|
113
113
|
|| [...parsed.entries.keys()].some(own);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/** The text of server `name`'s bare table, as its fingerprint is taken, or null when it has none. */
|
|
117
|
-
function serverTableText(text
|
|
117
|
+
function serverTableText(text , name ) {
|
|
118
118
|
const { lines, tables } = tableRanges(text);
|
|
119
119
|
const range = fullServerRange(tables, name);
|
|
120
120
|
return range ? tableText(lines, range) : null;
|
|
@@ -122,35 +122,35 @@ function serverTableText(text: any, name: any) {
|
|
|
122
122
|
|
|
123
123
|
/** The names among `names` that config.toml defines with no owned record: the user's own servers,
|
|
124
124
|
* which DoFlow never writes, removes or records. A file that cannot be read or parsed yields none. */
|
|
125
|
-
function userDefinedCodexMcpIds({ file, scope, names = [], managedResources = [], fsImpl = fs }
|
|
125
|
+
function userDefinedCodexMcpIds({ file, scope, names = [], managedResources = [], fsImpl = fs } ) {
|
|
126
126
|
let text; let parsed;
|
|
127
127
|
try {
|
|
128
128
|
text = fsImpl.existsSync(file) ? fsImpl.readFileSync(file, 'utf8') : '';
|
|
129
129
|
parsed = parseToml(text);
|
|
130
130
|
} catch { return []; }
|
|
131
131
|
const { tables } = tableRanges(text);
|
|
132
|
-
const owned = new Set(managedResources.filter((resource
|
|
132
|
+
const owned = new Set(managedResources.filter((resource ) => isOwnedRecord(resource, scope)).map((resource ) => resource.identity));
|
|
133
133
|
return [...new Set(names)].filter((name) => !owned.has(name) && definedInFile(name, { tables, parsed }));
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/** The tables DoFlow owns in config.toml now: owned records whose table is present with the
|
|
137
137
|
* fingerprint the record holds. A file that cannot be read or parsed yields none. */
|
|
138
|
-
function ownedCodexMcpIds({ file, scope, managedResources = [], fsImpl = fs }
|
|
138
|
+
function ownedCodexMcpIds({ file, scope, managedResources = [], fsImpl = fs } ) {
|
|
139
139
|
let text;
|
|
140
140
|
try {
|
|
141
141
|
text = fsImpl.existsSync(file) ? fsImpl.readFileSync(file, 'utf8') : '';
|
|
142
142
|
parseToml(text);
|
|
143
143
|
} catch { return []; }
|
|
144
144
|
const { lines, tables } = tableRanges(text);
|
|
145
|
-
return managedResources.filter((resource
|
|
145
|
+
return managedResources.filter((resource ) => isOwnedRecord(resource, scope)).filter((resource ) => {
|
|
146
146
|
const range = fullServerRange(tables, resource.identity);
|
|
147
147
|
return range !== null && fingerprint(tableText(lines, range)) === resource.fingerprint;
|
|
148
|
-
}).map((resource
|
|
148
|
+
}).map((resource ) => resource.identity);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/** How to stop managing a server whose table the user changed: the same run without it selected. */
|
|
152
|
-
function modifiedConflict(name
|
|
153
|
-
const rest = desired.filter((item
|
|
152
|
+
function modifiedConflict(name , desired , scopeArg ) {
|
|
153
|
+
const rest = desired.filter((item ) => item !== name);
|
|
154
154
|
// Quoted for a POSIX shell when it holds anything a shell would split or expand, so the command
|
|
155
155
|
// works as copied for a project root with a space in it.
|
|
156
156
|
const arg = /^[A-Za-z0-9_@%+=:,./-]+$/.test(scopeArg) ? scopeArg : `'${scopeArg.replace(/'/g, "'\\''")}'`;
|
|
@@ -165,27 +165,27 @@ function modifiedConflict(name: any, desired: any, scopeArg: any) {
|
|
|
165
165
|
* @param {string} [options.scopeArg='-g'] the scope as the user types it (`-g` or the project root),
|
|
166
166
|
* for the command a conflict names.
|
|
167
167
|
*/
|
|
168
|
-
function planCodexMcp({ file, scope, managedResources = [], selected = [], allServers, serverDefs, sourceVersion, recoveryPoint, removing = false, scopeArg = '-g' }
|
|
168
|
+
function planCodexMcp({ file, scope, managedResources = [], selected = [], allServers, serverDefs, sourceVersion, recoveryPoint, removing = false, scopeArg = '-g' } ) {
|
|
169
169
|
const original = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
170
170
|
let parsed;
|
|
171
|
-
try { parsed = parseToml(original); } catch (error
|
|
171
|
+
try { parsed = parseToml(original); } catch (error ) {
|
|
172
172
|
return { ok: false, status: 'malformed', file, original, changes: [], conflicts: [error.message], managedResources };
|
|
173
173
|
}
|
|
174
174
|
if (!Array.isArray(allServers) || !serverDefs || typeof serverDefs !== 'object') {
|
|
175
175
|
return { ok: false, status: 'invalid-request', file, original, changes: [], conflicts: ['Codex MCP catalog is required'], managedResources };
|
|
176
176
|
}
|
|
177
|
-
const unknown = selected.filter((name
|
|
177
|
+
const unknown = selected.filter((name ) => !allServers.includes(name));
|
|
178
178
|
if (unknown.length) return { ok: false, status: 'invalid-request', file, original, changes: [], conflicts: [`Unknown MCP server(s): ${unknown.join(', ')}`], managedResources };
|
|
179
|
-
const desired
|
|
180
|
-
try { for (const name of desired) renderServer(name, serverDefs[name]); } catch (error
|
|
179
|
+
const desired = [...new Set (selected)];
|
|
180
|
+
try { for (const name of desired) renderServer(name, serverDefs[name]); } catch (error ) {
|
|
181
181
|
return { ok: false, status: 'invalid-request', file, original, changes: [], conflicts: [error.message], managedResources };
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const { lines, tables } = tableRanges(original);
|
|
185
|
-
const owned = new Map
|
|
186
|
-
const changes
|
|
187
|
-
const conflicts
|
|
188
|
-
const notices
|
|
185
|
+
const owned = new Map (managedResources.filter((resource ) => isOwnedRecord(resource, scope)).map((resource ) => [resource.identity, resource]));
|
|
186
|
+
const changes = [];
|
|
187
|
+
const conflicts = [];
|
|
188
|
+
const notices = [];
|
|
189
189
|
const userDefined = allServers.filter((name) => !owned.has(name) && definedInFile(name, { tables, parsed }));
|
|
190
190
|
const names = new Set([...desired, ...owned.keys()]);
|
|
191
191
|
for (const name of names) {
|
|
@@ -235,24 +235,24 @@ function planCodexMcp({ file, scope, managedResources = [], selected = [], allSe
|
|
|
235
235
|
const invalid = newViolation({ file, original, content, identities: changes.map((change) => change.identity) });
|
|
236
236
|
if (invalid) return { ok: false, status: 'conflict', file, original, changes: [], conflicts: [invalid], managedResources };
|
|
237
237
|
|
|
238
|
-
const nextManagedResources = managedResources.filter((resource
|
|
238
|
+
const nextManagedResources = managedResources.filter((resource ) => !isOwnedRecord(resource, scope) || desired.includes(resource.identity));
|
|
239
239
|
for (const name of desired) {
|
|
240
240
|
if (userDefined.includes(name)) continue;
|
|
241
241
|
const next = resourceFor({ name, scope, definition: serverDefs[name], sourceVersion, recoveryPoint });
|
|
242
|
-
const index = nextManagedResources.findIndex((resource
|
|
242
|
+
const index = nextManagedResources.findIndex((resource ) => isOwnedRecord(resource, scope) && resource.identity === name);
|
|
243
243
|
if (index >= 0) nextManagedResources[index] = next;
|
|
244
244
|
else nextManagedResources.push(next);
|
|
245
245
|
}
|
|
246
246
|
return { ok: true, status: changes.length ? 'change' : 'unchanged', file, original, content, changes, conflicts: [], notices, userDefined, managedResources: nextManagedResources };
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
function applyCodexMcp(plan
|
|
249
|
+
function applyCodexMcp(plan , { dryRun = false, fsImpl = fs } = {}) {
|
|
250
250
|
if (!plan.ok || dryRun || plan.status === 'unchanged') return { ...plan, applied: false };
|
|
251
251
|
atomicWrite(plan.file, plan.content, fsImpl);
|
|
252
252
|
return { ...plan, applied: true };
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
function reconcileCodexMcp(options
|
|
255
|
+
function reconcileCodexMcp(options ) {
|
|
256
256
|
const file = options.file ?? configPath(options);
|
|
257
257
|
return applyCodexMcp(planCodexMcp({ ...options, file }), options);
|
|
258
258
|
}
|
|
@@ -3,25 +3,25 @@
|
|
|
3
3
|
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
4
|
|
|
5
5
|
// Codex's native-projection normalizer, moved here from the common adapter module (review A3:
|
|
6
|
-
// `nativeProjectionFor` in src/adapters/index.
|
|
6
|
+
// `nativeProjectionFor` in src/adapters/index.js contained this Codex-specific shape inline, so
|
|
7
7
|
// per-harness knowledge lived on the shared side of the adapter boundary). The common module now
|
|
8
8
|
// only dispatches by adapter name; the shape below — configResources / mcp catalog / agents dir /
|
|
9
9
|
// hooks trust — is Codex's own and belongs to its adapter directory.
|
|
10
10
|
|
|
11
|
-
const { resolveRegistrySource } = require('../resolve-source.
|
|
11
|
+
const { resolveRegistrySource } = require('../resolve-source.js');
|
|
12
12
|
|
|
13
13
|
/** Normalize the validated Codex registry declaration into its adapter's named
|
|
14
14
|
* input. Source paths always come from the registry; runtime overrides only
|
|
15
15
|
* affect an explicitly safe trust acknowledgement. */
|
|
16
|
-
function normalizeNativeProjection(registry
|
|
16
|
+
function normalizeNativeProjection(registry , harness , mcp , context ) {
|
|
17
17
|
const declaration = harness.nativeProjection;
|
|
18
18
|
const override = context.projectionOverrides?.[harness.id] ?? {};
|
|
19
19
|
if (!override || typeof override !== 'object' || Array.isArray(override)) throw new Error(`Projection override for '${harness.id}' must be an object`);
|
|
20
20
|
const trusted = override.hooks?.trusted;
|
|
21
21
|
if (trusted !== undefined && typeof trusted !== 'boolean') throw new Error(`Projection override '${harness.id}.hooks.trusted' must be boolean`);
|
|
22
22
|
return Object.freeze({
|
|
23
|
-
configResources: Object.freeze((declaration.config?.resources || []).map((resource
|
|
24
|
-
mcp: Object.freeze({ catalog: Object.freeze(mcp.map((server
|
|
23
|
+
configResources: Object.freeze((declaration.config?.resources || []).map((resource ) => Object.freeze({ ...resource }))),
|
|
24
|
+
mcp: Object.freeze({ catalog: Object.freeze(mcp.map((server ) => Object.freeze({ ...server }))), selected: Object.freeze(mcp.map((server ) => server.id)) }),
|
|
25
25
|
agents: Object.freeze({ sourceDir: resolveRegistrySource(registry, declaration.agents?.source, `${harness.id} agents`) }),
|
|
26
26
|
hooks: Object.freeze({
|
|
27
27
|
sourceFile: resolveRegistrySource(registry, declaration.hooks?.configSource, `${harness.id} hooks config`),
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
const fs = require('node:fs');
|
|
26
26
|
const path = require('node:path');
|
|
27
27
|
|
|
28
|
-
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.
|
|
29
|
-
const { planTree, applyTree, removeTree, verifyTree, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, sourceDirFor, resolveTransform } = require('../copy-tree.
|
|
30
|
-
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.
|
|
31
|
-
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.
|
|
28
|
+
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.js');
|
|
29
|
+
const { planTree, applyTree, removeTree, verifyTree, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, sourceDirFor, resolveTransform } = require('../copy-tree.js');
|
|
30
|
+
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.js');
|
|
31
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
|
|
32
32
|
|
|
33
33
|
const HARNESS = 'copilot';
|
|
34
34
|
/** Message text naming the instruction file the declared paths.instruction surface installs.
|
|
@@ -59,13 +59,13 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
59
59
|
// Parity note: Copilot's historical nativePaths() derived even its user-scope root from scopeRoot
|
|
60
60
|
// (the CLI passes $HOME there for -g installs), never from a separate homeDir argument — so the
|
|
61
61
|
// resolver is fed no homeDir and "root" keeps resolving exactly as before.
|
|
62
|
-
function nativePaths({ scope, scopeRoot }
|
|
62
|
+
function nativePaths({ scope, scopeRoot } = {}) {
|
|
63
63
|
return resolveHarnessPaths(declaredPaths, { scope, scopeRoot });
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/** Discovery keeps the MCP files as plan read them (`mcpSnapshot`), which verify compares against,
|
|
67
67
|
* and reports the servers DoFlow owns in Copilot's MCP config now (`mcpOwned`). */
|
|
68
|
-
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, fsImpl = fs }
|
|
68
|
+
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, fsImpl = fs } ) {
|
|
69
69
|
const paths = nativePaths({ scope, scopeRoot });
|
|
70
70
|
const instruction = paths.instruction && fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
71
71
|
const entries = mcpEntriesInput({ paths, mcp, mcpAdoptable, ledger });
|
|
@@ -76,7 +76,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
76
76
|
return { paths, instruction, mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
function render({ content = '' }
|
|
79
|
+
function render({ content = '' } = {}) {
|
|
80
80
|
return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -85,7 +85,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
85
85
|
* their own shared instruction files, and for the same reason: where DoFlow's content belongs in a
|
|
86
86
|
* file it doesn't fully own is a decision for the file's owner, not a guess for the installer. Add
|
|
87
87
|
* an empty marker pair to opt in. */
|
|
88
|
-
function managedInstruction(existing
|
|
88
|
+
function managedInstruction(existing , rendered ) {
|
|
89
89
|
if (existing === null) return { ok: true, operation: 'create', content: rendered };
|
|
90
90
|
const start = existing.indexOf(MARKER_START);
|
|
91
91
|
const end = existing.indexOf(MARKER_END);
|
|
@@ -97,7 +97,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
97
97
|
|
|
98
98
|
/** Strip DoFlow's span, leaving the rest of a shared copilot-instructions.md intact. Returns null
|
|
99
99
|
* when there is nothing to do, so plan() can skip the change entirely. */
|
|
100
|
-
function strippedInstruction(existing
|
|
100
|
+
function strippedInstruction(existing ) {
|
|
101
101
|
if (typeof existing !== 'string') return null;
|
|
102
102
|
const start = existing.indexOf(MARKER_START);
|
|
103
103
|
const end = existing.indexOf(MARKER_END);
|
|
@@ -110,11 +110,11 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
110
110
|
/** Plan the single instructions change (or none). Global scope always yields no change and no
|
|
111
111
|
* conflict — Copilot documents no global instructions file, so there is nothing to skip *to*,
|
|
112
112
|
* mirroring how other adapters skip a capability with no native equivalent for a given scope. */
|
|
113
|
-
function planInstructionsChange({ assets, found, context, removing, fsImpl }
|
|
113
|
+
function planInstructionsChange({ assets, found, context, removing, fsImpl } ) {
|
|
114
114
|
if (!found.paths.instruction) return { changes: [], conflicts: [] };
|
|
115
115
|
// The marker-managed instruction file is one specific asset: exclude tree-projected rule
|
|
116
116
|
// assets (copilot-rule-instructions), whose `source` is a directory, not a file.
|
|
117
|
-
const guidance = assets.find((asset
|
|
117
|
+
const guidance = assets.find((asset ) => asset.capability === 'instructions' && asset.renderer !== 'copilot-rule-instructions');
|
|
118
118
|
if (!guidance) return { changes: [], conflicts: [] };
|
|
119
119
|
const outcome = removing
|
|
120
120
|
? { ok: true, operation: 'remove', content: strippedInstruction(found.instruction) }
|
|
@@ -145,13 +145,13 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
145
145
|
* one adapter's asset, not a shape another harness also needs. Format logic, not a path fact —
|
|
146
146
|
* it stays code rather than moving into the registry's path declarations.
|
|
147
147
|
*/
|
|
148
|
-
function agentFileLayout(sourceRel
|
|
148
|
+
function agentFileLayout(sourceRel ) {
|
|
149
149
|
const ext = path.extname(sourceRel);
|
|
150
150
|
const base = sourceRel.slice(0, sourceRel.length - ext.length);
|
|
151
151
|
return `${base}.agent${ext || '.md'}`;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
function planTreeAssets({ assets, renderer, destRoot, scopeRoot, layout, context, ledger, removing, fsImpl = fs }
|
|
154
|
+
function planTreeAssets({ assets, renderer, destRoot, scopeRoot, layout, context, ledger, removing, fsImpl = fs } ) {
|
|
155
155
|
const changes = [];
|
|
156
156
|
const conflicts = [];
|
|
157
157
|
const treeResults = [];
|
|
@@ -167,10 +167,10 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
167
167
|
// is never deleted on removal, forced or not.
|
|
168
168
|
force: !removing && context?.force === true, });
|
|
169
169
|
treeResults.push(result);
|
|
170
|
-
conflicts.push(...result.conflicts.map((reason
|
|
170
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
171
171
|
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
172
172
|
// ownership row is released.
|
|
173
|
-
notices.push(...result.kept.map((item
|
|
173
|
+
notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(scopeRoot, item.target)}; DoFlow no longer manages it`));
|
|
174
174
|
for (const change of result.changes) {
|
|
175
175
|
changes.push({
|
|
176
176
|
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
@@ -186,7 +186,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
186
186
|
return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
function applyCopyTreeAssets(changes
|
|
189
|
+
function applyCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
190
190
|
let applied = 0;
|
|
191
191
|
const grouped = new Map();
|
|
192
192
|
for (const change of changes) {
|
|
@@ -201,13 +201,13 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
201
201
|
return applied;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
function removeCopyTreeAssets(changes
|
|
205
|
-
const treeChanges = changes.filter((change
|
|
206
|
-
.map((change
|
|
204
|
+
function removeCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
205
|
+
const treeChanges = changes.filter((change ) => change.projection?.renderer === 'copy-tree' && change.operation === 'remove' && !change.retained)
|
|
206
|
+
.map((change ) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
|
|
207
207
|
return removeTree({ changes: treeChanges, fsImpl }).removed;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
function verifyTreeAssets({ assets, renderer, destRoot, layout, context, fsImpl = fs }
|
|
210
|
+
function verifyTreeAssets({ assets, renderer, destRoot, layout, context, fsImpl = fs } ) {
|
|
211
211
|
const statuses = [];
|
|
212
212
|
const resources = [];
|
|
213
213
|
const conflicts = [];
|
|
@@ -215,7 +215,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
215
215
|
const destDir = copyTreeDestDir(destRoot, asset);
|
|
216
216
|
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Copilot');
|
|
217
217
|
const result = verifyTree({ sourceDir, destDir, fsImpl, layout: layout || asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
|
|
218
|
-
conflicts.push(...result.conflicts.map((reason
|
|
218
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
219
219
|
for (const resource of result.resources) {
|
|
220
220
|
resources.push({
|
|
221
221
|
assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${resource.relPath}`,
|
|
@@ -233,7 +233,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
233
233
|
|
|
234
234
|
/** Copilot's own per-server shape. The file may be shared with another tool (Claude Code reads the
|
|
235
235
|
* same project `.mcp.json`), so DoFlow only ever writes the entries it owns. */
|
|
236
|
-
function buildServerEntry(server
|
|
236
|
+
function buildServerEntry(server ) {
|
|
237
237
|
return {
|
|
238
238
|
command: server.command,
|
|
239
239
|
...(server.args?.length ? { args: [...server.args] } : {}),
|
|
@@ -241,43 +241,43 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
241
241
|
};
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
function ownershipIdentity(id
|
|
244
|
+
function ownershipIdentity(id ) { return `doflow:${HARNESS}:mcp-server:${id}`; }
|
|
245
245
|
|
|
246
246
|
/** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. */
|
|
247
|
-
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] }
|
|
248
|
-
const rendered = (servers
|
|
249
|
-
const rows = (ledger?.resources || []).filter((row
|
|
247
|
+
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] } ) {
|
|
248
|
+
const rendered = (servers ) => servers.map((server ) => ({ id: server.id, entry: buildServerEntry(server) }));
|
|
249
|
+
const rows = (ledger?.resources || []).filter((row ) => row.kind === 'mcp-server');
|
|
250
250
|
return {
|
|
251
251
|
file: paths.mcp, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
|
|
252
|
-
ownRows: rows.filter((row
|
|
252
|
+
ownRows: rows.filter((row ) => row.harness === HARNESS).map((row ) => ({
|
|
253
253
|
identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false,
|
|
254
254
|
})),
|
|
255
|
-
foreignRows: rows.filter((row
|
|
255
|
+
foreignRows: rows.filter((row ) => row.harness !== HARNESS).map((row ) => ({ harness: row.harness, identity: row.identity, target: row.target })),
|
|
256
256
|
identityFor: ownershipIdentity, assetId: pseudoAssetId(assets), renderer: MCP_RENDERER, label: 'Copilot MCP',
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
/** The release of the 1.18.0 whole-map row, under the asset id it was recorded with so the ledger
|
|
261
261
|
* drops exactly that row. The file is not touched. */
|
|
262
|
-
function legacyRegistrationReleases(ledger
|
|
263
|
-
return (ledger?.resources || []).filter((row
|
|
264
|
-
.map((row
|
|
262
|
+
function legacyRegistrationReleases(ledger ) {
|
|
263
|
+
return (ledger?.resources || []).filter((row ) => row.harness === HARNESS && row.ownershipIdentity === LEGACY_MCP_REGISTRATION)
|
|
264
|
+
.map((row ) => ({ assetId: row.assetId, target: row.target, operation: 'remove', release: true,
|
|
265
265
|
ownershipIdentity: row.ownershipIdentity, harness: HARNESS, projection: { renderer: MCP_RENDERER } }));
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
/** Copilot's MCP entry changes have no asset of their own in core/registry/assets.json (they are a
|
|
269
269
|
* registration side-effect of the selected MCP servers, not a projected asset), so they piggyback
|
|
270
270
|
* on a real asset id already routed to this harness — the same "pseudo-component" technique
|
|
271
|
-
* src/adapters/gemini/index.
|
|
271
|
+
* src/adapters/gemini/index.js#hooksAssetId and src/adapters/kiro/index.js#pseudoAssetId use. The
|
|
272
272
|
* lifecycle layer validates every change's assetId against the harness's actual asset list, so an
|
|
273
273
|
* invented id like a literal 'copilot.mcp' string is rejected as unknown. */
|
|
274
|
-
function pseudoAssetId(assets
|
|
275
|
-
return assets.find((asset
|
|
274
|
+
function pseudoAssetId(assets ) {
|
|
275
|
+
return assets.find((asset ) => asset.capability === 'instructions')?.id ?? assets[0]?.id;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
// ---- shared adapter contract ----
|
|
279
279
|
|
|
280
|
-
function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs }
|
|
280
|
+
function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs } ) {
|
|
281
281
|
const found = discovery || discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, fsImpl });
|
|
282
282
|
const changes = [];
|
|
283
283
|
const conflicts = [];
|
|
@@ -308,12 +308,12 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
308
308
|
return { changes, conflicts, notices: [...skills.notices, ...agents.notices, ...rules.notices, ...mcpPlan.notices], paths: found.paths };
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
-
function writeChange(change
|
|
311
|
+
function writeChange(change , fsImpl ) {
|
|
312
312
|
fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
|
|
313
313
|
fsImpl.writeFileSync(change.target, change.content, 'utf8');
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
function apply({ changes = [], fsImpl = fs }
|
|
316
|
+
function apply({ changes = [], fsImpl = fs } ) {
|
|
317
317
|
let applied = 0;
|
|
318
318
|
for (const change of changes) {
|
|
319
319
|
if (change.operation === 'remove') continue;
|
|
@@ -329,7 +329,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
329
329
|
return { applied };
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
function remove({ changes = [], fsImpl = fs }
|
|
332
|
+
function remove({ changes = [], fsImpl = fs } ) {
|
|
333
333
|
let removed = 0;
|
|
334
334
|
for (const change of changes) {
|
|
335
335
|
if (change.operation !== 'remove') continue;
|
|
@@ -343,7 +343,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
343
343
|
return { removed };
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs }
|
|
346
|
+
function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs } ) {
|
|
347
347
|
const found = discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, fsImpl });
|
|
348
348
|
const statuses = [];
|
|
349
349
|
const resources = [];
|
|
@@ -352,7 +352,7 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
352
352
|
if (found.paths.instruction) {
|
|
353
353
|
// The marker-managed instruction file is one specific asset: exclude tree-projected rule
|
|
354
354
|
// assets (copilot-rule-instructions), whose `source` is a directory, not a file.
|
|
355
|
-
const guidance = assets.find((asset
|
|
355
|
+
const guidance = assets.find((asset ) => asset.capability === 'instructions' && asset.renderer !== 'copilot-rule-instructions');
|
|
356
356
|
const hasSection = typeof found.instruction === 'string' && found.instruction.includes(MARKER_START) && found.instruction.includes(MARKER_END);
|
|
357
357
|
const assetId = guidance?.id ?? 'guidance.codex-pointer';
|
|
358
358
|
statuses.push({ harness: HARNESS, assetId, capability: 'instructions',
|
|
@@ -397,8 +397,8 @@ function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS]
|
|
|
397
397
|
agentFileLayout };
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
function treeAssetsFor(assets
|
|
401
|
-
return (assets || []).filter((asset
|
|
400
|
+
function treeAssetsFor(assets , renderer ) {
|
|
401
|
+
return (assets || []).filter((asset ) => asset?.renderer === renderer);
|
|
402
402
|
}
|
|
403
403
|
|
|
404
404
|
const singleton = createCopilotAdapter();
|