feat(box): passkey fetch, agent key-approval flow, unified lookups, tmux agent UX

- box passkey [show|fetch] (+ muse passkey): documents VM-only passkey
  (/srv/box/passkey.txt, fallback /etc/netvm/passkey.txt on 34.139.37.135),
  probes VM over SSH with graceful fallback; --json supported. No secrets on bl.
- approvals: request_key_approval / check_node_key_request; KEY_APPROVAL status
  surfaced in `box approvals check`; allow/deny resolve + audit to box-ctl.jsonl;
  never auto-approved. New `box approvals request-key <node> --reason`.
- box lookup (summary|fleet|threads|unread|approvals|key|docs) and docs-lookup
  engine with lookup_internal/ database (docs_internal symlink).
- muse-tmux: non-TTY attach falls back to scrollback capture; prune NameError fix.
- box/muse passthrough for tmux/muse/docs; thread list/view alias + prefix resolve.
- Docs: AGENTS.md, AGENT-TOOLING.md, BOX-WEB-SURFACE-GUIDE.md, README.
- Tests: key-approval + passkey tests; sync stale sidechat UUIDs and manifest name.
- .gitignore runtime trackers (subagent-sessions, conversation-nudge-tracker).
This commit is contained in:
operator
2026-10-05 20:18:47 +00:00
parent 59c9965791
commit adfcd2e602
38 changed files with 5948 additions and 168 deletions
+169 -1
View File
@@ -67,7 +67,7 @@
// Check hash on load
const hash = window.location.hash.replace('#', '');
if (['dashboard', 'dms', 'jobs', 'loops'].includes(hash)) {
if (['dashboard', 'dms', 'jobs', 'loops', 'lookup'].includes(hash)) {
switchTab(hash);
}
}
@@ -1188,6 +1188,8 @@
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/timers`;
} else if (currentTab === 'loops') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/loop/status\n\ncurl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/loop/health`;
} else if (currentTab === 'lookup') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/lookup\n\n# Or CLI lookup on bl:\nbox lookup surfaces\nbox lookup parse "[RESULT 7fce46e0] OK Done"`;
}
}
@@ -1278,6 +1280,171 @@
}
}
// -------------------------------------------------------------------------
// 8. Lookup & Grammar Surface Integration
// -------------------------------------------------------------------------
window.setLookupPreset = function (text) {
const input = document.getElementById('lookup-test-input');
if (input) {
input.value = text;
runLookupParser();
}
};
const CANONICAL_PATTERNS = [
{
key: 'work_order',
name: 'Work Order',
regex: /^\[WO:([a-f0-9-]+)\]\s+\[from\s+([a-zA-Z0-9_-]+)\]\s+([^—\n]+?)\s*—\s*(.+)$/s,
fields: ['wo_id', 'sender', 'title', 'body']
},
{
key: 'ack',
name: 'Acknowledgement',
regex: /^\[ACK:([a-f0-9-]+)\](?:\s+\[from\s+([a-zA-Z0-9_-]+)\])?/,
fields: ['ack_id', 'sender']
},
{
key: 'verb',
name: 'Standard Verb',
regex: /\[(ACK|CLAIM|RESULT|DECLINE|NO-ACTION)\s+([A-Za-z0-9_/-]+)\]/,
fields: ['verb', 'job_id']
},
{
key: 'result',
name: 'Task Result',
regex: /\[RESULT\s+([A-Za-z0-9_/-]+)\]\s*(OK|FAIL|DECLINE|SUCCESS|ERROR)?\s*(.*?)(?=\[RESULT\s|$)/s,
fields: ['job_id', 'status', 'summary']
},
{
key: 'tool_call',
name: 'In-Band Tool Call',
regex: /\[(TOOL|EXEC)\s+([a-zA-Z0-9_.-]+)\s+(\{.*?\})\]/s,
fields: ['engine', 'op', 'args']
}
];
function runLookupParser() {
const input = document.getElementById('lookup-test-input');
const resBox = document.getElementById('lookup-parse-result');
if (!input || !resBox) return;
const val = input.value.trim();
if (!val) {
resBox.style.display = 'none';
return;
}
const matches = [];
CANONICAL_PATTERNS.forEach(pat => {
const m = pat.regex.exec(val);
if (m) {
const tokens = {};
pat.fields.forEach((f, idx) => {
tokens[f] = m[idx + 1] !== undefined ? m[idx + 1].trim() : null;
});
matches.push({
key: pat.key,
name: pat.name,
matchedText: m[0],
tokens: tokens
});
}
});
resBox.style.display = 'block';
if (matches.length === 0) {
resBox.innerHTML = `
<div style="color: var(--warn); display: flex; align-items: center; gap: 8px;">
<span>⚠</span>
<span>No canonical sentence pattern matched this input. Check required tags: [WO:id] [from sender], [ACK:id], [RESULT id] OK, or [CLAIM id].</span>
</div>
`;
} else {
let html = `<div style="color: var(--ok); font-weight: 700; margin-bottom: 8px;">✔ Valid Syntax — Matched ${matches.length} Pattern(s):</div>`;
matches.forEach(m => {
html += `
<div style="border-top: 1px solid var(--border); padding-top: 8px; margin-top: 8px;">
<div style="font-weight: 600; color: var(--accent); margin-bottom: 4px;">Pattern: ${m.name} (<code>${m.key}</code>)</div>
<div style="color: var(--muted); font-size: 11px; margin-bottom: 6px;">Matched Chunk: <span style="color: var(--fg);">${m.matchedText}</span></div>
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
`;
Object.entries(m.tokens).forEach(([k, v]) => {
html += `
<div style="background: var(--bg); border: 1px solid var(--border); padding: 4px 8px; border-radius: 4px; font-size: 12px;">
<span style="color: var(--muted);">${k}:</span> <strong style="color: var(--ok);">${v || '-'}</strong>
</div>
`;
});
html += `</div></div>`;
});
resBox.innerHTML = html;
}
}
function renderLookupSurfaces() {
const tbody = document.getElementById('lookup-surfaces-tbody');
if (!tbody) return;
const surfaces = [
{ name: 'Fleet Pulse', id: 'dashboard', selector: '.tab-btn[data-tab="dashboard"]', route: 'GET /api/box/fleet', hint: 'Real-time CDP status, page titles, and queue depths across all nodes.' },
{ name: 'DMs & Work Orders', id: 'dms', selector: '.tab-btn[data-tab="dms"]', route: 'GET /api/box/dm/log?limit=50', hint: 'Chronological audit trail of signed work orders, acks, and agent replies.' },
{ name: 'Timers & Jobs', id: 'jobs', selector: '.tab-btn[data-tab="jobs"]', route: 'GET /api/box/timers', hint: 'Systemd user timers with hot-trigger buttons (POST /api/box/jobs/{name}/trigger).' },
{ name: 'Loop & Strategy', id: 'loops', selector: '.tab-btn[data-tab="loops"]', route: 'GET /api/box/loop/health', hint: 'Fleet loop velocity, open SLA deadlines, strategies, and runtime variables.' },
{ name: 'Lookup & Grammar', id: 'lookup', selector: '.tab-btn[data-tab="lookup"]', route: 'GET /api/box/lookup', hint: 'Interactive regex testing, sentence grammar, and DOM surface maps.' },
{ name: 'Approvals Surface', id: 'approvals', selector: '[data-testid="approval-dialog"]', route: 'GET /api/approvals', hint: 'Permission modals and operator elevation requests (exit code 2 contract).' }
];
tbody.innerHTML = surfaces.map(s => `
<tr>
<td style="font-weight: 600; color: var(--fg);">${s.name}</td>
<td><code>#tab-${s.id}</code></td>
<td><code style="color: var(--accent);">${s.selector}</code></td>
<td><code style="color: var(--ok);">${s.route}</code></td>
<td style="color: var(--muted); font-size: 12px;">${s.hint}</td>
</tr>
`).join('');
}
function renderLookupSentences() {
const grid = document.getElementById('lookup-sentence-grid');
if (!grid) return;
const cards = [
{ name: 'Work Order', tag: '[WO:<id>]', template: '[WO:{id}] [from {sender}] {title} — {body}', lifecycle: 'open -> claimed -> resolved', desc: 'Dispatches actionable, trackable tasking between operators or from orchestrator.' },
{ name: 'Acknowledgement', tag: '[ACK:<id>]', template: '[ACK:{id}] [from {sender}]', lifecycle: 'open -> acknowledged', desc: 'Confirms receipt of task without closing the tracked loop.' },
{ name: 'Task Claim', tag: '[CLAIM <id>]', template: '[CLAIM {job_id}]', lifecycle: 'acknowledged -> claimed', desc: 'Declares worker ownership of a task or swarm slot, preventing duplicate runs.' },
{ name: 'Task Result', tag: '[RESULT <id>]', template: '[RESULT {job_id}] {status} {summary}', lifecycle: 'claimed -> resolved', desc: 'Submits completion evidence and resolves the active loop.' },
{ name: 'Task Decline', tag: '[DECLINE <id>]', template: '[DECLINE {job_id}] {reason}', lifecycle: 'claimed -> declined', desc: 'Explicit rejection of a task with reason, prompting fallback.' },
{ name: 'In-Band Tool Call', tag: '[TOOL <op> <args>]', template: '[TOOL {op} {args_json}]', lifecycle: 'in-flight execution', desc: 'Inline tool directive parsed and executed directly by response-harvester.' }
];
grid.innerHTML = cards.map(c => `
<div class="node-card" style="padding: 16px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-weight: 700; color: var(--fg);">${c.name}</span>
<span class="node-status-badge badge-active">${c.tag}</span>
</div>
<div style="font-family: var(--font-mono); font-size: 12px; color: var(--accent); background: var(--bg); padding: 6px 8px; border-radius: 4px; margin-bottom: 8px; word-break: break-all;">${c.template}</div>
<div style="font-size: 12px; color: var(--muted); margin-bottom: 8px;">${c.desc}</div>
<div style="font-size: 11px; color: var(--muted); text-transform: uppercase;">Lifecycle: <span style="color: var(--ok);">${c.lifecycle}</span></div>
</div>
`).join('');
}
function setupLookupTab() {
const parseBtn = document.getElementById('lookup-parse-btn');
const input = document.getElementById('lookup-test-input');
if (parseBtn) parseBtn.addEventListener('click', runLookupParser);
if (input) {
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') runLookupParser();
});
}
renderLookupSurfaces();
renderLookupSentences();
}
// -------------------------------------------------------------------------
// 9. Initialization
// -------------------------------------------------------------------------
@@ -1291,6 +1458,7 @@
setupTabs();
setupFilters();
setupCurlDrawer();
setupLookupTab();
// Initial Fetch & Start Polling
refreshData();
+60
View File
@@ -47,6 +47,9 @@
Loop &amp; Strategy
<span id="loops-count-badge" class="tab-badge">0</span>
</button>
<button class="tab-btn" data-tab="lookup">
Lookup &amp; Grammar
</button>
</nav>
<!-- Main Container -->
@@ -242,6 +245,63 @@
</div>
</section>
<!-- Tab 5: Lookup & Grammar -->
<section id="tab-lookup" class="tab-pane">
<!-- Section 1: Interactive Regex & Sentence Parser -->
<div class="section-heading">
<div class="section-title">Interactive Sentence &amp; Regex Parser</div>
<div class="section-subtitle">Test and validate agent sentence structures against lookup_internal patterns</div>
</div>
<div class="table-card" style="padding: 16px;">
<div style="display: flex; gap: 8px; margin-bottom: 12px;">
<input type="text" id="lookup-test-input" placeholder="Type or paste an agent message (e.g. [WO:7fce46e0] [from super] Audit — Check stats)..." style="flex: 1; padding: 10px 14px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-family: var(--font-mono); font-size: 13px;">
<button id="lookup-parse-btn" class="btn-control" style="background: var(--accent); color: #fff; font-weight: 600; padding: 0 18px;">Parse &amp; Validate</button>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 12px;">
<span style="font-size: 11px; color: var(--muted); text-transform: uppercase; align-self: center;">Presets:</span>
<button class="btn-control preset-btn" onclick="setLookupPreset('[WO:7fce46e0] [from super] Audit exec.muse-dev.online — Check 200 OK codes')">[WO]</button>
<button class="btn-control preset-btn" onclick="setLookupPreset('[ACK:7fce46e0] [from 646]')">[ACK]</button>
<button class="btn-control preset-btn" onclick="setLookupPreset('[CLAIM 7fce46e0]')">[CLAIM]</button>
<button class="btn-control preset-btn" onclick="setLookupPreset('[RESULT 7fce46e0] OK 14 endpoints verified healthy')">[RESULT]</button>
<button class="btn-control preset-btn" onclick="setLookupPreset('[TOOL followup.create {&quot;in_m&quot;: 5, &quot;prompt&quot;: &quot;Recheck reachability&quot;}]')">[TOOL]</button>
</div>
<div id="lookup-parse-result" style="display: none; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 12px; font-family: var(--font-mono); font-size: 13px;">
<!-- Rendered dynamically -->
</div>
</div>
<!-- Section 2: Sentence Structure Catalog -->
<div class="section-heading" style="margin-top: 24px;">
<div class="section-title">Protocol Grammar &amp; Conversational Contracts</div>
<div class="section-subtitle">Authoritative patterns from lookup_internal/sentence_structure.json</div>
</div>
<div id="lookup-sentence-grid" class="grid-nodes">
<!-- Rendered dynamically by box.js -->
</div>
<!-- Section 3: Assistive Surfaces Catalog -->
<div class="section-heading" style="margin-top: 24px;">
<div class="section-title">Assistive Surfaces Map for box.muse-dev.online</div>
<div class="section-subtitle">DOM Selectors, data-testids, and REST endpoints for browser agents</div>
</div>
<div class="table-card">
<table id="lookup-surfaces-table" class="data-table">
<thead>
<tr>
<th style="width: 120px;">Surface</th>
<th style="width: 150px;">Tab / Pane ID</th>
<th style="width: 240px;">DOM Tab Selector</th>
<th style="width: 240px;">API Route</th>
<th>Assistive Purpose &amp; Hint</th>
</tr>
</thead>
<tbody id="lookup-surfaces-tbody">
<!-- Rendered dynamically by box.js -->
</tbody>
</table>
</div>
</section>
</main>
<!-- 'View as curl' Drawer -->