@getmarrow/install 0.1.34 → 0.1.35

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
@@ -62,9 +62,31 @@ Required secret:
62
62
  export MARROW_API_KEY=mrw_live_...
63
63
  ```
64
64
 
65
- ## What's New in v0.1.34
65
+ ## Keeping Marrow Current
66
66
 
67
- v0.1.34 verifies whether passive governance is actually active after install. Activation now registers a bounded capability profile, a one-way configuration fingerprint, expected and observed hook surfaces, and a server-accepted lifecycle receipt. The Fleet Operator shows activation state, capture coverage, outcome closure, intervention follow-through, drift, and the exact repair:
67
+ Marrow's hosted API, website, and dashboard update automatically; local SDK dependencies, generated runtime files, MCP hooks/configuration, and pinned package versions do not silently rewrite themselves. Keeping them current delivers new client-side features, compatibility improvements, and any published security fixes. Supported clients report their package version during authenticated status/runtime activity, and Marrow returns a `client_update` notice with the exact action when the version is behind or unknown.
68
+
69
+ ```bash
70
+ npx -y @getmarrow/install@latest activate
71
+ npx -y @getmarrow/install@latest doctor
72
+
73
+ # Use only when doctor reports drift
74
+ npx -y @getmarrow/install@latest --repair
75
+ ```
76
+
77
+ `activate` reconciles Marrow-managed entries while retaining unrelated user hooks and configuration. Detection and notification are automatic; local changes remain explicit and subject to the operator's normal change policy.
78
+
79
+ ## What's New in v0.1.35
80
+
81
+ v0.1.35 turns server-side client update detection into a guided, low-friction operator workflow. Installer status, activation reports, and the Fleet Operator expose a request-specific advisory with the exact update and verification commands while keeping local mutation explicit:
82
+
83
+ - official installer requests identify the installed `@getmarrow/install` version;
84
+ - status, self-test, and Fleet Operator output show recommended, unrecognized, and security-required update states without conflating them;
85
+ - generated agent instructions tell the agent to notify the operator and obey local change policy;
86
+ - certified activation now pins MCP 3.9.51 and SDK 3.7.50, including the exact SDK registry integrity;
87
+ - `activate`, `doctor`, and `--repair` remain explicit commands and preserve unrelated hooks and configuration.
88
+
89
+ It preserves the passive-governance verification introduced in v0.1.34. Activation registers a bounded capability profile, a one-way configuration fingerprint, expected and observed hook surfaces, and a server-accepted lifecycle receipt. The Fleet Operator shows activation state, capture coverage, outcome closure, intervention follow-through, drift, and the exact repair:
68
90
 
69
91
  - Claude Code installation includes exact `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, and `Stop` hooks;
70
92
  - matching pre-action/result receipts use one tool correlation, and activation fingerprints the exact hook contract without uploading configuration contents;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmarrow/install",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "Universal installer and governed runner for Marrow agent fleets.",
5
5
  "bin": {
6
6
  "marrow-install": "bin/marrow-install.js"
@@ -4,6 +4,7 @@ const fs = require('node:fs');
4
4
  const os = require('node:os');
5
5
  const path = require('node:path');
6
6
  const readline = require('node:readline');
7
+ const { version: INSTALLER_PACKAGE_VERSION } = require('../package.json');
7
8
 
8
9
  const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
9
10
  const HIGH_RISK_TERMS = /\b(deploy|prod|production|publish|release|merge|migration|migrate|secret|token|key|cloudflare|wrangler|npm publish|gh pr merge|git push|terraform apply|kubectl apply|delete|destroy|drop)\b/i;
@@ -343,6 +344,8 @@ function headers(options) {
343
344
  'X-Marrow-Agent-Id': options.agentId,
344
345
  'X-Marrow-Session-Id': options.sessionId,
345
346
  'X-Marrow-Client': sourceClient(options.client),
347
+ 'X-Marrow-Package': '@getmarrow/install',
348
+ 'X-Marrow-Package-Version': INSTALLER_PACKAGE_VERSION,
346
349
  'User-Agent': '@getmarrow/install governed-runner',
347
350
  };
348
351
  return h;
@@ -657,6 +660,31 @@ async function statusOnly(parsed) {
657
660
  return requestJson(parsed.options, 'GET', '/v1/agent/status');
658
661
  }
659
662
 
663
+ function statusPanel(status = {}) {
664
+ const update = status.client_update && typeof status.client_update === 'object'
665
+ ? status.client_update
666
+ : null;
667
+ const lines = [
668
+ 'Marrow runtime status',
669
+ `Health: ${displayText(firstDefined(status.health, status.status, status.ok === false ? 'degraded' : 'unknown'), 40)}`,
670
+ ];
671
+ const notification = update?.notification_state || update?.notification;
672
+ const priority = notification === 'security_required' || notification === 'recommended'
673
+ ? notification
674
+ : update?.version_status === 'unknown' || notification === 'unknown' || notification === 'version_unknown'
675
+ ? 'version_unknown'
676
+ : update?.priority || 'recommended';
677
+ if (update && (update.update_available === true || update.version_status === 'unknown' || notification === 'unknown' || notification === 'version_unknown' || priority === 'security_required')) {
678
+ lines.push(`Client update: ${displayText(priority, 32)}; installed=${displayText(update.installed_version || update.current_version || 'unknown', 32)}; latest=${displayText(update.latest_version || 'unknown', 32)}`);
679
+ lines.push('Automatic notification: yes; automatic local mutation: no; operator policy applies.');
680
+ if (update.update_command || update.exact_update_command) lines.push(`Update: ${displayText(update.update_command || update.exact_update_command, 240)}`);
681
+ if (update.verification_command || update.exact_verification_command) lines.push(`Verify: ${displayText(update.verification_command || update.exact_verification_command, 240)}`);
682
+ } else {
683
+ lines.push('Client update: current or unavailable.');
684
+ }
685
+ return lines.join('\n');
686
+ }
687
+
660
688
  async function optionalRequestJson(options, method, route, body) {
661
689
  try {
662
690
  return { ok: true, data: await requestJson(options, method, route, body) };
@@ -809,6 +837,9 @@ function normalizeFixCommands(status, capacity) {
809
837
  add(status.activation_coverage?.exact_fix);
810
838
  add(status.activation_coverage?.drift?.repair_command, true);
811
839
  add(status.passive_activation?.exact_fix);
840
+ if (status.client_update?.update_available === true || status.client_update?.version_status === 'unknown' || status.client_update?.notification_state === 'unknown' || status.client_update?.notification === 'version_unknown') {
841
+ add(status.client_update?.update_command || status.client_update?.exact_update_command, true);
842
+ }
812
843
  add(capacity.exact_next_action, true);
813
844
  add(capacity.next_action, true);
814
845
  if (listValue(status.missed_hooks, status.degraded_hooks).length) add('npx @getmarrow/install --repair');
@@ -944,6 +975,7 @@ function normalizeFleetSnapshot(raw, options) {
944
975
  gates,
945
976
  arbitrations,
946
977
  activation_coverage: activationCoverage,
978
+ client_update: status.client_update || null,
947
979
  agents,
948
980
  fix_commands: fixCommands.length ? fixCommands : ['npx @getmarrow/install doctor'],
949
981
  source_errors: errors,
@@ -1003,6 +1035,9 @@ function fleetPanel(snapshot) {
1003
1035
  `Failed/stale outcomes: ${snapshot.failed_stale_outcomes}`,
1004
1036
  `Backpressure/capacity status: ${snapshot.backpressure_status}${snapshot.capacity_next_action ? ` - ${snapshot.capacity_next_action}` : ''}`,
1005
1037
  `Degraded hooks: ${degraded}`,
1038
+ snapshot.client_update && (snapshot.client_update.update_available === true || snapshot.client_update.version_status === 'unknown' || snapshot.client_update.notification_state === 'unknown' || snapshot.client_update.notification === 'version_unknown')
1039
+ ? `Marrow client update: ${displayText(snapshot.client_update.notification_state === 'security_required' ? 'security_required' : snapshot.client_update.notification_state === 'recommended' ? 'recommended' : snapshot.client_update.version_status === 'unknown' || snapshot.client_update.notification_state === 'unknown' || snapshot.client_update.notification === 'version_unknown' ? 'version_unknown' : snapshot.client_update.priority || 'recommended', 32)}; installed=${displayText(snapshot.client_update.installed_version || snapshot.client_update.current_version || 'unknown', 32)}; latest=${displayText(snapshot.client_update.latest_version || 'unknown', 32)}; operator approval required`
1040
+ : 'Marrow client update: current or unavailable',
1006
1041
  `Deploy/publish/merge gates: deploy=${snapshot.gates.deploy} publish=${snapshot.gates.publish} merge=${snapshot.gates.merge}`,
1007
1042
  '',
1008
1043
  'Live agent roster:',
@@ -1839,6 +1874,7 @@ async function runCli(argv) {
1839
1874
 
1840
1875
  if (parsed.options?.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
1841
1876
  else if (result?.blocked) process.stderr.write(`BLOCKED: ${result.message || 'Marrow blocked this action.'}\n`);
1877
+ else if (parsed.command === 'status') process.stdout.write(`${statusPanel(result)}\n`);
1842
1878
  else if (!['run', 'fleet', 'hermes', 'openclaw', 'integrations'].includes(parsed.command)) process.stdout.write('Marrow command completed.\n');
1843
1879
 
1844
1880
  if (parsed.command === 'run' || result?.blocked) process.exitCode = result?.exitCode ?? (result?.ok === false ? 1 : 0);
@@ -1868,6 +1904,7 @@ module.exports = {
1868
1904
  gateOnly,
1869
1905
  proofOnly,
1870
1906
  statusOnly,
1907
+ statusPanel,
1871
1908
  runStatusCheck,
1872
1909
  runGateCheck,
1873
1910
  runGovernInteractive,
package/src/installer.js CHANGED
@@ -2,14 +2,14 @@ const fs = require('node:fs');
2
2
  const path = require('node:path');
3
3
  const os = require('node:os');
4
4
  const crypto = require('node:crypto');
5
+ const { version: INSTALLER_ADAPTER_VERSION } = require('../package.json');
5
6
 
6
7
  const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
7
8
  const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
8
9
  const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
9
- const INSTALLER_ADAPTER_VERSION = '0.1.34';
10
- const MCP_ADAPTER_VERSION = '3.9.50';
11
- const SDK_ADAPTER_VERSION = '3.7.49';
12
- const SDK_ADAPTER_INTEGRITY = 'sha512-9a6pWWACubWTmulG7TwwgMNP/iSzoEh4wCH2oWUyO8XHeD2Eokj1GXrkCyX86md3bV7vGX6kyllfswZDlGj6WA==';
10
+ const MCP_ADAPTER_VERSION = '3.9.51';
11
+ const SDK_ADAPTER_VERSION = '3.7.50';
12
+ const SDK_ADAPTER_INTEGRITY = 'sha512-TyCXUKZAaKRPdfVqXEuIvWnOt4GLcIUbwhpX+EopzdALNzq+t5wUGHrqJlkNSvopppPTTdFVLJ7O1vtwofqFqw==';
13
13
  const SDK_ADAPTER_TARBALL = `https://registry.npmjs.org/@getmarrow/sdk/-/sdk-${SDK_ADAPTER_VERSION}.tgz`;
14
14
  const MCP_PACKAGE_SPEC = `@getmarrow/mcp@${MCP_ADAPTER_VERSION}`;
15
15
  const MCP_CONTEXT_HOOK_COMMAND = `npx -y ${MCP_PACKAGE_SPEC} context-hook`;
@@ -380,6 +380,7 @@ Marrow should run passively after install:
380
380
  - Before risky work, use Marrow's decision brief or passive prompt hook.
381
381
  - After meaningful work, record the outcome so future agents learn from it.
382
382
  - Check health with \`marrow_agent_status\` or \`GET /v1/agent/status\`.
383
+ - When status/runtime returns a \`client_update\` notice, tell the operator and use its exact update and verification commands only when local change policy permits.
383
384
 
384
385
  Required environment:
385
386
 
@@ -954,6 +955,8 @@ async function runSelfTest(options) {
954
955
  'content-type': 'application/json',
955
956
  'x-marrow-session-id': `install-${Date.now()}`,
956
957
  'x-marrow-client': options.client || sourceClient(),
958
+ 'x-marrow-package': '@getmarrow/install',
959
+ 'x-marrow-package-version': INSTALLER_ADAPTER_VERSION,
957
960
  };
958
961
  if (options.agentId) headers['x-marrow-agent-id'] = options.agentId;
959
962
 
@@ -1141,6 +1144,7 @@ async function runSelfTest(options) {
1141
1144
  first_value_signal: firstValueSignal,
1142
1145
  install_value_moment: installValueMoment,
1143
1146
  token_value_proof: tokenValueProof,
1147
+ client_update: status.client_update || runtime.client_update || runtime.status?.client_update || null,
1144
1148
  performance_proof: performance && performance.ok !== false ? {
1145
1149
  avoided_mistakes: performance.avoided_mistakes ?? performance.avoided_repeated_mistakes ?? 0,
1146
1150
  reused_winning_decisions: performance.reused_winning_decisions ?? 0,
@@ -1299,6 +1303,18 @@ function printReport(report) {
1299
1303
  process.stdout.write(`- one-call runtime: ${report.selfTest.runtime_active ? 'active' : 'not verified'}\n`);
1300
1304
  if (report.selfTest.error) process.stdout.write(`- error: ${report.selfTest.error}\n`);
1301
1305
  if (report.selfTest.next_action) process.stdout.write(`- next action: ${report.selfTest.next_action}\n`);
1306
+ const update = report.selfTest.client_update;
1307
+ const notification = update?.notification_state || update?.notification;
1308
+ if (update && (update.update_available === true || update.version_status === 'unknown' || notification === 'unknown' || notification === 'version_unknown' || notification === 'security_required')) {
1309
+ process.stdout.write('\nMarrow client update:\n');
1310
+ process.stdout.write(`- priority: ${notification === 'security_required' ? 'security_required' : notification === 'recommended' ? 'recommended' : update.version_status === 'unknown' || notification === 'unknown' || notification === 'version_unknown' ? 'version_unknown' : update.priority || 'recommended'}\n`);
1311
+ process.stdout.write(`- installed: ${update.installed_version || update.current_version || 'unknown'}\n`);
1312
+ process.stdout.write(`- latest: ${update.latest_version || 'unknown'}\n`);
1313
+ process.stdout.write('- automatic notification: yes\n');
1314
+ process.stdout.write('- automatic local mutation: no; operator policy applies\n');
1315
+ if (update.update_command || update.exact_update_command) process.stdout.write(`- update: ${update.update_command || update.exact_update_command}\n`);
1316
+ if (update.verification_command || update.exact_verification_command) process.stdout.write(`- verify: ${update.verification_command || update.exact_verification_command}\n`);
1317
+ }
1302
1318
  if (report.selfTest.first_value_signal) {
1303
1319
  process.stdout.write('\nFirst value:\n');
1304
1320
  const valueMoment = report.selfTest.install_value_moment;