@getmarrow/install 0.1.32 → 0.1.33
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 +3 -3
- package/package.json +1 -1
- package/src/governed-runner.js +60 -7
package/README.md
CHANGED
|
@@ -62,9 +62,9 @@ Required secret:
|
|
|
62
62
|
export MARROW_API_KEY=mrw_live_...
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
## What's New in v0.1.
|
|
65
|
+
## What's New in v0.1.33
|
|
66
66
|
|
|
67
|
-
v0.1.
|
|
67
|
+
v0.1.33 adds agent-disagreement visibility to the Fleet Operator TUI. Operators can see open and review-required arbitration receipts and inspect the exact next action produced through the existing Marrow runtime. It preserves the machine-readable governance-fit contract introduced in v0.1.32 and the server-verified first-run activation introduced in v0.1.29:
|
|
68
68
|
|
|
69
69
|
- GitHub and npm now advertise separate signed discovery placements;
|
|
70
70
|
- package metadata identifies the installer as agent governance rather than a general memory utility;
|
|
@@ -160,7 +160,7 @@ npx @getmarrow/install --repair
|
|
|
160
160
|
npx @getmarrow/install fleet
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
The fleet view shows live agents, active workflows, risky actions waiting for proof, stale or failed outcomes, capture health, recent decisions, and exact repair commands. It is an operator surface for the authenticated account, not a public status dashboard.
|
|
163
|
+
The fleet view shows live agents, active workflows, agent disagreements and their latest arbitration receipt, risky actions waiting for proof, stale or failed outcomes, capture health, recent decisions, and exact repair commands. Press Enter on **Agent disagreements** to inspect the bound decision, selected proposal, whether Marrow selected a proposal, synthesized a safe sequence, held the action for owner review, or blocked the conflicting actions. Review-required work must be approved from an authenticated Marrow dashboard session; the TUI does not let an agent approve itself. It is an operator surface for the authenticated account, not a public status dashboard.
|
|
164
164
|
|
|
165
165
|
## Integration Paths
|
|
166
166
|
|
package/package.json
CHANGED
package/src/governed-runner.js
CHANGED
|
@@ -8,7 +8,7 @@ const readline = require('node:readline');
|
|
|
8
8
|
const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
|
|
9
9
|
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;
|
|
10
10
|
const GOVERN_TUI_ROW_COUNT = 7;
|
|
11
|
-
const FLEET_TUI_ROW_COUNT =
|
|
11
|
+
const FLEET_TUI_ROW_COUNT = 12;
|
|
12
12
|
function usage() {
|
|
13
13
|
return `Usage:
|
|
14
14
|
npx @getmarrow/install run --agent deploy-agent -- npm test
|
|
@@ -761,6 +761,38 @@ function normalizeGates(status, report) {
|
|
|
761
761
|
};
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
+
function normalizeArbitrations(status, report, fleet) {
|
|
765
|
+
const source = firstDefined(
|
|
766
|
+
report.arbitrations,
|
|
767
|
+
report.report?.arbitrations,
|
|
768
|
+
fleet.arbitrations,
|
|
769
|
+
status.arbitrations,
|
|
770
|
+
{},
|
|
771
|
+
) || {};
|
|
772
|
+
const receipts = listValue(
|
|
773
|
+
source.receipts,
|
|
774
|
+
source.items,
|
|
775
|
+
report.recent_arbitrations,
|
|
776
|
+
fleet.recent_arbitrations,
|
|
777
|
+
status.recent_arbitrations,
|
|
778
|
+
).slice(0, 8).map((receipt) => ({
|
|
779
|
+
id: displayText(firstDefined(receipt?.id, receipt?.receipt_id, 'arbitration'), 80),
|
|
780
|
+
decision_id: displayText(firstDefined(receipt?.decision_id, ''), 80),
|
|
781
|
+
resolution: statusLabel(receipt?.resolution, 'unknown'),
|
|
782
|
+
conflict_type: displayText(firstDefined(receipt?.conflict_type, 'action_conflict'), 60),
|
|
783
|
+
selected_proposal_id: displayText(firstDefined(receipt?.selected_proposal_id, ''), 80),
|
|
784
|
+
requesting_agent_id: displayText(firstDefined(receipt?.requesting_agent_id, ''), 80),
|
|
785
|
+
exact_next_action: displayText(firstDefined(receipt?.exact_next_action, ''), 180),
|
|
786
|
+
owner_approval_required: Boolean(receipt?.owner_approval_required),
|
|
787
|
+
created_at: displayText(firstDefined(receipt?.created_at, ''), 80),
|
|
788
|
+
}));
|
|
789
|
+
return {
|
|
790
|
+
open_count: numberValue(firstDefined(source.open_count, source.open, receipts.filter((item) => item.resolution !== 'selected' && item.resolution !== 'synthesized').length), 0),
|
|
791
|
+
review_required_count: numberValue(firstDefined(source.review_required_count, source.review_required, receipts.filter((item) => item.resolution === 'review_required').length), 0),
|
|
792
|
+
receipts,
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
764
796
|
function normalizeFixCommands(status, capacity) {
|
|
765
797
|
const commands = [];
|
|
766
798
|
const add = (value, commandOnly = false) => {
|
|
@@ -840,6 +872,7 @@ function normalizeFleetSnapshot(raw, options) {
|
|
|
840
872
|
), raw.capacity?.ok ? 'ok' : 'unknown');
|
|
841
873
|
const recentDecisions = normalizeRecentDecisions(status, report, fleet);
|
|
842
874
|
const gates = normalizeGates(status, report);
|
|
875
|
+
const arbitrations = normalizeArbitrations(status, report, fleet);
|
|
843
876
|
const fixCommands = normalizeFixCommands(status, capacity);
|
|
844
877
|
const errors = Object.entries(raw)
|
|
845
878
|
.filter(([, value]) => value && value.ok === false)
|
|
@@ -859,6 +892,7 @@ function normalizeFleetSnapshot(raw, options) {
|
|
|
859
892
|
recent_decisions: recentDecisions,
|
|
860
893
|
degraded_hooks: missedHooks,
|
|
861
894
|
gates,
|
|
895
|
+
arbitrations,
|
|
862
896
|
agents,
|
|
863
897
|
fix_commands: fixCommands.length ? fixCommands : ['npx @getmarrow/install doctor'],
|
|
864
898
|
source_errors: errors,
|
|
@@ -898,6 +932,10 @@ function fleetPanel(snapshot) {
|
|
|
898
932
|
? snapshot.agents.slice(0, 5).map((agent) => ` - ${agent.id}${agent.role ? ` (${agent.role})` : ''}: ${agent.status}${agent.last_seen_at ? ` last_seen=${agent.last_seen_at}` : ''}`).join('\n')
|
|
899
933
|
: ' - no agent roster returned yet';
|
|
900
934
|
const fixes = snapshot.fix_commands.map((command) => ` - ${command}`).join('\n');
|
|
935
|
+
const arbitration = snapshot.arbitrations.receipts[0];
|
|
936
|
+
const arbitrationSummary = arbitration
|
|
937
|
+
? `${arbitration.resolution} (${arbitration.conflict_type})${arbitration.exact_next_action ? ` - ${arbitration.exact_next_action}` : ''}`
|
|
938
|
+
: 'none reported yet';
|
|
901
939
|
return [
|
|
902
940
|
'Marrow Fleet Operator',
|
|
903
941
|
'',
|
|
@@ -906,6 +944,8 @@ function fleetPanel(snapshot) {
|
|
|
906
944
|
'',
|
|
907
945
|
`Live agents: ${snapshot.live_agents ?? 'unknown'}`,
|
|
908
946
|
`Active workflows: ${snapshot.active_workflows ?? 'unknown'}`,
|
|
947
|
+
`Agent disagreements: open=${snapshot.arbitrations.open_count} review_required=${snapshot.arbitrations.review_required_count}`,
|
|
948
|
+
`Latest arbitration: ${arbitrationSummary}`,
|
|
909
949
|
`Risky actions waiting for proof: ${snapshot.proof_waiting}`,
|
|
910
950
|
`Failed/stale outcomes: ${snapshot.failed_stale_outcomes}`,
|
|
911
951
|
`Backpressure/capacity status: ${snapshot.backpressure_status}${snapshot.capacity_next_action ? ` - ${snapshot.capacity_next_action}` : ''}`,
|
|
@@ -1324,6 +1364,7 @@ function renderFleetTui(state) {
|
|
|
1324
1364
|
const gateSummary = `deploy=${snapshot.gates.deploy} publish=${snapshot.gates.publish} merge=${snapshot.gates.merge}`;
|
|
1325
1365
|
const fixCommand = snapshot.fix_commands[0] || 'npx @getmarrow/install doctor';
|
|
1326
1366
|
const recent = snapshot.recent_decisions[0] || 'none reported yet';
|
|
1367
|
+
const arbitration = snapshot.arbitrations.receipts[0];
|
|
1327
1368
|
const rows = [
|
|
1328
1369
|
{
|
|
1329
1370
|
label: 'Live agents',
|
|
@@ -1335,6 +1376,13 @@ function renderFleetTui(state) {
|
|
|
1335
1376
|
value: String(snapshot.active_workflows ?? 'unknown'),
|
|
1336
1377
|
hint: 'Current account-scoped workflow pressure from Marrow.',
|
|
1337
1378
|
},
|
|
1379
|
+
{
|
|
1380
|
+
label: 'Agent disagreements',
|
|
1381
|
+
value: `open=${snapshot.arbitrations.open_count} review_required=${snapshot.arbitrations.review_required_count}`,
|
|
1382
|
+
hint: arbitration
|
|
1383
|
+
? `${arbitration.resolution}: ${arbitration.exact_next_action || arbitration.conflict_type}`
|
|
1384
|
+
: 'No conflicting fleet proposals reported.',
|
|
1385
|
+
},
|
|
1338
1386
|
{
|
|
1339
1387
|
label: 'Risky actions waiting for proof',
|
|
1340
1388
|
value: String(snapshot.proof_waiting),
|
|
@@ -1651,31 +1699,36 @@ async function runFleetInteractive(options, input = process.stdin, output = proc
|
|
|
1651
1699
|
state.status = 'Agent selection changed.';
|
|
1652
1700
|
render();
|
|
1653
1701
|
} else if (key.name === 'return') {
|
|
1654
|
-
if (state.cursor ===
|
|
1702
|
+
if (state.cursor === 10) {
|
|
1655
1703
|
cleanup();
|
|
1656
1704
|
output.write(`\n${state.snapshot.fix_commands[0] || 'npx @getmarrow/install doctor'}\n`);
|
|
1657
1705
|
resolve();
|
|
1658
1706
|
return;
|
|
1659
1707
|
}
|
|
1660
|
-
if (state.cursor ===
|
|
1708
|
+
if (state.cursor === 11) {
|
|
1661
1709
|
cleanup();
|
|
1662
1710
|
resolve();
|
|
1663
1711
|
return;
|
|
1664
1712
|
}
|
|
1665
1713
|
const selectedAgent = state.snapshot.agents[state.agentIndex];
|
|
1666
|
-
if (state.cursor === 0 || state.cursor ===
|
|
1714
|
+
if (state.cursor === 0 || state.cursor === 9) {
|
|
1667
1715
|
state.lastResult = selectedAgent
|
|
1668
1716
|
? `Agent ${selectedAgent.id}: status=${selectedAgent.status}${selectedAgent.role ? ` role=${selectedAgent.role}` : ''}${selectedAgent.last_seen_at ? ` last_seen=${selectedAgent.last_seen_at}` : ''}`
|
|
1669
1717
|
: 'No live agent roster returned yet. Check API key scope or wait for agents to log activity.';
|
|
1670
|
-
} else if (state.cursor ===
|
|
1718
|
+
} else if (state.cursor === 2) {
|
|
1719
|
+
const receipts = state.snapshot.arbitrations.receipts;
|
|
1720
|
+
state.lastResult = receipts.length
|
|
1721
|
+
? receipts.map((receipt, index) => `${index + 1}. ${receipt.id}: ${receipt.resolution}${receipt.decision_id ? `; decision=${receipt.decision_id}` : ''}${receipt.selected_proposal_id ? `; selected=${receipt.selected_proposal_id}` : ''}; ${receipt.exact_next_action || receipt.conflict_type}${receipt.owner_approval_required ? ' Owner approval must be issued from an authenticated Marrow dashboard session.' : ''}`).join(' ')
|
|
1722
|
+
: 'No agent disagreements or arbitration receipts returned yet.';
|
|
1723
|
+
} else if (state.cursor === 6) {
|
|
1671
1724
|
state.lastResult = state.snapshot.recent_decisions.length
|
|
1672
1725
|
? state.snapshot.recent_decisions.map((decision, index) => `${index + 1}. ${decision}`).join(' ')
|
|
1673
1726
|
: 'No recent decisions returned yet.';
|
|
1674
|
-
} else if (state.cursor ===
|
|
1727
|
+
} else if (state.cursor === 7) {
|
|
1675
1728
|
state.lastResult = state.snapshot.degraded_hooks.length
|
|
1676
1729
|
? `Degraded hooks: ${state.snapshot.degraded_hooks.join(', ')}. Fix: ${state.snapshot.fix_commands[0]}`
|
|
1677
1730
|
: 'No degraded hooks reported.';
|
|
1678
|
-
} else if (state.cursor ===
|
|
1731
|
+
} else if (state.cursor === 8) {
|
|
1679
1732
|
state.lastResult = `Release gates: deploy=${state.snapshot.gates.deploy}, publish=${state.snapshot.gates.publish}, merge=${state.snapshot.gates.merge}.`;
|
|
1680
1733
|
} else {
|
|
1681
1734
|
state.lastResult = fleetPanel(state.snapshot).replace(/\n/g, ' ');
|