instar 0.28.51 → 0.28.53
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/dashboard/index.html +320 -11
- package/dist/cli.js +51 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/backup.js +3 -3
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/gate.d.ts +33 -0
- package/dist/commands/gate.d.ts.map +1 -0
- package/dist/commands/gate.js +171 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +100 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +10 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +71 -0
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +71 -18
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +12 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/BackupManager.d.ts.map +1 -1
- package/dist/core/BackupManager.js +34 -1
- package/dist/core/BackupManager.js.map +1 -1
- package/dist/core/CommitmentSweeper.d.ts +101 -0
- package/dist/core/CommitmentSweeper.d.ts.map +1 -0
- package/dist/core/CommitmentSweeper.js +222 -0
- package/dist/core/CommitmentSweeper.js.map +1 -0
- package/dist/core/LedgerSessionRegistry.d.ts +225 -0
- package/dist/core/LedgerSessionRegistry.d.ts.map +1 -0
- package/dist/core/LedgerSessionRegistry.js +667 -0
- package/dist/core/LedgerSessionRegistry.js.map +1 -0
- package/dist/core/MessageSentinel.d.ts +40 -0
- package/dist/core/MessageSentinel.d.ts.map +1 -1
- package/dist/core/MessageSentinel.js +80 -0
- package/dist/core/MessageSentinel.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +81 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +436 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +29 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +104 -1
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SharedStateLedger.d.ts.map +1 -1
- package/dist/core/SharedStateLedger.js +11 -0
- package/dist/core/SharedStateLedger.js.map +1 -1
- package/dist/core/StopGateDb.d.ts +97 -0
- package/dist/core/StopGateDb.d.ts.map +1 -0
- package/dist/core/StopGateDb.js +282 -0
- package/dist/core/StopGateDb.js.map +1 -0
- package/dist/core/UnjustifiedStopGate.d.ts +145 -0
- package/dist/core/UnjustifiedStopGate.d.ts.map +1 -0
- package/dist/core/UnjustifiedStopGate.js +325 -0
- package/dist/core/UnjustifiedStopGate.js.map +1 -0
- package/dist/core/WorktreeKeyVault.d.ts +50 -0
- package/dist/core/WorktreeKeyVault.d.ts.map +1 -0
- package/dist/core/WorktreeKeyVault.js +242 -0
- package/dist/core/WorktreeKeyVault.js.map +1 -0
- package/dist/core/WorktreeManager.d.ts +250 -0
- package/dist/core/WorktreeManager.d.ts.map +1 -0
- package/dist/core/WorktreeManager.js +833 -0
- package/dist/core/WorktreeManager.js.map +1 -0
- package/dist/core/types.d.ts +153 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/data/pr-gate-artifacts.d.ts +38 -0
- package/dist/data/pr-gate-artifacts.d.ts.map +1 -0
- package/dist/data/pr-gate-artifacts.js +383 -0
- package/dist/data/pr-gate-artifacts.js.map +1 -0
- package/dist/messaging/shared/compactionResumePayload.d.ts +60 -0
- package/dist/messaging/shared/compactionResumePayload.d.ts.map +1 -0
- package/dist/messaging/shared/compactionResumePayload.js +88 -0
- package/dist/messaging/shared/compactionResumePayload.js.map +1 -0
- package/dist/monitoring/DegradationReporter.d.ts +15 -0
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +27 -0
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/WorktreeReaper.d.ts +52 -0
- package/dist/monitoring/WorktreeReaper.d.ts.map +1 -0
- package/dist/monitoring/WorktreeReaper.js +199 -0
- package/dist/monitoring/WorktreeReaper.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +8 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +20 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +25 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +20 -3
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes.d.ts +12 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +1277 -3
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +77 -0
- package/dist/server/stopGate.d.ts.map +1 -0
- package/dist/server/stopGate.js +161 -0
- package/dist/server/stopGate.js.map +1 -0
- package/dist/server/worktreeRoutes.d.ts +48 -0
- package/dist/server/worktreeRoutes.d.ts.map +1 -0
- package/dist/server/worktreeRoutes.js +247 -0
- package/dist/server/worktreeRoutes.js.map +1 -0
- package/package.json +1 -1
- package/scripts/destructive-command-shim.js +218 -0
- package/scripts/gh-ruleset-install.mjs +143 -0
- package/scripts/migrate-incident-2026-04-17.mjs +138 -0
- package/scripts/worktree-commit-msg-hook.js +168 -0
- package/scripts/worktree-precommit-gate.js +144 -0
- package/src/data/builtin-manifest.json +94 -94
- package/src/data/pr-gate-artifacts.ts +394 -0
- package/upgrades/0.28.51.md +10 -1
- package/upgrades/0.28.52.md +13 -61
- package/upgrades/0.28.53.md +70 -0
- package/upgrades/side-effects/NEXT.md +61 -0
- package/upgrades/side-effects/context-death-pr0a-server-infra.md +131 -0
- package/upgrades/side-effects/context-death-pr0b-sentinel-intent.md +130 -0
- package/upgrades/side-effects/context-death-pr0c-guardian-pulse-degradation-consumer.md +118 -0
- package/upgrades/side-effects/context-death-pr0d-e2e-compaction-harness.md +113 -0
- package/upgrades/side-effects/context-death-pr1-identity-text.md +110 -0
- package/upgrades/side-effects/context-death-pr2-e2e-compaction-recovery-test.md +82 -0
- package/upgrades/side-effects/context-death-pr3-gate-authority.md +193 -0
- package/upgrades/side-effects/context-death-pr4-gate-cli.md +91 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-1-foundation.md +192 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-2-session-bind.md +218 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-3-commitment-kind.md +105 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-4-resolve.md +98 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-5-sweepers.md +80 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-6-dashboard-rendering.md +67 -0
- package/upgrades/side-effects/integrated-being-ledger-v2-slice-7-bindings-revoke.md +111 -0
- package/upgrades/side-effects/parallel-dev-isolation.md +129 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-1-blocked-path-prefixes.md +135 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-2-backupconfig-plumbing.md +157 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-3-gitignore-pr-gate.md +130 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-4-pipeline-artifacts.md +157 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-5-backup-manifest.md +129 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-6-rollback-skill.md +116 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-7-dashboard-tab.md +124 -0
- package/upgrades/side-effects/pr-gate-phase-a-commit-8-phase-off-kill-switch.md +151 -0
- package/upgrades/side-effects/pr-gate-phase-a-spec-and-reports-docs-only.md +34 -0
package/dashboard/index.html
CHANGED
|
@@ -2414,6 +2414,7 @@
|
|
|
2414
2414
|
<button class="tab" data-tab="features" onclick="switchTab('features')">Features</button>
|
|
2415
2415
|
<button class="tab" data-tab="systems" onclick="switchTab('systems')">Health</button>
|
|
2416
2416
|
<button class="tab" data-tab="integrated-being" onclick="switchTab('integrated-being')">Integrated-Being</button>
|
|
2417
|
+
<button class="tab" data-tab="pr-pipeline" onclick="switchTab('pr-pipeline')">PR Pipeline</button>
|
|
2417
2418
|
</nav>
|
|
2418
2419
|
</div>
|
|
2419
2420
|
<div class="vital-signs" id="vitalSigns">
|
|
@@ -2731,6 +2732,51 @@
|
|
|
2731
2732
|
</div>
|
|
2732
2733
|
<pre id="ibChainResult" style="margin-top:10px;max-height:200px;overflow:auto;font-size:11px"></pre>
|
|
2733
2734
|
</div>
|
|
2735
|
+
|
|
2736
|
+
<!-- Bindings subtab (slice 7) -->
|
|
2737
|
+
<div id="ibBindingsSection" style="background:var(--panel);border-radius:8px;border:1px solid var(--border);padding:12px;display:none">
|
|
2738
|
+
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
|
|
2739
|
+
<div style="font-size:13px;font-weight:600">Session bindings (v2)</div>
|
|
2740
|
+
<button onclick="loadIntegratedBeingBindings()" style="padding:4px 10px;font-size:11px">Refresh</button>
|
|
2741
|
+
</div>
|
|
2742
|
+
<div id="ibBindingsNotice" style="font-size:11px;color:var(--text-dim);margin-bottom:8px">
|
|
2743
|
+
Each registered session has a binding token. Revoke to invalidate it — subsequent writes from that session fail 401. Revocation is logged as a subsystem-asserted note.
|
|
2744
|
+
</div>
|
|
2745
|
+
<table style="width:100%;border-collapse:collapse;font-size:11px">
|
|
2746
|
+
<thead>
|
|
2747
|
+
<tr style="background:var(--bg-alt)">
|
|
2748
|
+
<th style="text-align:left;padding:6px">Session ID</th>
|
|
2749
|
+
<th style="text-align:left;padding:6px">Label</th>
|
|
2750
|
+
<th style="text-align:left;padding:6px">Registered</th>
|
|
2751
|
+
<th style="text-align:left;padding:6px">Last active</th>
|
|
2752
|
+
<th style="text-align:left;padding:6px">Absolute TTL</th>
|
|
2753
|
+
<th style="text-align:left;padding:6px">Status</th>
|
|
2754
|
+
<th style="text-align:left;padding:6px">Action</th>
|
|
2755
|
+
</tr>
|
|
2756
|
+
</thead>
|
|
2757
|
+
<tbody id="ibBindingsTbody">
|
|
2758
|
+
<tr><td colspan="7" style="padding:14px;color:var(--text-dim);text-align:center">Loading…</td></tr>
|
|
2759
|
+
</tbody>
|
|
2760
|
+
</table>
|
|
2761
|
+
</div>
|
|
2762
|
+
</div>
|
|
2763
|
+
|
|
2764
|
+
<!-- PR Pipeline Tab (PR-REVIEW-HARDENING-SPEC Phase A) -->
|
|
2765
|
+
<!-- Read-only: NO action buttons that mutate eligibility. All PR-authored -->
|
|
2766
|
+
<!-- content rendered via textContent, never innerHTML — XSS defense rule -->
|
|
2767
|
+
<!-- for the dashboard per spec §"Dashboard surface rules". -->
|
|
2768
|
+
<div id="prPipelinePanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
2769
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
2770
|
+
<h2 style="margin:0">PR Pipeline</h2>
|
|
2771
|
+
<div>
|
|
2772
|
+
<button onclick="loadPrPipeline()" style="padding:6px 12px">Refresh</button>
|
|
2773
|
+
</div>
|
|
2774
|
+
</div>
|
|
2775
|
+
<div id="prPipelinePhaseNotice" style="font-size:12px;color:var(--text-dim)"></div>
|
|
2776
|
+
<div id="prPipelineEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
2777
|
+
No PR activity to display.
|
|
2778
|
+
</div>
|
|
2779
|
+
<div id="prPipelineList" style="display:flex;flex-direction:column;gap:12px"></div>
|
|
2734
2780
|
</div>
|
|
2735
2781
|
|
|
2736
2782
|
<!-- Health Tab (was Systems) -->
|
|
@@ -3754,9 +3800,15 @@
|
|
|
3754
3800
|
id: 'integrated-being',
|
|
3755
3801
|
panels: ['integratedBeingPanel'],
|
|
3756
3802
|
display: ['flex'],
|
|
3757
|
-
onActivate: () => { if (typeof loadIntegratedBeing === 'function') loadIntegratedBeing(); if (typeof startIntegratedBeingPoll === 'function') startIntegratedBeingPoll(); },
|
|
3803
|
+
onActivate: () => { if (typeof loadIntegratedBeing === 'function') loadIntegratedBeing(); if (typeof loadIntegratedBeingBindings === 'function') loadIntegratedBeingBindings(); if (typeof startIntegratedBeingPoll === 'function') startIntegratedBeingPoll(); },
|
|
3758
3804
|
onDeactivate: () => { if (typeof stopIntegratedBeingPoll === 'function') stopIntegratedBeingPoll(); },
|
|
3759
3805
|
},
|
|
3806
|
+
{
|
|
3807
|
+
id: 'pr-pipeline',
|
|
3808
|
+
panels: ['prPipelinePanel'],
|
|
3809
|
+
display: ['flex'],
|
|
3810
|
+
onActivate: () => { if (typeof loadPrPipeline === 'function') loadPrPipeline(); },
|
|
3811
|
+
},
|
|
3760
3812
|
];
|
|
3761
3813
|
|
|
3762
3814
|
function switchTab(tabName) {
|
|
@@ -5545,6 +5597,108 @@
|
|
|
5545
5597
|
}
|
|
5546
5598
|
}
|
|
5547
5599
|
|
|
5600
|
+
// ── PR Pipeline Tab (PR-REVIEW-HARDENING-SPEC Phase A) ───────
|
|
5601
|
+
//
|
|
5602
|
+
// Fetches /pr-gate/metrics on panel activation and renders the
|
|
5603
|
+
// current pipeline state. Hard rules (enforced structurally here):
|
|
5604
|
+
// - NO action buttons that mutate eligibility (read-only tab).
|
|
5605
|
+
// - NO innerHTML — all PR content goes through textContent.
|
|
5606
|
+
// - NO form submissions to /pr-gate/* endpoints.
|
|
5607
|
+
// - On 404 (prGate.phase='off' — commit 8), render a disabled
|
|
5608
|
+
// placeholder rather than erroring.
|
|
5609
|
+
async function loadPrPipeline() {
|
|
5610
|
+
const list = document.getElementById('prPipelineList');
|
|
5611
|
+
const notice = document.getElementById('prPipelinePhaseNotice');
|
|
5612
|
+
const empty = document.getElementById('prPipelineEmpty');
|
|
5613
|
+
// Reset view via DOM mutation, not innerHTML, to keep the
|
|
5614
|
+
// "never inject content as HTML" invariant trivially true.
|
|
5615
|
+
while (list.firstChild) list.removeChild(list.firstChild);
|
|
5616
|
+
notice.textContent = 'Loading…';
|
|
5617
|
+
empty.style.display = 'none';
|
|
5618
|
+
|
|
5619
|
+
// Use raw fetch (not apiFetch) so we can distinguish 404 (gate
|
|
5620
|
+
// disabled, expected during phase=off) from other errors without
|
|
5621
|
+
// apiFetch's throw-on-non-ok behavior.
|
|
5622
|
+
let res = null;
|
|
5623
|
+
let httpStatus = 0;
|
|
5624
|
+
try {
|
|
5625
|
+
const raw = await fetch('/pr-gate/metrics', {
|
|
5626
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
5627
|
+
});
|
|
5628
|
+
httpStatus = raw.status;
|
|
5629
|
+
if (raw.ok) res = await raw.json();
|
|
5630
|
+
} catch {
|
|
5631
|
+
res = null;
|
|
5632
|
+
}
|
|
5633
|
+
|
|
5634
|
+
if (httpStatus === 404 || (res && res.disabled === true)) {
|
|
5635
|
+
notice.textContent = 'Gate disabled (phase=off). No pipeline activity recorded yet.';
|
|
5636
|
+
empty.style.display = 'block';
|
|
5637
|
+
return;
|
|
5638
|
+
}
|
|
5639
|
+
if (!res) {
|
|
5640
|
+
notice.textContent = 'PR Pipeline metrics unavailable. Endpoint did not respond.';
|
|
5641
|
+
empty.style.display = 'block';
|
|
5642
|
+
return;
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5645
|
+
const phase = typeof res.phase === 'string' ? res.phase : 'unknown';
|
|
5646
|
+
notice.textContent = `Phase: ${phase}`;
|
|
5647
|
+
|
|
5648
|
+
const entries = Array.isArray(res.entries) ? res.entries : [];
|
|
5649
|
+
if (entries.length === 0) {
|
|
5650
|
+
empty.style.display = 'block';
|
|
5651
|
+
return;
|
|
5652
|
+
}
|
|
5653
|
+
|
|
5654
|
+
for (const entry of entries) {
|
|
5655
|
+
const card = document.createElement('div');
|
|
5656
|
+
card.style.background = 'var(--panel)';
|
|
5657
|
+
card.style.padding = '12px';
|
|
5658
|
+
card.style.borderRadius = '6px';
|
|
5659
|
+
card.style.border = '1px solid var(--border)';
|
|
5660
|
+
|
|
5661
|
+
const header = document.createElement('div');
|
|
5662
|
+
header.style.display = 'flex';
|
|
5663
|
+
header.style.justifyContent = 'space-between';
|
|
5664
|
+
header.style.marginBottom = '6px';
|
|
5665
|
+
|
|
5666
|
+
const left = document.createElement('div');
|
|
5667
|
+
left.style.fontWeight = '600';
|
|
5668
|
+
const pr = typeof entry.pr_number === 'number' ? `PR #${entry.pr_number}` : 'PR #—';
|
|
5669
|
+
const sha = typeof entry.head_sha === 'string' ? ` @ ${entry.head_sha.slice(0, 8)}` : '';
|
|
5670
|
+
left.textContent = pr + sha;
|
|
5671
|
+
|
|
5672
|
+
const right = document.createElement('div');
|
|
5673
|
+
right.style.fontSize = '12px';
|
|
5674
|
+
right.style.color = entry.eligible ? 'var(--accent)' : 'var(--text-dim)';
|
|
5675
|
+
right.textContent = entry.eligible ? 'eligible' : 'not eligible';
|
|
5676
|
+
|
|
5677
|
+
header.appendChild(left);
|
|
5678
|
+
header.appendChild(right);
|
|
5679
|
+
card.appendChild(header);
|
|
5680
|
+
|
|
5681
|
+
if (typeof entry.reason === 'string' && entry.reason.length > 0) {
|
|
5682
|
+
const reason = document.createElement('div');
|
|
5683
|
+
reason.style.fontSize = '13px';
|
|
5684
|
+
reason.style.color = 'var(--text-dim)';
|
|
5685
|
+
reason.textContent = entry.reason;
|
|
5686
|
+
card.appendChild(reason);
|
|
5687
|
+
}
|
|
5688
|
+
|
|
5689
|
+
if (typeof entry.created_at === 'string') {
|
|
5690
|
+
const time = document.createElement('div');
|
|
5691
|
+
time.style.fontSize = '11px';
|
|
5692
|
+
time.style.color = 'var(--text-dim)';
|
|
5693
|
+
time.style.marginTop = '4px';
|
|
5694
|
+
time.textContent = entry.created_at;
|
|
5695
|
+
card.appendChild(time);
|
|
5696
|
+
}
|
|
5697
|
+
|
|
5698
|
+
list.appendChild(card);
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
|
|
5548
5702
|
// ── Integrated-Being Tab (v1) ────────────────────────────────
|
|
5549
5703
|
let integratedBeingPollTimer = null;
|
|
5550
5704
|
|
|
@@ -5568,16 +5722,98 @@
|
|
|
5568
5722
|
if (entries.length === 0) {
|
|
5569
5723
|
tbody.innerHTML = '<tr><td colspan="7" style="padding:14px;color:var(--text-dim);text-align:center">No entries</td></tr>';
|
|
5570
5724
|
} else {
|
|
5571
|
-
|
|
5725
|
+
// Build a map of commitmentId → effective-status derivation
|
|
5726
|
+
// from supersession pointers: if a later note with subject
|
|
5727
|
+
// starting "expired:" or "stranded:" or "resolved:"/"cancelled:"
|
|
5728
|
+
// points back at a commitment, that commitment's effective
|
|
5729
|
+
// status flips to the supersession. (Slice 5 + slice 6.)
|
|
5730
|
+
const supersessionByTarget = new Map();
|
|
5731
|
+
for (const ent of entries) {
|
|
5732
|
+
if (ent.supersedes) {
|
|
5733
|
+
const existing = supersessionByTarget.get(ent.supersedes);
|
|
5734
|
+
// Prefer most-recent note with a lifecycle prefix.
|
|
5735
|
+
if (!existing || new Date(ent.t) > new Date(existing.t)) {
|
|
5736
|
+
supersessionByTarget.set(ent.supersedes, ent);
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
const disputeCountByTarget = new Map();
|
|
5741
|
+
for (const ent of entries) {
|
|
5742
|
+
if (ent.disputes) {
|
|
5743
|
+
disputeCountByTarget.set(
|
|
5744
|
+
ent.disputes,
|
|
5745
|
+
(disputeCountByTarget.get(ent.disputes) || 0) + 1,
|
|
5746
|
+
);
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
const esc2 = (s) => esc(String(s == null ? '' : s));
|
|
5750
|
+
const badge = (label, bg, fg) =>
|
|
5751
|
+
`<span style="display:inline-block;padding:1px 6px;font-size:10px;border-radius:3px;background:${bg};color:${fg};margin-right:4px">${esc2(label)}</span>`;
|
|
5752
|
+
tbody.innerHTML = entries.map(e => {
|
|
5753
|
+
const ts = (e.t || '').slice(0, 19).replace('T', ' ');
|
|
5754
|
+
let subjectCell = esc2(e.subject);
|
|
5755
|
+
let kindCell = esc2(e.kind);
|
|
5756
|
+
// Commitment-kind enrichment (slice 6): badges for mechanism
|
|
5757
|
+
// type, deadline w/ overdue highlight, refStatus, and any
|
|
5758
|
+
// derived effective-status from the supersession chain.
|
|
5759
|
+
if (e.kind === 'commitment' && e.commitment) {
|
|
5760
|
+
const mech = e.commitment.mechanism || {};
|
|
5761
|
+
const mechBg = mech.type === 'passive-wait' ? '#d4a017' : '#4a6a8a';
|
|
5762
|
+
kindCell = badge('commitment', '#6a4a8a', '#fff')
|
|
5763
|
+
+ badge(mech.type || '(?)', mechBg, '#fff');
|
|
5764
|
+
if (mech.refStatus && mech.refStatus !== 'valid') {
|
|
5765
|
+
kindCell += badge('ref:' + mech.refStatus, '#888', '#fff');
|
|
5766
|
+
}
|
|
5767
|
+
if (e.commitment.deadline) {
|
|
5768
|
+
const dlMs = Date.parse(e.commitment.deadline);
|
|
5769
|
+
const overdue = !Number.isNaN(dlMs) && dlMs < Date.now();
|
|
5770
|
+
const dlLabel = (e.commitment.deadline || '').slice(0, 16).replace('T', ' ');
|
|
5771
|
+
subjectCell += '<div style="font-size:11px;color:'
|
|
5772
|
+
+ (overdue ? '#e74c3c' : 'var(--text-dim)')
|
|
5773
|
+
+ ';margin-top:2px">'
|
|
5774
|
+
+ (overdue ? '⚠ overdue ' : 'due ')
|
|
5775
|
+
+ esc2(dlLabel)
|
|
5776
|
+
+ '</div>';
|
|
5777
|
+
}
|
|
5778
|
+
// Effective status from supersession chain.
|
|
5779
|
+
const superseder = supersessionByTarget.get(e.id);
|
|
5780
|
+
if (superseder && typeof superseder.subject === 'string') {
|
|
5781
|
+
const s = superseder.subject;
|
|
5782
|
+
let statusLabel = 'resolved';
|
|
5783
|
+
let statusBg = '#27ae60';
|
|
5784
|
+
if (s.startsWith('expired:')) { statusLabel = 'expired'; statusBg = '#e74c3c'; }
|
|
5785
|
+
else if (s.startsWith('stranded:')) { statusLabel = 'stranded'; statusBg = '#e67e22'; }
|
|
5786
|
+
else if (s.startsWith('cancelled:')) { statusLabel = 'cancelled'; statusBg = '#7f8c8d'; }
|
|
5787
|
+
subjectCell = badge(statusLabel, statusBg, '#fff') + subjectCell;
|
|
5788
|
+
}
|
|
5789
|
+
const disputes = disputeCountByTarget.get(e.id) || 0;
|
|
5790
|
+
if (disputes > 0) {
|
|
5791
|
+
subjectCell = badge('disputed × ' + disputes, '#c0392b', '#fff') + subjectCell;
|
|
5792
|
+
}
|
|
5793
|
+
} else if (e.kind === 'note' && e.disputes) {
|
|
5794
|
+
// Dispute note — highlight the disputes-pointer.
|
|
5795
|
+
kindCell = badge('note', '#444', '#fff') + badge('dispute', '#c0392b', '#fff');
|
|
5796
|
+
} else if (e.kind === 'note' && typeof e.subject === 'string' && e.subject.startsWith('expired:')) {
|
|
5797
|
+
kindCell = badge('note', '#444', '#fff') + badge('expired', '#e74c3c', '#fff');
|
|
5798
|
+
} else if (e.kind === 'note' && typeof e.subject === 'string' && e.subject.startsWith('stranded:')) {
|
|
5799
|
+
kindCell = badge('note', '#444', '#fff') + badge('stranded', '#e67e22', '#fff');
|
|
5800
|
+
}
|
|
5801
|
+
const ptr = e.supersedes
|
|
5802
|
+
? 'supersedes:' + e.supersedes
|
|
5803
|
+
: e.disputes
|
|
5804
|
+
? 'disputes:' + e.disputes
|
|
5805
|
+
: '';
|
|
5806
|
+
return `
|
|
5572
5807
|
<tr style="border-top:1px solid var(--border)">
|
|
5573
|
-
<td style="padding:6px;font-family:monospace">${
|
|
5574
|
-
<td style="padding:6px">${
|
|
5575
|
-
<td style="padding:6px">${
|
|
5576
|
-
<td style="padding:6px">${
|
|
5577
|
-
<td style="padding:6px">${
|
|
5578
|
-
<td style="padding:6px;font-size:11px;color:var(--text-dim)">${
|
|
5579
|
-
<td style="padding:6px;font-family:monospace;font-size:11px">${
|
|
5580
|
-
</tr
|
|
5808
|
+
<td style="padding:6px;font-family:monospace">${esc2(e.id)}</td>
|
|
5809
|
+
<td style="padding:6px">${esc2(ts)}</td>
|
|
5810
|
+
<td style="padding:6px">${kindCell}</td>
|
|
5811
|
+
<td style="padding:6px">${subjectCell}</td>
|
|
5812
|
+
<td style="padding:6px">${esc2(e.counterparty?.type)}/${esc2(e.counterparty?.name)}</td>
|
|
5813
|
+
<td style="padding:6px;font-size:11px;color:var(--text-dim)">${esc2(e.provenance)}${e.source ? ' · '+esc2(e.source):''}</td>
|
|
5814
|
+
<td style="padding:6px;font-family:monospace;font-size:11px">${esc2(ptr)}</td>
|
|
5815
|
+
</tr>`;
|
|
5816
|
+
}).join('');
|
|
5581
5817
|
}
|
|
5582
5818
|
}
|
|
5583
5819
|
if (statsRes) {
|
|
@@ -5599,9 +5835,82 @@
|
|
|
5599
5835
|
}
|
|
5600
5836
|
}
|
|
5601
5837
|
|
|
5838
|
+
async function loadIntegratedBeingBindings() {
|
|
5839
|
+
// GET /shared-state/sessions returns 503 when v2Enabled=false.
|
|
5840
|
+
// In that case, keep the Bindings section hidden.
|
|
5841
|
+
const section = document.getElementById('ibBindingsSection');
|
|
5842
|
+
const tbody = document.getElementById('ibBindingsTbody');
|
|
5843
|
+
try {
|
|
5844
|
+
const res = await apiFetch('/shared-state/sessions').catch(() => null);
|
|
5845
|
+
if (!res || !Array.isArray(res.sessions)) {
|
|
5846
|
+
if (section) section.style.display = 'none';
|
|
5847
|
+
return;
|
|
5848
|
+
}
|
|
5849
|
+
if (section) section.style.display = 'block';
|
|
5850
|
+
if (res.sessions.length === 0) {
|
|
5851
|
+
tbody.innerHTML = '<tr><td colspan="7" style="padding:14px;color:var(--text-dim);text-align:center">No sessions registered</td></tr>';
|
|
5852
|
+
return;
|
|
5853
|
+
}
|
|
5854
|
+
const nowMs = Date.now();
|
|
5855
|
+
const esc2 = (s) => esc(String(s == null ? '' : s));
|
|
5856
|
+
tbody.innerHTML = res.sessions.map(s => {
|
|
5857
|
+
const ttlMs = Date.parse(s.absoluteExpiresAt || '') - nowMs;
|
|
5858
|
+
const ttlLabel = Number.isFinite(ttlMs)
|
|
5859
|
+
? (ttlMs < 0 ? 'expired' : Math.round(ttlMs / 3600000) + 'h')
|
|
5860
|
+
: '';
|
|
5861
|
+
const status = s.revoked
|
|
5862
|
+
? '<span style="color:#e74c3c">revoked</span>'
|
|
5863
|
+
: (Date.parse(s.absoluteExpiresAt || '') < nowMs
|
|
5864
|
+
? '<span style="color:#888">expired</span>'
|
|
5865
|
+
: (s.hasWritten ? '<span style="color:#27ae60">active</span>' : '<span style="color:var(--text-dim)">bound</span>'));
|
|
5866
|
+
const idShort = (s.sessionId || '').slice(0, 8) + '…';
|
|
5867
|
+
const action = s.revoked
|
|
5868
|
+
? '<span style="color:var(--text-dim);font-size:10px">—</span>'
|
|
5869
|
+
: `<button onclick="revokeIntegratedBeingBinding('${esc2(s.sessionId)}')" style="padding:2px 8px;font-size:10px;background:#c0392b;color:#fff;border:none;border-radius:3px;cursor:pointer">Revoke</button>`;
|
|
5870
|
+
return `
|
|
5871
|
+
<tr style="border-top:1px solid var(--border)">
|
|
5872
|
+
<td style="padding:4px;font-family:monospace" title="${esc2(s.sessionId)}">${esc2(idShort)}</td>
|
|
5873
|
+
<td style="padding:4px">${esc2(s.label || '')}</td>
|
|
5874
|
+
<td style="padding:4px">${esc2((s.registeredAt || '').slice(0, 16).replace('T', ' '))}</td>
|
|
5875
|
+
<td style="padding:4px">${esc2((s.lastActiveAt || '').slice(0, 16).replace('T', ' '))}</td>
|
|
5876
|
+
<td style="padding:4px">${esc2(ttlLabel)}</td>
|
|
5877
|
+
<td style="padding:4px">${status}</td>
|
|
5878
|
+
<td style="padding:4px">${action}</td>
|
|
5879
|
+
</tr>`;
|
|
5880
|
+
}).join('');
|
|
5881
|
+
} catch (err) {
|
|
5882
|
+
console.error('[integrated-being-v2] bindings load error', err);
|
|
5883
|
+
if (section) section.style.display = 'none';
|
|
5884
|
+
}
|
|
5885
|
+
}
|
|
5886
|
+
|
|
5887
|
+
async function revokeIntegratedBeingBinding(sid) {
|
|
5888
|
+
if (!sid) return;
|
|
5889
|
+
if (!confirm('Revoke the binding for session ' + sid.slice(0, 8) + '…?\n\nThis invalidates the session token. Subsequent writes from that session will fail 401.')) return;
|
|
5890
|
+
try {
|
|
5891
|
+
const res = await apiFetch(`/shared-state/sessions/${encodeURIComponent(sid)}/revoke`, {
|
|
5892
|
+
method: 'POST',
|
|
5893
|
+
headers: { 'X-Instar-Request': '1' },
|
|
5894
|
+
});
|
|
5895
|
+
if (res && res.revoked) {
|
|
5896
|
+
await loadIntegratedBeingBindings();
|
|
5897
|
+
await loadIntegratedBeing();
|
|
5898
|
+
} else {
|
|
5899
|
+
alert('Revocation did not succeed — see console for details.');
|
|
5900
|
+
console.warn('[integrated-being-v2] revoke unexpected', res);
|
|
5901
|
+
}
|
|
5902
|
+
} catch (err) {
|
|
5903
|
+
console.error('[integrated-being-v2] revoke error', err);
|
|
5904
|
+
alert('Revoke failed: ' + (err && err.message ? err.message : err));
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
|
|
5602
5908
|
function startIntegratedBeingPoll() {
|
|
5603
5909
|
if (integratedBeingPollTimer) return;
|
|
5604
|
-
integratedBeingPollTimer = setInterval(
|
|
5910
|
+
integratedBeingPollTimer = setInterval(() => {
|
|
5911
|
+
loadIntegratedBeing();
|
|
5912
|
+
loadIntegratedBeingBindings();
|
|
5913
|
+
}, 30000);
|
|
5605
5914
|
}
|
|
5606
5915
|
function stopIntegratedBeingPoll() {
|
|
5607
5916
|
if (integratedBeingPollTimer) {
|
package/dist/cli.js
CHANGED
|
@@ -1557,13 +1557,22 @@ const migrateCmd = program
|
|
|
1557
1557
|
// /shared-state/render injection after an update.
|
|
1558
1558
|
migrateCmd
|
|
1559
1559
|
.command('sync-session-hook')
|
|
1560
|
-
.description('Sync .claude/hooks/instar/session-start.sh with the latest template (Integrated-Being v1)')
|
|
1560
|
+
.description('Sync .claude/hooks/instar/session-start.sh with the latest template (Integrated-Being v1 + v2)')
|
|
1561
1561
|
.option('-d, --dir <path>', 'Project directory')
|
|
1562
1562
|
.option('--force', 'Overwrite a divergent local hook')
|
|
1563
|
+
.option('--v2-mode <mode>', 'v2 migration mode: "inject" (update only v2 section, preserve customizations) or "overwrite" (replace entire hook, save backup)')
|
|
1563
1564
|
.action(async (opts) => {
|
|
1564
1565
|
try {
|
|
1566
|
+
if (opts.v2Mode && opts.v2Mode !== 'inject' && opts.v2Mode !== 'overwrite') {
|
|
1567
|
+
console.error(JSON.stringify({ error: '--v2-mode must be "inject" or "overwrite"' }));
|
|
1568
|
+
process.exit(2);
|
|
1569
|
+
}
|
|
1565
1570
|
const { syncSessionHook } = await import('./commands/migrate.js');
|
|
1566
|
-
const result = await syncSessionHook(
|
|
1571
|
+
const result = await syncSessionHook({
|
|
1572
|
+
dir: opts.dir,
|
|
1573
|
+
force: opts.force,
|
|
1574
|
+
v2Mode: opts.v2Mode,
|
|
1575
|
+
});
|
|
1567
1576
|
console.log(JSON.stringify(result));
|
|
1568
1577
|
}
|
|
1569
1578
|
catch (err) {
|
|
@@ -1898,5 +1907,45 @@ playbookCmd
|
|
|
1898
1907
|
const { playbookUserAudit } = await import('./commands/playbook.js');
|
|
1899
1908
|
return playbookUserAudit(userId, opts);
|
|
1900
1909
|
});
|
|
1910
|
+
// ── `instar gate` — UnjustifiedStopGate operator tooling (PR4) ──────
|
|
1911
|
+
const gateCmd = program
|
|
1912
|
+
.command('gate')
|
|
1913
|
+
.description('Operator tooling for the UnjustifiedStopGate (context-death-pitfall-prevention)');
|
|
1914
|
+
gateCmd
|
|
1915
|
+
.command('status')
|
|
1916
|
+
.description('Show gate mode, kill-switch state, autonomous flag')
|
|
1917
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
1918
|
+
.action(async (opts) => {
|
|
1919
|
+
const { gateStatus } = await import('./commands/gate.js');
|
|
1920
|
+
return gateStatus(opts);
|
|
1921
|
+
});
|
|
1922
|
+
gateCmd
|
|
1923
|
+
.command('set <subject>')
|
|
1924
|
+
.description('Set a gate mode. Subjects: unjustified-stop')
|
|
1925
|
+
.requiredOption('--mode <mode>', 'off | shadow | enforce')
|
|
1926
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
1927
|
+
.action(async (subject, opts) => {
|
|
1928
|
+
const { gateSet } = await import('./commands/gate.js');
|
|
1929
|
+
return gateSet(subject, opts);
|
|
1930
|
+
});
|
|
1931
|
+
gateCmd
|
|
1932
|
+
.command('kill-switch')
|
|
1933
|
+
.description('Set or clear the gate kill-switch (fast-path allow-everything override)')
|
|
1934
|
+
.option('--set', 'Set the kill-switch (all evaluations short-circuit to allow)')
|
|
1935
|
+
.option('--clear', 'Clear the kill-switch (restore normal evaluation)')
|
|
1936
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
1937
|
+
.action(async (opts) => {
|
|
1938
|
+
const { gateKillSwitch } = await import('./commands/gate.js');
|
|
1939
|
+
return gateKillSwitch(opts);
|
|
1940
|
+
});
|
|
1941
|
+
gateCmd
|
|
1942
|
+
.command('log')
|
|
1943
|
+
.description('Show the most recent gate evaluation events')
|
|
1944
|
+
.option('--tail <n>', 'Number of events to show (default 20)')
|
|
1945
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
1946
|
+
.action(async (opts) => {
|
|
1947
|
+
const { gateLog } = await import('./commands/gate.js');
|
|
1948
|
+
return gateLog(opts);
|
|
1949
|
+
});
|
|
1901
1950
|
program.parse();
|
|
1902
1951
|
//# sourceMappingURL=cli.js.map
|