@getmarrow/install 0.1.42 → 0.1.44

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/README.md CHANGED
@@ -71,7 +71,7 @@ npx -y @getmarrow/install@latest activate
71
71
  npx -y @getmarrow/install@latest doctor
72
72
 
73
73
  # Measured API read health and local backlog
74
- npx -y @getmarrow/mcp@latest ping
74
+ npx -y --package=@getmarrow/mcp@latest marrow-mcp ping
75
75
 
76
76
  # Use only when doctor reports drift
77
77
  npx -y @getmarrow/install@latest --repair
@@ -91,16 +91,30 @@ npx @getmarrow/install controller stop
91
91
 
92
92
  Persistent controller lifecycle is currently Linux-only. On macOS or Windows, activation still installs and verifies the supported hooks without starting or signaling a background process; run `npx @getmarrow/install sidecar` under an owner-managed service and pass `--no-controller`. The controller does not silently upgrade packages, change governance policy, rotate credentials, or modify unrelated project configuration.
93
93
 
94
- ## What's New in v0.1.42
94
+ ## What's New in v0.1.44
95
95
 
96
- v0.1.42 keeps stale client detection and recovery deterministic even when other Marrow MCP clients are running on the installation host:
96
+ v0.1.44 restores exact package-chain detection and current MCP setup truth:
97
97
 
98
- - `doctor` detects active stale, mixed, or version-unknown Marrow MCP processes, including direct `node_modules/.bin/marrow-mcp` launches, without exposing command lines or credentials;
99
- - when repair is needed, `doctor` reports the executable pinned setup command, the separate owning-harness restart requirement, and the executable verification command; it does not terminate harness processes itself;
100
- - certified hooks pin MCP `3.9.57` and SDK `3.7.56` so the installed runtime matches the advertised control contract;
98
+ - exact declared, locked, and installed SDK `3.7.56` dependencies are recognized using the live public registry integrity;
99
+ - generated MCP setup, launch, and certified hook commands pin current MCP `3.9.61`;
100
+ - the installer exposes the certified MCP source SHA and public registry integrity in its programmatic adapter provenance without changing credentials, policy, or unrelated configuration;
101
+ - regression coverage rejects stale SDK lock integrity and treats MCP versions older than `3.9.61` as stale.
102
+
103
+ ## Previous: v0.1.43
104
+
105
+ v0.1.43 hardens the MCP control path and makes stale client recovery explicit:
106
+
107
+ - `doctor` detects active and configured stale, mixed, or version-unknown Marrow MCP clients without exposing command lines, file paths, configuration contents, or credentials;
108
+ - every generated MCP launch and hook uses the package-explicit `npx --package ... marrow-mcp` form so npm can resolve the executable reliably;
109
+ - when repair is needed, `doctor` reports the pinned setup command, the separate owning-harness restart requirement, and a self-test verification command; it does not terminate harness processes itself;
110
+ - certified hooks pinned MCP `3.9.59` and SDK `3.7.56` so the installed runtime matched that release's advertised control contract;
101
111
  - existing harnesses retain their honest coverage level: native hooks where supported, MCP calls where available, and governed wrappers or event contracts elsewhere;
102
112
  - package upgrades remain operator-approved and never rotate keys or rewrite unrelated configuration.
103
113
 
114
+ ## Previous: v0.1.42
115
+
116
+ v0.1.42 added deterministic active-process detection, including direct `node_modules/.bin/marrow-mcp` launches, while keeping repair operator-approved.
117
+
104
118
  ## Previous: v0.1.40
105
119
 
106
120
  v0.1.40 binds governed runs to a privacy-safe workspace fingerprint and separates observed execution from verified completion:
@@ -108,7 +122,7 @@ v0.1.40 binds governed runs to a privacy-safe workspace fingerprint and separate
108
122
  - ordinary prompts receive one compact context read; risky or mutating prompts receive one fresh runtime gate instead;
109
123
  - passive prompt telemetry is buffered locally rather than delaying the agent turn;
110
124
  - transient read failures can use clearly labeled owner-only last-known guidance, while authentication failures never use cache;
111
- - `doctor` prints the exact `npx -y @getmarrow/mcp@latest ping` command for measured current/p50/p99 latency, last success, and backlog health;
125
+ - `doctor` prints the exact `npx -y --package=@getmarrow/mcp@latest marrow-mcp ping` command for measured current/p50/p99 latency, last success, and backlog health;
112
126
  - certified hook commands pin MCP `3.9.56` and SDK `3.7.55` so advertised behavior matches that release's deployed server contract;
113
127
  - governed runtime requests attach a stable privacy-safe project fingerprint and harness label without sending the raw working-directory path;
114
128
  - successful command exit remains observed execution, not verified business completion, unless a verification command or explicit proof file supplies evidence;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmarrow/install",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "Universal installer and governed runner for Marrow agent fleets.",
5
5
  "bin": {
6
6
  "marrow-install": "bin/marrow-install.js"
@@ -1387,11 +1387,11 @@ const GENERIC_GOVERNED_COMMAND = 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/ins
1387
1387
  function localSupportedHarnesses() {
1388
1388
  const harnesses = [
1389
1389
  { display_name: 'OpenAI Codex', client_label: 'codex', category: 'agent_harness', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent codex-prod -- codex' },
1390
- { display_name: 'Claude Code', client_label: 'claude-code', category: 'agent_harness', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1391
- { display_name: 'Cursor', client_label: 'cursor', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1392
- { display_name: 'Cursor Composer', client_label: 'composer', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1393
- { display_name: 'Windsurf', client_label: 'windsurf', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1394
- { display_name: 'Cline', client_label: 'cline', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1390
+ { display_name: 'Claude Code', client_label: 'claude-code', category: 'agent_harness', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1391
+ { display_name: 'Cursor', client_label: 'cursor', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1392
+ { display_name: 'Cursor Composer', client_label: 'composer', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1393
+ { display_name: 'Windsurf', client_label: 'windsurf', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1394
+ { display_name: 'Cline', client_label: 'cline', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1395
1395
  { display_name: 'OpenCode', client_label: 'opencode', category: 'agent_harness', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent opencode-prod -- opencode' },
1396
1396
  { display_name: 'Hermes Agent', client_label: 'hermes', category: 'agent_harness', support_level: 'first_class_addon', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install hermes' },
1397
1397
  { display_name: 'OpenClaw', client_label: 'openclaw', category: 'agent_harness', support_level: 'first_class_addon', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install openclaw' },
@@ -1402,7 +1402,7 @@ function localSupportedHarnesses() {
1402
1402
  { display_name: 'Kimi', client_label: 'kimi', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
1403
1403
  { display_name: 'MiniMax', client_label: 'minimax', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
1404
1404
  { display_name: 'GLM', client_label: 'glm', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
1405
- { display_name: 'MCP-compatible clients', client_label: 'mcp', category: 'mcp_client', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
1405
+ { display_name: 'MCP-compatible clients', client_label: 'mcp', category: 'mcp_client', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx -y --package=@getmarrow/mcp@latest marrow-mcp setup' },
1406
1406
  { display_name: 'CI scripts and deploy runners', client_label: 'ci', category: 'ci_runner', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent ci-release --profile production --policy enforce -- <ci-or-deploy-command>' },
1407
1407
  { display_name: 'Custom shell/API harness', client_label: 'custom', category: 'custom_runner', support_level: 'event_contract', install_command: 'POST /v1/agent/integrations/events with harness, event_type, agent_id, and action' },
1408
1408
  ];
package/src/installer.js CHANGED
@@ -8,15 +8,30 @@ const { controllerStatus, controllerSupportedPlatform, ensureGovernanceControlle
8
8
  const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
9
9
  const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
10
10
  const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
11
- const MCP_ADAPTER_VERSION = '3.9.57';
11
+ const MCP_ADAPTER_VERSION = '3.9.61';
12
+ const MCP_ADAPTER_SOURCE_SHA = 'ebe06a5c78895e70ceea7b7383ac31d5aaacbd41';
13
+ const MCP_ADAPTER_INTEGRITY = 'sha512-6ojhKztiJp8/mZecuSnt+kiEe41COPBOjrka9j+r+yFacNl4uapW9quq/wEVo5SxuDmxolFIBaqkX6xIdaD2rA==';
12
14
  const SDK_ADAPTER_VERSION = '3.7.56';
13
- const SDK_ADAPTER_INTEGRITY = 'sha512-5htliY4wfn8a1mbLT9N4OWXqhp9fWzMHuAQgUetc3RUKjOes5mWB3t91/leRKFRRIgCnEczJN6jHXg7Aw489Mw==';
15
+ const SDK_ADAPTER_INTEGRITY = 'sha512-mllohsI4DHpcVuEL58303kpGwS/pl/HMZ99mGNo3swYLomZwwfVzcner9Bn+p0b72989NOpS1l2frY/vra1gfQ==';
14
16
  const SDK_ADAPTER_TARBALL = `https://registry.npmjs.org/@getmarrow/sdk/-/sdk-${SDK_ADAPTER_VERSION}.tgz`;
15
17
  const MCP_PACKAGE_SPEC = `@getmarrow/mcp@${MCP_ADAPTER_VERSION}`;
16
- const MCP_CONTEXT_HOOK_COMMAND = `npx -y ${MCP_PACKAGE_SPEC} context-hook`;
17
- const MCP_PRE_ACTION_HOOK_COMMAND = `npx -y ${MCP_PACKAGE_SPEC} pre-action-hook`;
18
- const MCP_ACTION_RESULT_HOOK_COMMAND = `npx -y ${MCP_PACKAGE_SPEC} hook`;
19
- const MCP_SESSION_END_HOOK_COMMAND = `npx -y ${MCP_PACKAGE_SPEC} session-hook`;
18
+ const ADAPTER_PROVENANCE = Object.freeze({
19
+ mcp: Object.freeze({
20
+ package: '@getmarrow/mcp',
21
+ version: MCP_ADAPTER_VERSION,
22
+ source_sha: MCP_ADAPTER_SOURCE_SHA,
23
+ integrity: MCP_ADAPTER_INTEGRITY,
24
+ }),
25
+ sdk: Object.freeze({
26
+ package: '@getmarrow/sdk',
27
+ version: SDK_ADAPTER_VERSION,
28
+ integrity: SDK_ADAPTER_INTEGRITY,
29
+ }),
30
+ });
31
+ const MCP_CONTEXT_HOOK_COMMAND = `npx -y --package=${MCP_PACKAGE_SPEC} marrow-mcp context-hook`;
32
+ const MCP_PRE_ACTION_HOOK_COMMAND = `npx -y --package=${MCP_PACKAGE_SPEC} marrow-mcp pre-action-hook`;
33
+ const MCP_ACTION_RESULT_HOOK_COMMAND = `npx -y --package=${MCP_PACKAGE_SPEC} marrow-mcp hook`;
34
+ const MCP_SESSION_END_HOOK_COMMAND = `npx -y --package=${MCP_PACKAGE_SPEC} marrow-mcp session-hook`;
20
35
  const NATIVE_HOOK_MATCHER = 'Bash|Edit|Write|MultiEdit|mcp__(?!marrow_).*';
21
36
  const NATIVE_EXPECTED_HOOKS = ['prompt', 'pre_action', 'action_result', 'session_end'];
22
37
  const SOURCE_CLIENTS = new Set(['claude-code', 'cursor', 'composer', 'windsurf', 'openclaw', 'codex', 'gemini', 'grok', 'deepseek', 'qwen', 'kimi', 'minimax', 'cline', 'opencode', 'hermes', 'glm', 'mcp', 'ci', 'custom', 'unknown']);
@@ -101,7 +116,7 @@ function isMcpProcessCommand(command) {
101
116
  const packageManagers = new Set(['bun', 'bunx', 'npm', 'npm-cli.js', 'npx', 'npx-cli.js', 'pnpm', 'pnpx', 'yarn']);
102
117
  const runner = executable === 'node' && args[1] ? path.basename(args[1]) : executable;
103
118
  return packageManagers.has(runner)
104
- && args.some((arg) => /^@getmarrow\/mcp(?:@[^\s]+)?$/.test(arg));
119
+ && args.some((arg) => /^(?:--package=)?@getmarrow\/mcp(?:@[^\s]+)?$/.test(arg));
105
120
  }
106
121
 
107
122
  function readLinuxProcessCommands(procRoot = '/proc') {
@@ -135,7 +150,7 @@ function inspectMcpProcesses(options = {}) {
135
150
  const mixedVersions = versions.length > 1 || (versions.length > 0 && unknownVersionProcesses > 0);
136
151
  const stale = staleVersions.length > 0;
137
152
  const needsRepair = stale || mixedVersions || unknownVersionProcesses > 0;
138
- const repairCommand = `npx -y @getmarrow/mcp@${MCP_ADAPTER_VERSION} setup`;
153
+ const repairCommand = `npx -y --package=@getmarrow/mcp@${MCP_ADAPTER_VERSION} marrow-mcp setup`;
139
154
  return {
140
155
  available: process.platform === 'linux' || Array.isArray(options.commands),
141
156
  expected_version: MCP_ADAPTER_VERSION,
@@ -148,7 +163,59 @@ function inspectMcpProcesses(options = {}) {
148
163
  exact_fix: needsRepair ? repairCommand : null,
149
164
  restart_required: needsRepair,
150
165
  restart_instruction: needsRepair ? 'Restart every owning harness to replace its active Marrow MCP process.' : null,
151
- verification_command: needsRepair ? 'npx -y @getmarrow/install@latest doctor' : null,
166
+ verification_command: needsRepair ? 'npx -y @getmarrow/install@latest doctor --self-test' : null,
167
+ };
168
+ }
169
+
170
+ function inspectMcpConfigurations(detection, options = {}) {
171
+ const home = options.home || process.env.HOME || process.env.USERPROFILE || os.homedir();
172
+ const configuredPaths = Array.isArray(options.paths) ? options.paths : [
173
+ detection?.paths?.claudeSettings,
174
+ detection?.paths?.cursorMcp,
175
+ detection?.paths?.mcpJson,
176
+ path.join(home, '.claude', 'settings.json'),
177
+ path.join(home, '.claude.json'),
178
+ path.join(home, '.cursor', 'mcp.json'),
179
+ path.join(home, '.mcp.json'),
180
+ ];
181
+ const versions = [];
182
+ let filesChecked = 0;
183
+ let configurationsFound = 0;
184
+ let unknownVersionConfigurations = 0;
185
+ for (const filePath of [...new Set(configuredPaths.filter(Boolean).map((entry) => path.resolve(String(entry))))]) {
186
+ try {
187
+ if (!fs.existsSync(filePath)) continue;
188
+ const stat = fs.lstatSync(filePath);
189
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 2 * 1024 * 1024) continue;
190
+ filesChecked += 1;
191
+ const raw = fs.readFileSync(filePath, 'utf8');
192
+ const specs = [...raw.matchAll(/@getmarrow\/mcp@(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/g)]
193
+ .map((match) => match[1]);
194
+ if (/@getmarrow\/mcp(?:@|["'\s])/.test(raw)) {
195
+ configurationsFound += 1;
196
+ if (specs.length === 0) unknownVersionConfigurations += 1;
197
+ }
198
+ versions.push(...specs);
199
+ } catch {
200
+ // Doctor remains read-only and ignores inaccessible or malformed owner configuration.
201
+ }
202
+ }
203
+ const configuredVersions = [...new Set(versions)].sort();
204
+ const staleVersions = configuredVersions.filter((version) => version !== MCP_ADAPTER_VERSION);
205
+ const mixedVersions = configuredVersions.length > 1
206
+ || (configuredVersions.length > 0 && unknownVersionConfigurations > 0);
207
+ const healthy = staleVersions.length === 0 && !mixedVersions && unknownVersionConfigurations === 0;
208
+ return {
209
+ expected_version: MCP_ADAPTER_VERSION,
210
+ files_checked: filesChecked,
211
+ configurations_found: configurationsFound,
212
+ configured_versions: configuredVersions,
213
+ unknown_version_configurations: unknownVersionConfigurations,
214
+ stale_versions: staleVersions,
215
+ mixed_versions: mixedVersions,
216
+ healthy,
217
+ exact_fix: healthy ? null : `Run npx -y --package=@getmarrow/mcp@${MCP_ADAPTER_VERSION} marrow-mcp setup in each owning workspace, update its MCP launch to npx -y --package=@getmarrow/mcp@${MCP_ADAPTER_VERSION} marrow-mcp, then restart that harness.`,
218
+ verification_command: healthy ? null : 'npx -y @getmarrow/install@latest doctor --self-test',
152
219
  };
153
220
  }
154
221
 
@@ -549,7 +616,7 @@ function passiveInstructions() {
549
616
 
550
617
  Marrow should run passively after install:
551
618
 
552
- - Use MCP hooks when available: \`npx -y @getmarrow/mcp setup\`.
619
+ - Use MCP hooks when available: \`npx -y --package=@getmarrow/mcp@latest marrow-mcp setup\`.
553
620
  - Use SDK passive runtime in owned Node processes: \`createPassiveRuntime().install()\`.
554
621
  - Keep passive token/model usage proof enabled so Marrow can show token, cost, latency, and workflow savings after real work completes.
555
622
  - Before risky work, use Marrow's decision brief or passive prompt hook.
@@ -674,7 +741,7 @@ function exactHookDescriptors(settings, eventName, command, matcher) {
674
741
  function marrowHookSubcommand(command) {
675
742
  if (typeof command !== 'string') return null;
676
743
  const match = command.trim().match(
677
- /^npx\s+(?:-y\s+)?@getmarrow\/mcp(?:@[^\s]+)?\s+(context-hook|pre-action-hook|hook|session-hook)$/,
744
+ /^npx\s+(?:-y\s+)?(?:--package=@getmarrow\/mcp(?:@[^\s]+)?\s+marrow-mcp|@getmarrow\/mcp(?:@[^\s]+)?)\s+(context-hook|pre-action-hook|hook|session-hook)$/,
678
745
  );
679
746
  return match?.[1] || null;
680
747
  }
@@ -839,7 +906,7 @@ function activationProfile(detection, plan, changes, client) {
839
906
  if (capabilityLevel === 'mcp' && mcpConfigs.some((config) => (
840
907
  config?.mcpServers?.marrow?.command === 'npx'
841
908
  && Array.isArray(config.mcpServers.marrow.args)
842
- && config.mcpServers.marrow.args.join(' ') === `-y ${MCP_PACKAGE_SPEC}`
909
+ && config.mcpServers.marrow.args.join(' ') === `-y --package=${MCP_PACKAGE_SPEC} marrow-mcp`
843
910
  ))) observedHooks.push('mcp_tool_calls');
844
911
  const fingerprintMaterial = changes
845
912
  .filter((change) => change.applied || change.already_present)
@@ -877,7 +944,7 @@ function upsertMcpServerConfig(filePath) {
877
944
  : {};
878
945
  servers.marrow = {
879
946
  command: 'npx',
880
- args: ['-y', MCP_PACKAGE_SPEC],
947
+ args: ['-y', `--package=${MCP_PACKAGE_SPEC}`, 'marrow-mcp'],
881
948
  env: {
882
949
  MARROW_API_KEY: '${MARROW_API_KEY}',
883
950
  MARROW_BASE_URL: '${MARROW_BASE_URL}',
@@ -1647,6 +1714,11 @@ function printReport(report) {
1647
1714
  if (processes.restart_instruction) process.stdout.write(`- restart required: ${processes.restart_instruction}\n`);
1648
1715
  if (processes.verification_command) process.stdout.write(`- verify repair: ${processes.verification_command}\n`);
1649
1716
  }
1717
+ if (report.doctor.mcpConfigurations) {
1718
+ const configurations = report.doctor.mcpConfigurations;
1719
+ process.stdout.write(`- configured MCP versions: ${configurations.configured_versions.length ? configurations.configured_versions.join(', ') : 'none pinned'}\n`);
1720
+ process.stdout.write(`- stale/mixed/version-unknown MCP configuration: ${configurations.healthy ? 'no' : 'yes'}\n`);
1721
+ }
1650
1722
  if (report.doctor.recommendedFix) process.stdout.write(`- recommended fix: ${report.doctor.recommendedFix}\n`);
1651
1723
  process.stdout.write(`- live health: ${report.doctor.healthCommand}\n`);
1652
1724
  }
@@ -1708,6 +1780,7 @@ async function install(options) {
1708
1780
  : [];
1709
1781
  const envHints = options.apiKey ? [] : findLikelyEnvFiles(detection);
1710
1782
  const mcpProcesses = inspectMcpProcesses({ commands: options.processCommands });
1783
+ const mcpConfigurations = inspectMcpConfigurations(detection, { paths: options.mcpConfigPaths });
1711
1784
  let selfTest;
1712
1785
  try {
1713
1786
  selfTest = await runSelfTest(options);
@@ -1775,6 +1848,7 @@ async function install(options) {
1775
1848
 
1776
1849
  return {
1777
1850
  root: detection.root,
1851
+ adapterProvenance: ADAPTER_PROVENANCE,
1778
1852
  mode: plan.mode,
1779
1853
  writeMode,
1780
1854
  detected: {
@@ -1800,12 +1874,13 @@ async function install(options) {
1800
1874
  envHints,
1801
1875
  missingHooks: changes.filter((change) => change.changed).map((change) => change.label),
1802
1876
  mcpProcesses,
1803
- recommendedFix: mcpProcesses.exact_fix || configDiagnostics.npm_token.recommended_fix || (!options.apiKey
1877
+ mcpConfigurations,
1878
+ recommendedFix: mcpProcesses.exact_fix || mcpConfigurations.exact_fix || configDiagnostics.npm_token.recommended_fix || (!options.apiKey
1804
1879
  ? envHints.length
1805
1880
  ? `MARROW_API_KEY was found in a likely env file at ${envHints[0]}. Load that key from trusted secret storage, export only MARROW_API_KEY, then run npx @getmarrow/install --repair.`
1806
1881
  : 'Set MARROW_API_KEY, then run npx @getmarrow/install --repair.'
1807
1882
  : controller.exact_fix || selfTest.recommended_fix || null),
1808
- healthCommand: 'npx -y @getmarrow/mcp@latest ping',
1883
+ healthCommand: 'npx -y --package=@getmarrow/mcp@latest marrow-mcp ping',
1809
1884
  },
1810
1885
  remediation,
1811
1886
  configDiagnostics,
@@ -1820,6 +1895,9 @@ async function install(options) {
1820
1895
  ...(!mcpProcesses.healthy
1821
1896
  ? ['Stale, mixed, or version-unknown Marrow MCP clients are active. Run the exact repair command, then restart every owning harness.']
1822
1897
  : []),
1898
+ ...(!mcpConfigurations.healthy
1899
+ ? ['Stale, mixed, or version-unknown Marrow MCP versions remain in owner configuration. Repair each owning workspace and restart its harness.']
1900
+ : []),
1823
1901
  ],
1824
1902
  };
1825
1903
  }
@@ -1850,11 +1928,13 @@ module.exports = {
1850
1928
  inspectNpmTokenConfig,
1851
1929
  inspectSdkDependency,
1852
1930
  inspectMcpProcesses,
1931
+ inspectMcpConfigurations,
1853
1932
  buildInstallValueMoment,
1854
1933
  buildTokenValueProof,
1855
1934
  stableAgentId,
1856
1935
  activationProfile,
1857
1936
  claudeNativeHookFingerprint,
1858
1937
  printReport,
1938
+ ADAPTER_PROVENANCE,
1859
1939
  HARNESS_CAPABILITY_REGISTRY,
1860
1940
  };