@njeybe/nativ 2.2.0 → 2.3.1
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/CHANGELOG.md +24 -1
- package/README.md +15 -0
- package/dist/runner/agent-supervisor.d.ts +5 -3
- package/dist/runner/agent-supervisor.js +17 -12
- package/dist/server/studio-server.js +1 -130
- package/dist/server/studio-ui/document.d.ts +3 -0
- package/dist/server/studio-ui/document.js +22 -0
- package/dist/server/studio-ui/pages/benchmarks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/benchmarks/index.js +11 -0
- package/dist/server/studio-ui/pages/benchmarks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/script.js +104 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.js +30 -0
- package/dist/server/studio-ui/pages/database/browser.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/browser.js +326 -0
- package/dist/server/studio-ui/pages/database/connection.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/connection.js +158 -0
- package/dist/server/studio-ui/pages/database/data-shell.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/data-shell.js +165 -0
- package/dist/server/studio-ui/pages/database/drift.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/drift.js +301 -0
- package/dist/server/studio-ui/pages/database/events.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/events.js +231 -0
- package/dist/server/studio-ui/pages/database/explorer.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/explorer.js +183 -0
- package/dist/server/studio-ui/pages/database/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/index.js +28 -0
- package/dist/server/studio-ui/pages/database/markup.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/markup.js +32 -0
- package/dist/server/studio-ui/pages/database/state.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/state.js +57 -0
- package/dist/server/studio-ui/pages/database/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/styles.js +118 -0
- package/dist/server/studio-ui/pages/flow/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/flow/index.js +11 -0
- package/dist/server/studio-ui/pages/flow/layout.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/layout.js +105 -0
- package/dist/server/studio-ui/pages/flow/plan-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/plan-view.js +67 -0
- package/dist/server/studio-ui/pages/flow/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/script.js +61 -0
- package/dist/server/studio-ui/pages/flow/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/styles.js +59 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.js +95 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.js +92 -0
- package/dist/server/studio-ui/pages/home/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/home/index.js +11 -0
- package/dist/server/studio-ui/pages/home/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/script.js +160 -0
- package/dist/server/studio-ui/pages/home/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/styles.js +48 -0
- package/dist/server/studio-ui/pages/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/index.js +17 -0
- package/dist/server/studio-ui/pages/tasks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/tasks/index.js +11 -0
- package/dist/server/studio-ui/pages/tasks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/script.js +96 -0
- package/dist/server/studio-ui/pages/tasks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/styles.js +37 -0
- package/dist/server/studio-ui/pages/team/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/team/index.js +11 -0
- package/dist/server/studio-ui/pages/team/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/script.js +112 -0
- package/dist/server/studio-ui/pages/team/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/styles.js +22 -0
- package/dist/server/studio-ui/pages/types.d.ts +13 -0
- package/dist/server/studio-ui/pages/types.js +1 -0
- package/dist/server/studio-ui/pages/worktrees/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/worktrees/index.js +11 -0
- package/dist/server/studio-ui/pages/worktrees/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/script.js +104 -0
- package/dist/server/studio-ui/pages/worktrees/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/styles.js +15 -0
- package/dist/server/studio-ui/shell/actions.d.ts +1 -0
- package/dist/server/studio-ui/shell/actions.js +49 -0
- package/dist/server/studio-ui/shell/boot.d.ts +2 -0
- package/dist/server/studio-ui/shell/boot.js +13 -0
- package/dist/server/studio-ui/shell/console.d.ts +1 -0
- package/dist/server/studio-ui/shell/console.js +194 -0
- package/dist/server/studio-ui/shell/core.d.ts +1 -0
- package/dist/server/studio-ui/shell/core.js +50 -0
- package/dist/server/studio-ui/shell/detail-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail-view.js +80 -0
- package/dist/server/studio-ui/shell/detail.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail.js +83 -0
- package/dist/server/studio-ui/shell/dispatch.d.ts +1 -0
- package/dist/server/studio-ui/shell/dispatch.js +150 -0
- package/dist/server/studio-ui/shell/events-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/events-tools.js +94 -0
- package/dist/server/studio-ui/shell/format.d.ts +1 -0
- package/dist/server/studio-ui/shell/format.js +151 -0
- package/dist/server/studio-ui/shell/icons.d.ts +2 -0
- package/dist/server/studio-ui/shell/icons.js +20 -0
- package/dist/server/studio-ui/shell/markup-head.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-head.js +43 -0
- package/dist/server/studio-ui/shell/markup-panels.d.ts +2 -0
- package/dist/server/studio-ui/shell/markup-panels.js +7 -0
- package/dist/server/studio-ui/shell/markup-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-tools.js +222 -0
- package/dist/server/studio-ui/shell/model.d.ts +1 -0
- package/dist/server/studio-ui/shell/model.js +192 -0
- package/dist/server/studio-ui/shell/paint.d.ts +1 -0
- package/dist/server/studio-ui/shell/paint.js +154 -0
- package/dist/server/studio-ui/shell/palette-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette-view.js +60 -0
- package/dist/server/studio-ui/shell/palette.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette.js +80 -0
- package/dist/server/studio-ui/shell/pipeline-state.d.ts +1 -0
- package/dist/server/studio-ui/shell/pipeline-state.js +152 -0
- package/dist/server/studio-ui/shell/proposals.d.ts +1 -0
- package/dist/server/studio-ui/shell/proposals.js +197 -0
- package/dist/server/studio-ui/shell/pure.d.ts +3 -0
- package/dist/server/studio-ui/shell/pure.js +9 -0
- package/dist/server/studio-ui/shell/router.d.ts +1 -0
- package/dist/server/studio-ui/shell/router.js +95 -0
- package/dist/server/studio-ui/shell/sidebar-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +38 -0
- package/dist/server/studio-ui/shell/sync.d.ts +1 -0
- package/dist/server/studio-ui/shell/sync.js +120 -0
- package/dist/server/studio-ui/shell/toasts-format.d.ts +1 -0
- package/dist/server/studio-ui/shell/toasts-format.js +89 -0
- package/dist/server/studio-ui/shell/triage.d.ts +1 -0
- package/dist/server/studio-ui/shell/triage.js +210 -0
- package/dist/server/studio-ui/styles/console.d.ts +1 -0
- package/dist/server/studio-ui/styles/console.js +83 -0
- package/dist/server/studio-ui/styles/dialogs.d.ts +1 -0
- package/dist/server/studio-ui/styles/dialogs.js +118 -0
- package/dist/server/studio-ui/styles/responsive.d.ts +1 -0
- package/dist/server/studio-ui/styles/responsive.js +28 -0
- package/dist/server/studio-ui/styles/shell.d.ts +1 -0
- package/dist/server/studio-ui/styles/shell.js +117 -0
- package/dist/server/studio-ui/styles/strategist.d.ts +1 -0
- package/dist/server/studio-ui/styles/strategist.js +77 -0
- package/dist/server/studio-ui/styles/tokens-base.d.ts +1 -0
- package/dist/server/studio-ui/styles/tokens-base.js +131 -0
- package/dist/server/studio-ui.d.ts +1 -10
- package/dist/server/studio-ui.js +63 -5314
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Tier 1 strategist.
|
|
2
|
+
export const triageScript = String.raw ` // ─── Tier 1 AI Strategist (/api/pipeline/triage/*, ui_specs.md §5) ─────────
|
|
3
|
+
/** Decision-card selection for the escalation on screen; survives re-renders from live updates. */
|
|
4
|
+
var t1Choice = { escalationId: null, index: 0, custom: '' };
|
|
5
|
+
|
|
6
|
+
/** "gemini-3.8-flash" -> "Gemini 3.8 Flash". */
|
|
7
|
+
function modelName(id) {
|
|
8
|
+
return String(id || 'gemini').split('-').map(function (w) { return w.charAt(0).toUpperCase() + w.slice(1); }).join(' ');
|
|
9
|
+
}
|
|
10
|
+
function triageRunningCount() { return Object.keys(pipe.triageRunning).length; }
|
|
11
|
+
/** Pending escalations whose stored Tier 1 verdict asks the product owner to decide. */
|
|
12
|
+
function awaitingDecision() {
|
|
13
|
+
return (pipe.escalations || []).filter(function (e) {
|
|
14
|
+
return e.status === 'pending_review' && e.triage && e.triage.classification === 'REQUIRE_HUMAN_DECISION';
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function lastTriage() {
|
|
18
|
+
if (pipe.triageLast) return pipe.triageLast;
|
|
19
|
+
var newest = null;
|
|
20
|
+
(pipe.escalations || []).forEach(function (e) {
|
|
21
|
+
if (e.triage && (!newest || String(e.triage.evaluatedAt) > String(newest.evaluatedAt))) newest = e.triage;
|
|
22
|
+
});
|
|
23
|
+
return newest;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderTriageChip() {
|
|
27
|
+
var t = pipe.triage;
|
|
28
|
+
var model = (t && t.model) || 'gemini-3.8-flash';
|
|
29
|
+
var waiting = awaitingDecision().length;
|
|
30
|
+
var state = triageRunningCount() ? 'triaging' : waiting ? 'attention' : 'idle';
|
|
31
|
+
var chip = $('t1-chip');
|
|
32
|
+
chip.setAttribute('data-state', state);
|
|
33
|
+
chip.title = state === 'triaging' ? 'Tier 1 AI Strategist is assessing an escalation'
|
|
34
|
+
: state === 'attention' ? waiting + ' escalation' + (waiting === 1 ? ' needs' : 's need') + ' your decision' : 'Tier 1 AI Strategist';
|
|
35
|
+
$('t1-chip-model').textContent = modelName(model);
|
|
36
|
+
$('t1-model').textContent = model;
|
|
37
|
+
var last = lastTriage();
|
|
38
|
+
$('t1-latency').textContent = last ? fmtMs(last.latencyMs) + ' · ' + modelName(last.model || model) : 'No evaluations yet';
|
|
39
|
+
$('t1-key').textContent = pipe.errors.triage && !t ? 'Status unavailable' : !t ? 'Checking' : t.hasApiKey ? 'Configured' : 'Not set (offline rules)';
|
|
40
|
+
var sw = $('t1-auto');
|
|
41
|
+
var on = !!(t && t.autoTriageEnabled);
|
|
42
|
+
sw.setAttribute('aria-checked', String(on));
|
|
43
|
+
sw.textContent = on ? 'ON' : 'OFF';
|
|
44
|
+
sw.disabled = !t || !!pipe.busy.triageConfig;
|
|
45
|
+
var stats = (t && t.stats) || {};
|
|
46
|
+
$('t1-evaluated').textContent = num(stats.totalEvaluated || 0);
|
|
47
|
+
$('t1-resolved').textContent = num(stats.autoResolved || 0);
|
|
48
|
+
$('t1-human').textContent = num(stats.escalatedToHuman || 0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function setTriageMenu(open) {
|
|
52
|
+
var menu = $('t1-menu');
|
|
53
|
+
if (menu.hidden === !open) return;
|
|
54
|
+
menu.hidden = !open;
|
|
55
|
+
$('t1-chip').setAttribute('aria-expanded', String(open));
|
|
56
|
+
if (!open) return;
|
|
57
|
+
renderTriageChip();
|
|
58
|
+
fetchPipeline(['triage']);
|
|
59
|
+
($('t1-auto').disabled ? menu : $('t1-auto')).focus();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function setAutoTriage(enabled) {
|
|
63
|
+
if (pipe.busy.triageConfig) return;
|
|
64
|
+
pipe.busy.triageConfig = true;
|
|
65
|
+
renderTriageChip();
|
|
66
|
+
postJson('/api/pipeline/triage/config', { autoTriageEnabled: enabled }).then(function (body) {
|
|
67
|
+
pipe.triage = Object.assign({}, pipe.triage || {}, { autoTriageEnabled: !!(body.config && body.config.autoTriageEnabled) });
|
|
68
|
+
toast(enabled ? 'Autonomous Auto-Triage on: fixes Tier 1 proves safe are applied without asking' : 'Autonomous Auto-Triage off: every fix waits for your approval', 'ok');
|
|
69
|
+
}, function (e) {
|
|
70
|
+
toast('Could not change Autonomous Auto-Triage: ' + e.message);
|
|
71
|
+
}).then(function () {
|
|
72
|
+
pipe.busy.triageConfig = false;
|
|
73
|
+
renderTriageChip();
|
|
74
|
+
if (rc.tab === 'heal') renderHeal();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Asks the strategist to assess one escalation. The server stores the verdict on the escalation record. */
|
|
79
|
+
function runTriage(escalation) {
|
|
80
|
+
if (!escalation || pipe.triageRunning[escalation.id]) return;
|
|
81
|
+
var taskId = escalation.taskId;
|
|
82
|
+
pipe.triageRunning[escalation.id] = taskId;
|
|
83
|
+
rc.heal = { taskId: taskId, busy: true, result: null };
|
|
84
|
+
renderTriageChip();
|
|
85
|
+
renderHeal();
|
|
86
|
+
refreshUi([]);
|
|
87
|
+
postJson('/api/pipeline/triage/evaluate', { escalationId: escalation.id }).then(function (body) {
|
|
88
|
+
pipe.triageLast = { latencyMs: body.latencyMs, model: body.model };
|
|
89
|
+
t1Choice.escalationId = null; // a re-run may bring new options
|
|
90
|
+
rc.heal = { taskId: taskId, busy: false, result: null, triage: body, escalation: escalation };
|
|
91
|
+
if (body.autoPatchApplied) {
|
|
92
|
+
pipe.triageRecent[taskId] = Date.now();
|
|
93
|
+
setTimeout(function () { delete pipe.triageRecent[taskId]; }, 12000);
|
|
94
|
+
toast('Tier 1 auto-resolved ' + escalation.id + ' in ' + fmtMs(body.latencyMs), 'ok');
|
|
95
|
+
} else if (body.classification === 'REQUIRE_HUMAN_DECISION') {
|
|
96
|
+
toast(escalation.id + ' needs your decision', 'ok');
|
|
97
|
+
}
|
|
98
|
+
// A resolved escalation leaves the pending list; keep its stored verdict (applied patch, unblock) on screen.
|
|
99
|
+
return api('/api/pipeline/escalations?status=all').then(function (list) {
|
|
100
|
+
(list.escalations || []).some(function (e) {
|
|
101
|
+
if (e.id !== escalation.id) return false;
|
|
102
|
+
if (rc.heal && rc.heal.triage === body) rc.heal.escalation = e;
|
|
103
|
+
return true;
|
|
104
|
+
});
|
|
105
|
+
}, function () { /* the evaluate response is enough to render */ });
|
|
106
|
+
}, function (e) {
|
|
107
|
+
rc.heal = { taskId: taskId, busy: false, result: { ok: false, message: 'Tier 1 triage failed: ' + e.message } };
|
|
108
|
+
toast('Tier 1 triage failed for ' + escalation.id + ': ' + e.message);
|
|
109
|
+
}).then(function () {
|
|
110
|
+
delete pipe.triageRunning[escalation.id];
|
|
111
|
+
renderTriageChip();
|
|
112
|
+
renderHeal();
|
|
113
|
+
refreshUi([]);
|
|
114
|
+
return fetchPipeline(['escalations', 'triage', 'status', 'tasks', 'telemetry']);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Verdict for the console task: this tab's latest evaluation first, else the one stored on the escalation. */
|
|
119
|
+
function triageFor(escalation, heal) {
|
|
120
|
+
if (heal && heal.triage) {
|
|
121
|
+
var stored = heal.escalation || escalation;
|
|
122
|
+
return { verdict: (stored && stored.triage) || heal.triage, escalation: stored };
|
|
123
|
+
}
|
|
124
|
+
if (escalation && escalation.triage) return { verdict: escalation.triage, escalation: escalation };
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function triageStrip(escalation, hasVerdict) {
|
|
129
|
+
var running = !!pipe.triageRunning[escalation.id];
|
|
130
|
+
var text = running ? 'is assessing this escalation' : hasVerdict ? 'has assessed this escalation. Run it again after the contracts change.'
|
|
131
|
+
: 'can assess this escalation: resolve a safe fix automatically or prepare a decision card for you.';
|
|
132
|
+
return '<div class="t1-strip' + (running ? ' is-triaging' : '') + '" role="status"><span>' + ICON.spark + '<strong>Tier 1 AI Strategist</strong> ' + esc(text) + '</span>' +
|
|
133
|
+
'<button class="rc-btn t1-run" type="button" data-heal="t1-run"' + (running ? ' disabled' : '') + '>' +
|
|
134
|
+
(running ? '<span class="spinner" aria-hidden="true"></span>Triaging…' : hasVerdict ? 'Re-run Triage' : 'Run Tier 1 Triage') + '</button></div>';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function triageVerdictHtml(v, escalation) {
|
|
138
|
+
var meta = modelName(v.model) + ' in ' + fmtMs(v.latencyMs);
|
|
139
|
+
if (v.classification === 'AUTO_RESOLVE' && v.autoPatchApplied) {
|
|
140
|
+
var patch = (v.resolution && v.resolution.patch) || (escalation.proposedPatch && escalation.proposedPatch.candidate);
|
|
141
|
+
var unblocked = v.unblockedTaskId || (escalation.resolution && escalation.resolution.unblockedTaskId);
|
|
142
|
+
return '<p class="t1-banner is-resolved" role="status">' + ICON.spark + esc('Auto-Resolved by Tier 1 AI Strategist (' + meta + ')') + '</p>' +
|
|
143
|
+
(patch ? '<section class="heal-section"><h4>Applied contract modification</h4><pre class="heal-patch">' + patchLine('+', patch) + '</pre></section>' : '') +
|
|
144
|
+
'<p class="heal-diag"><strong>Auto-unblocking:</strong> ' +
|
|
145
|
+
esc(unblocked ? 'Task ' + unblocked + ' is back in the queue and can be dispatched again.' : 'The task was not blocked, so nothing needed unblocking.') +
|
|
146
|
+
(v.reasoning ? ' ' + esc(v.reasoning) : '') + '</p>';
|
|
147
|
+
}
|
|
148
|
+
if (v.classification === 'AUTO_RESOLVE') {
|
|
149
|
+
var auto = !!(pipe.triage && pipe.triage.autoTriageEnabled);
|
|
150
|
+
var next = escalation.proposedPatch
|
|
151
|
+
? 'Nothing was written yet. Approve the proposal below' + (auto ? '.' : ', or turn on Autonomous Auto-Triage and run triage again.')
|
|
152
|
+
: 'No contract change is needed. Approve below to unblock the task.';
|
|
153
|
+
return '<p class="t1-banner is-safe" role="status">' + ICON.spark + esc('Tier 1 AI Strategist: safe to resolve (' + meta + ')') + '</p>' +
|
|
154
|
+
'<p class="heal-diag">' + esc((v.reasoning ? v.reasoning + ' ' : '') + next) + '</p>';
|
|
155
|
+
}
|
|
156
|
+
return humanCardHtml(v, escalation, meta);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** ui_specs.md §5.2: amber 4-part card. Options are selectable; the footer commits the choice. */
|
|
160
|
+
function humanCardHtml(v, escalation, meta) {
|
|
161
|
+
var card = v.humanCard || {};
|
|
162
|
+
var options = Array.isArray(card.options) ? card.options : [];
|
|
163
|
+
var recorded = escalation.humanDecision || null;
|
|
164
|
+
if (t1Choice.escalationId !== escalation.id) {
|
|
165
|
+
var pick = 0;
|
|
166
|
+
options.some(function (o, i) { if (o.recommended) { pick = i; return true; } return false; });
|
|
167
|
+
if (recorded) options.some(function (o, i) { if (o.id === recorded.optionId) { pick = i; return true; } return false; });
|
|
168
|
+
t1Choice = { escalationId: escalation.id, index: pick, custom: recorded && recorded.instructions ? recorded.instructions : '' };
|
|
169
|
+
}
|
|
170
|
+
var buttons = options.map(function (o, i) {
|
|
171
|
+
var label = String(o.label || 'Option ' + (i + 1));
|
|
172
|
+
var tag = o.recommended && !/recommended/i.test(label) ? ' (Recommended)' : '';
|
|
173
|
+
return '<button class="t1-opt' + (o.recommended ? ' is-recommended' : '') + '" type="button" role="radio" aria-checked="' + (t1Choice.index === i) + '"' +
|
|
174
|
+
' tabindex="' + (t1Choice.index === i ? '0' : '-1') + '" data-t1-opt="' + i + '"><b>' + esc(label + tag) + '</b><span>' + esc(o.outcome || o.description || '') + '</span></button>';
|
|
175
|
+
}).join('');
|
|
176
|
+
return '<article class="t1-card" aria-label="Human decision required">' +
|
|
177
|
+
'<div class="t1-card-head"><span class="t1-badge">Human Decision Required</span><span class="heal-tag">' + esc(escalation.id) + '</span><span class="t1-meta">' + esc(meta) + '</span></div>' +
|
|
178
|
+
'<ol class="t1-parts">' +
|
|
179
|
+
'<li><h4>What is Happening?</h4><p>' + esc(card.symptom || escalation.summary || '') + '</p></li>' +
|
|
180
|
+
'<li><h4>Why is This Happening?</h4><p>' + esc(card.rootCause || '') + '</p></li>' +
|
|
181
|
+
'<li><h4>Who & What is Affected?</h4><p>' + esc(card.blastRadius || '') + '</p></li>' +
|
|
182
|
+
'<li><h4>Actionable Options & Trade-offs</h4>' +
|
|
183
|
+
'<div class="t1-options" role="radiogroup" aria-label="Decision options">' + buttons + '</div>' +
|
|
184
|
+
'<label class="t1-custom" for="t1-custom">Custom instructions (optional, used instead of the option above)' +
|
|
185
|
+
'<textarea id="t1-custom" maxlength="900" rows="2" placeholder="Tell the agent exactly what to do instead">' + esc(t1Choice.custom) + '</textarea></label>' +
|
|
186
|
+
(recorded ? '<p class="t1-decided">Recorded from the terminal: ' + esc(recorded.label || recorded.optionId) + '</p>' : '') +
|
|
187
|
+
'</li>' +
|
|
188
|
+
'</ol>' +
|
|
189
|
+
'</article>';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function decisionActions(escalation) {
|
|
193
|
+
return '<div class="heal-actions"><button class="rc-btn reject" type="button" data-heal="t1-dismiss">Dismiss Escalation</button>' +
|
|
194
|
+
'<button class="rc-btn approve" type="button" data-heal="t1-decide">' + (escalation.proposedPatch ? 'Apply Proposal & Unblock' : 'Unblock with This Decision') + '</button></div>';
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Sends the card choice (or custom instructions) as the resolution notes the unblocked agent reads. */
|
|
198
|
+
function commitDecision(decision) {
|
|
199
|
+
var escalation = rc.taskId ? escalationFor(rc.taskId) : null;
|
|
200
|
+
var tri = triageFor(escalation, rc.heal && rc.heal.taskId === rc.taskId ? rc.heal : null);
|
|
201
|
+
if (!escalation || !tri) return;
|
|
202
|
+
var options = (tri.verdict.humanCard && tri.verdict.humanCard.options) || [];
|
|
203
|
+
var chosen = options[t1Choice.index];
|
|
204
|
+
var custom = String(t1Choice.custom || '').trim();
|
|
205
|
+
var notes = custom ? 'Product owner instructions: ' + custom
|
|
206
|
+
: chosen ? 'Product owner chose "' + (chosen.label || chosen.id) + '": ' + (chosen.outcome || chosen.description || '') : '';
|
|
207
|
+
resolveEscalation(decision, notes.slice(0, 1000), decision === 'approve' ? 't1-decide' : 't1-dismiss');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const consoleCss: string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Runner console drawer and proposal review styles.
|
|
2
|
+
export const consoleCss = String.raw `/* Live runner console drawer */
|
|
3
|
+
body.has-console { padding-bottom: min(58vh, 520px); }
|
|
4
|
+
body.has-console-min { padding-bottom: 56px; }
|
|
5
|
+
#runner-console-drawer { position: fixed; inset: auto 0 0 var(--sidebar-w); z-index: 60; display: flex; flex-direction: column; max-height: min(58vh, 520px); background: var(--term-bg); color: var(--term-text); border-top: 1px solid var(--chip-border); box-shadow: var(--shadow-float); animation: rc-slide-up .28s cubic-bezier(.2, .8, .2, 1); }
|
|
6
|
+
#runner-console-drawer[hidden] { display: none; }
|
|
7
|
+
#runner-console-drawer.is-min .rc-body, #runner-console-drawer.is-min .rc-foot { display: none; }
|
|
8
|
+
@keyframes rc-slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
|
|
9
|
+
.rc-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 14px; border-bottom: 1px solid var(--term-line); }
|
|
10
|
+
.rc-task { font-family: var(--mono); font-size: 12.5px; font-weight: 600; }
|
|
11
|
+
.rc-title { font-size: 12.5px; color: var(--term-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 34ch; }
|
|
12
|
+
.rc-steps { display: flex; align-items: center; gap: 6px; margin: 0 0 0 auto; padding: 0; list-style: none; }
|
|
13
|
+
.rc-step { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; font-size: 11px; color: var(--term-muted); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
14
|
+
.rc-step.is-done { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 55%, transparent); }
|
|
15
|
+
.rc-step.is-active { color: var(--term-text); background: color-mix(in srgb, var(--primary) 32%, transparent); border-color: var(--primary); }
|
|
16
|
+
.rc-step.is-failed { color: var(--term-text); background: color-mix(in srgb, var(--danger) 32%, transparent); border-color: var(--danger); }
|
|
17
|
+
.rc-controls { display: flex; gap: 6px; flex: none; }
|
|
18
|
+
.rc-btn { padding: 5px 9px; font: 500 11px/1 var(--font); color: var(--term-text); background: transparent; border: 1px solid var(--term-line); border-radius: var(--r-control); cursor: pointer; }
|
|
19
|
+
.rc-btn:hover { background: color-mix(in srgb, var(--term-muted) 22%, transparent); }
|
|
20
|
+
.rc-btn:disabled { opacity: .45; cursor: not-allowed; }
|
|
21
|
+
.rc-btn[aria-pressed="true"] { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 34%, transparent); }
|
|
22
|
+
.rc-btn.danger { color: var(--term-text); border-color: var(--danger); }
|
|
23
|
+
.rc-btn.danger:hover { background: color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
24
|
+
.rc-btn:focus-visible { outline: 2px solid var(--term-text); outline-offset: 2px; }
|
|
25
|
+
.rc-body { flex: 1 1 auto; min-height: 120px; margin: 0; padding: 10px 14px; overflow: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
26
|
+
.rc-body:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
27
|
+
.rc-empty { color: var(--term-muted); }
|
|
28
|
+
.rc-fg-muted { color: var(--term-muted); }
|
|
29
|
+
.rc-fg-warn { color: var(--warn); }
|
|
30
|
+
.rc-fg-ok { color: var(--ok); }
|
|
31
|
+
.rc-fg-info { color: var(--accent); }
|
|
32
|
+
.rc-fg-danger { color: color-mix(in srgb, var(--danger) 55%, #fff); }
|
|
33
|
+
.rc-bold { font-weight: 700; }
|
|
34
|
+
.rc-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 7px 14px; font-size: 11.5px; color: var(--term-muted); border-top: 1px solid var(--term-line); }
|
|
35
|
+
.rc-foot strong { font-family: var(--mono); font-weight: 600; color: var(--term-text); }
|
|
36
|
+
#runner-console-drawer.is-min .rc-tabs { display: none; }
|
|
37
|
+
.rc-tabs { display: flex; gap: 2px; padding: 0 14px; border-bottom: 1px solid var(--term-line); }
|
|
38
|
+
.rc-tab { display: inline-flex; align-items: center; gap: 6px; padding: 8px 10px; font: 500 12px/1 var(--font); color: var(--term-muted); background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; }
|
|
39
|
+
.rc-tab:hover { color: var(--term-text); }
|
|
40
|
+
.rc-tab[aria-selected="true"] { color: var(--term-text); border-bottom-color: var(--primary); }
|
|
41
|
+
.rc-tab:focus-visible { outline: 2px solid var(--term-text); outline-offset: -2px; }
|
|
42
|
+
.rc-tab .rc-count { min-width: 18px; padding: 0 5px; font-family: var(--mono); font-size: 10.5px; line-height: 16px; text-align: center; color: var(--term-text); background: color-mix(in srgb, var(--term-muted) 22%, transparent); border-radius: var(--r-control); }
|
|
43
|
+
.rc-diff { flex: 1 1 auto; min-height: 120px; display: flex; flex-direction: column; overflow: hidden; }
|
|
44
|
+
#runner-console-drawer.is-min .rc-diff { display: none; }
|
|
45
|
+
.rc-diff-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 14px; font-size: 11.5px; color: var(--term-muted); border-bottom: 1px solid var(--term-line); }
|
|
46
|
+
.rc-diff-bar code { color: var(--term-text); font-family: var(--mono); }
|
|
47
|
+
.rc-diff-bar .rc-btn { margin-left: auto; }
|
|
48
|
+
.rc-files { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 8px 14px 0; list-style: none; }
|
|
49
|
+
.rc-files li { padding: 1px 7px; font-family: var(--mono); font-size: 11px; color: var(--term-text); border: 1px solid var(--term-line); border-radius: var(--r-control); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
50
|
+
.rc-diff-body { flex: 1 1 auto; margin: 0; padding: 10px 14px; overflow: auto; font-family: var(--mono); font-size: 12px; line-height: 1.5; white-space: pre; }
|
|
51
|
+
.rc-diff-body:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
52
|
+
/* Console tab 3: self-healing proposal review (dark drawer surface). */
|
|
53
|
+
.rc-tab .rc-count.is-proposal { color: #fff; background: var(--proposal); }
|
|
54
|
+
.rc-heal { flex: 1 1 auto; min-height: 120px; overflow: auto; padding: 12px 14px 14px; font-size: 13px; line-height: 1.5; }
|
|
55
|
+
#runner-console-drawer.is-min .rc-heal { display: none; }
|
|
56
|
+
.rc-heal:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
57
|
+
.heal-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
|
|
58
|
+
.heal-head h3 { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--term-text); }
|
|
59
|
+
.heal-tag { font: 500 11px/18px var(--mono); padding: 0 7px; color: var(--term-text); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
60
|
+
.heal-verdict { display: inline-flex; align-items: center; gap: 5px; font: 600 11.5px/20px var(--font); padding: 0 8px; border-radius: var(--r-control); }
|
|
61
|
+
.heal-verdict.pass { color: var(--ok); background: color-mix(in srgb, var(--ok) 16%, transparent); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent); }
|
|
62
|
+
.heal-verdict.fail { color: color-mix(in srgb, var(--danger) 55%, #fff); background: color-mix(in srgb, var(--danger) 18%, transparent); border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
63
|
+
.heal-diag { margin: 0 0 10px; color: var(--term-muted); overflow-wrap: anywhere; }
|
|
64
|
+
.heal-diag strong { color: var(--term-text); font-weight: 600; }
|
|
65
|
+
.heal-grid { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 12px; }
|
|
66
|
+
.heal-section h4 { margin: 0 0 6px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--term-muted); }
|
|
67
|
+
.heal-patch { margin: 0; padding: 8px 10px; font-family: var(--mono); font-size: 12px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; background: rgb(148 163 184 / 0.08); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
68
|
+
.heal-checks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
|
|
69
|
+
.heal-checks li { display: flex; gap: 7px; align-items: flex-start; color: var(--term-muted); font-size: 12.5px; }
|
|
70
|
+
.heal-checks li b { color: var(--term-text); font-family: var(--mono); font-weight: 500; }
|
|
71
|
+
.heal-checks .ok { color: var(--ok); }
|
|
72
|
+
.heal-checks .bad { color: color-mix(in srgb, var(--danger) 55%, #fff); }
|
|
73
|
+
/* Pinned to the drawer's bottom edge so the decision never needs a scroll. */
|
|
74
|
+
.heal-actions { position: sticky; bottom: -14px; display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; margin: 12px -14px -14px; padding: 10px 14px; background: var(--term-bg); border-top: 1px solid var(--term-line); }
|
|
75
|
+
.rc-btn.approve { color: #fff; background: var(--success); border-color: var(--success); }
|
|
76
|
+
.rc-btn.approve:hover:not(:disabled) { background: color-mix(in srgb, var(--success) 88%, #000); }
|
|
77
|
+
.rc-btn.reject { color: color-mix(in srgb, var(--danger) 55%, #fff); border-color: color-mix(in srgb, var(--danger) 50%, transparent); }
|
|
78
|
+
.rc-btn.reject:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 16%, transparent); }
|
|
79
|
+
.heal-result { margin: 0 0 10px; padding: 8px 10px; color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent); border-radius: var(--r-control); }
|
|
80
|
+
.heal-result.is-error { color: color-mix(in srgb, var(--danger) 55%, #fff); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
81
|
+
.heal-skel { height: 12px; margin: 8px 0; border-radius: 4px; background: var(--term-line); animation: blink 1.4s ease-in-out infinite; }
|
|
82
|
+
@media (max-width: 768px) { .heal-grid { grid-template-columns: 1fr; } }
|
|
83
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const dialogsCss: string;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Toasts, dialogs, dispatch modal and small shared widgets.
|
|
2
|
+
export const dialogsCss = String.raw `/* Toasts */
|
|
3
|
+
/* Bottom-right so notifications never cover the sticky header and navigation. */
|
|
4
|
+
.toast-host { position: fixed; right: 16px; bottom: 16px; z-index: 100; display: flex; flex-direction: column; gap: 8px; width: min(440px, calc(100vw - 32px)); pointer-events: none; }
|
|
5
|
+
.toast { pointer-events: auto; display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; font-size: 13.5px; background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--danger); border-radius: var(--r-card); box-shadow: var(--shadow-float); animation: toast-in .18s ease-out; }
|
|
6
|
+
.toast.ok { border-left-color: var(--success); }
|
|
7
|
+
.toast .t-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
8
|
+
.toast .t-hint { color: var(--muted); font-size: 12.5px; }
|
|
9
|
+
.toast button { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 16px; line-height: 1; }
|
|
10
|
+
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }
|
|
11
|
+
|
|
12
|
+
/* Dialogs */
|
|
13
|
+
dialog { border: none; padding: 0; background: transparent; color: var(--text); width: min(640px, calc(100vw - 32px)); max-height: calc(100vh - 32px); }
|
|
14
|
+
dialog.narrow { width: min(460px, calc(100vw - 32px)); }
|
|
15
|
+
dialog::backdrop { background: rgb(10 10 20 / 0.4); backdrop-filter: blur(2px); }
|
|
16
|
+
.modal { padding: 22px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card); box-shadow: var(--shadow-float); }
|
|
17
|
+
.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; }
|
|
18
|
+
.modal .lead { color: var(--muted); margin: 0 0 16px; font-size: 14px; line-height: 1.55; }
|
|
19
|
+
.field { margin-bottom: 16px; }
|
|
20
|
+
.field label { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13.5px; margin-bottom: 6px; }
|
|
21
|
+
.field-row { display: flex; gap: 8px; }
|
|
22
|
+
.field-row .input { flex: 1; font-family: var(--mono); font-size: 12.5px; min-width: 0; }
|
|
23
|
+
.field-row + .field-row { margin-top: 8px; }
|
|
24
|
+
.field-row select.input { font-family: var(--font); }
|
|
25
|
+
.param-grid { display: grid; grid-template-columns: 140px 1fr 96px; gap: 8px; margin-top: 8px; }
|
|
26
|
+
.param-grid .input { font-family: var(--mono); font-size: 12.5px; min-width: 0; }
|
|
27
|
+
.param-grid select.input { font-family: var(--font); }
|
|
28
|
+
.param-grid .span-2 { grid-column: span 2; }
|
|
29
|
+
.field .current { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-size: 12.5px; color: var(--muted); min-width: 0; }
|
|
30
|
+
.field .current code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
31
|
+
.field-error { margin: 6px 0 0; font-size: 13px; color: var(--danger); }
|
|
32
|
+
.result { margin-top: 6px; font-size: 13px; }
|
|
33
|
+
.result.ok { color: var(--success); } .result.err { color: var(--danger); }
|
|
34
|
+
.modal-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
|
|
35
|
+
.modal-prod-guard { border-color: var(--danger-line); }
|
|
36
|
+
.challenge-badge { display: inline-flex; align-items: center; gap: 6px; padding: 1px 8px; border-radius: var(--r-control); font-size: 11px; font-weight: 700; color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger-line); margin-bottom: 12px; }
|
|
37
|
+
.challenge-box { padding: 14px; border-radius: var(--r-control); border: 1px solid var(--danger-line); background: var(--danger-bg); margin: 12px 0; }
|
|
38
|
+
.challenge-box p { margin: 0 0 8px; font-size: 13.5px; line-height: 1.5; }
|
|
39
|
+
.challenge-box code { color: var(--danger); font-weight: 700; font-size: 13px; }
|
|
40
|
+
.record-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; max-height: 60vh; overflow-y: auto; padding-right: 4px; margin-bottom: 16px; }
|
|
41
|
+
.record-form-grid .field-full { grid-column: 1 / -1; }
|
|
42
|
+
.record-form-grid label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 4px; color: var(--muted); }
|
|
43
|
+
.record-form-grid label b { color: var(--text); font-family: var(--mono); }
|
|
44
|
+
.record-form-grid .input { width: 100%; }
|
|
45
|
+
.record-form-grid textarea.input { min-height: 64px; font-family: var(--mono); font-size: 12px; }
|
|
46
|
+
|
|
47
|
+
/* Task chips used by the dispatch dialog */
|
|
48
|
+
.tcard-id { display: inline-flex; align-items: center; gap: 5px; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
49
|
+
.file-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px; }
|
|
50
|
+
.file { max-width: 100%; padding: 1px 7px; font-family: var(--mono); font-size: 11.5px; background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
51
|
+
.cmd { flex: 1; min-width: 0; font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
52
|
+
.cmd-label { color: var(--text); font-weight: 600; font-size: 12px; }
|
|
53
|
+
|
|
54
|
+
/* Intelligent dispatch modal */
|
|
55
|
+
.dispatch-task { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; margin-bottom: 16px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-control); }
|
|
56
|
+
.dispatch-task-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
|
|
57
|
+
.dispatch-task h3 { margin: 0; font-size: 14.5px; font-weight: 600; line-height: 1.45; }
|
|
58
|
+
.dispatch-task .cmd { flex: none; white-space: normal; overflow-wrap: anywhere; }
|
|
59
|
+
textarea.cmd-preview { min-height: 92px; font-family: var(--mono); font-size: 12px; background: var(--bg); }
|
|
60
|
+
.field-hint { margin: 6px 0 0; font-size: 12.5px; color: var(--muted); }
|
|
61
|
+
.switches { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
|
|
62
|
+
.switch { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
|
|
63
|
+
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
|
|
64
|
+
.switch-track { position: relative; flex: none; width: 32px; height: 18px; margin-top: 1px; background: var(--chip-border); border-radius: 999px; transition: background .15s; }
|
|
65
|
+
.switch-track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; background: var(--surface); border-radius: 50%; box-shadow: var(--shadow); transition: transform .15s; }
|
|
66
|
+
.switch input:checked + .switch-track { background: var(--primary); }
|
|
67
|
+
.switch input:checked + .switch-track::after { transform: translateX(14px); }
|
|
68
|
+
.switch input:focus-visible + .switch-track { outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
69
|
+
.switch input:disabled + .switch-track { opacity: .45; }
|
|
70
|
+
/* Dual-mode dispatch: engine cards + thinking budget chips (radio groups, keyboard-native). */
|
|
71
|
+
.choice-group { margin: 0 0 16px; padding: 0; border: none; min-width: 0; }
|
|
72
|
+
.choice-group > legend { padding: 0; margin-bottom: 8px; font-size: 13px; font-weight: 600; }
|
|
73
|
+
.engine-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
74
|
+
.engine-option { position: relative; display: flex; gap: 10px; align-items: flex-start; padding: 11px 12px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-control); cursor: pointer; transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); }
|
|
75
|
+
.engine-option:hover { border-color: var(--chip-border); }
|
|
76
|
+
.engine-option input, .budget-chip input { position: absolute; opacity: 0; width: 1px; height: 1px; }
|
|
77
|
+
.engine-option .icon { flex: none; margin-top: 2px; color: var(--muted); }
|
|
78
|
+
.engine-option b { display: block; font-size: 13.5px; font-weight: 600; }
|
|
79
|
+
.engine-option span span { display: block; font-size: 12.5px; color: var(--muted); line-height: 1.45; }
|
|
80
|
+
.engine-option:has(input:checked) { border-color: var(--primary); background: var(--primary-tint); box-shadow: inset 0 0 0 1px var(--primary); }
|
|
81
|
+
.engine-option:has(input:checked) .icon { color: var(--primary); }
|
|
82
|
+
.engine-option:has(input:focus-visible), .budget-chip:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
83
|
+
.budget-chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
84
|
+
.budget-chip { position: relative; display: inline-flex; align-items: center; min-height: 32px; padding: 0 11px; font-size: 13px; background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); cursor: pointer; transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); }
|
|
85
|
+
.budget-chip small { margin-left: 5px; font-family: var(--mono); font-size: 11.5px; color: var(--muted); }
|
|
86
|
+
.budget-chip:has(input:checked) { color: var(--primary); background: var(--primary-tint); border-color: var(--primary); }
|
|
87
|
+
.budget-chip:has(input:checked) small { color: var(--primary); }
|
|
88
|
+
@media (max-width: 768px) { .engine-options { grid-template-columns: 1fr; } }
|
|
89
|
+
/* Grounded spend KPI (ui_specs.md View 1, card 3). */
|
|
90
|
+
.cache-pill { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 1px; padding: 5px 9px; font-size: 12.5px; line-height: 1.4; color: var(--success); background: var(--success-bg); border: 1px solid var(--success-line); border-radius: var(--r-control); font-variant-numeric: tabular-nums; }
|
|
91
|
+
.cache-pill .label { white-space: nowrap; }
|
|
92
|
+
.cache-pill b { font-weight: 650; }
|
|
93
|
+
/* The savings line wraps under the rate instead of being clipped in a narrow card. */
|
|
94
|
+
.cache-pill .save { flex-basis: 100%; color: var(--muted); }
|
|
95
|
+
.tel-chips { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
|
|
96
|
+
.tel-chips li { display: flex; flex-direction: column; gap: 1px; min-width: 0; padding: 5px 8px; background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); }
|
|
97
|
+
.tel-chips span { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
98
|
+
.tel-chips b { font-family: var(--mono); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
99
|
+
.kpi-note { margin: 0; font-size: 13px; color: var(--muted); }
|
|
100
|
+
.kpi-note .btn { margin-left: 6px; }
|
|
101
|
+
.dot-proposal { background: var(--proposal); }
|
|
102
|
+
/* Self-healing proposals on the kanban and in the sidebar. */
|
|
103
|
+
.badge-proposal { color: var(--proposal); background: var(--proposal-bg); border-color: var(--proposal-line); }
|
|
104
|
+
.nav-tab .count.count-proposal { color: var(--proposal); background: var(--proposal-bg); border-color: var(--proposal-line); }
|
|
105
|
+
.tcard.has-proposal { border-color: var(--proposal-line); box-shadow: inset 3px 0 0 var(--proposal), var(--shadow); }
|
|
106
|
+
.proposal-banner { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 11px; font: 600 13px/1.4 var(--font); text-align: left; color: var(--proposal); background: var(--proposal-bg); border: 1px solid var(--proposal-line); border-radius: var(--r-control); cursor: pointer; transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); }
|
|
107
|
+
.proposal-banner:hover { border-color: var(--proposal); }
|
|
108
|
+
.proposal-banner:active { transform: scale(0.98); }
|
|
109
|
+
.proposal-banner:focus-visible { outline: 2px solid var(--proposal); outline-offset: 2px; }
|
|
110
|
+
.proposal-banner .icon { flex: none; }
|
|
111
|
+
.switch input:disabled ~ .switch-text { opacity: .55; }
|
|
112
|
+
.switch-text { display: flex; flex-direction: column; font-size: 13.5px; }
|
|
113
|
+
.switch-text b { font-weight: 600; }
|
|
114
|
+
.switch-text span { font-size: 12.5px; color: var(--muted); }
|
|
115
|
+
kbd { padding: 0 5px; font-family: var(--mono); font-size: 11px; color: var(--muted); background: var(--chip); border: 1px solid var(--chip-border); border-radius: 4px; }
|
|
116
|
+
.btn.primary kbd { color: var(--accent-fg); background: transparent; border-color: color-mix(in srgb, var(--accent-fg) 45%, transparent); }
|
|
117
|
+
|
|
118
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const responsiveCss: string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Responsive rules for the kept pages and dialogs.
|
|
2
|
+
export const responsiveCss = String.raw `/* Responsive */
|
|
3
|
+
@media (max-width: 900px) {
|
|
4
|
+
#runner-console-drawer { inset: auto 0 0 0; }
|
|
5
|
+
.panes { grid-template-columns: 1fr; }
|
|
6
|
+
.summary-banner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
7
|
+
.hero { grid-template-columns: 1fr; }
|
|
8
|
+
.hero-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
9
|
+
}
|
|
10
|
+
@media (max-width: 820px) {
|
|
11
|
+
table.grid thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
|
|
12
|
+
table.grid, table.grid tbody, table.grid tr, table.grid td { display: block; }
|
|
13
|
+
table.grid tr { padding: 10px 16px; border-bottom: 1px solid var(--border); }
|
|
14
|
+
table.grid tbody tr:last-child { border-bottom: none; }
|
|
15
|
+
table.grid td { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 0; border: none; text-align: right; min-width: 0; }
|
|
16
|
+
table.grid td::before { content: attr(data-label); flex: none; font-size: 12px; color: var(--muted); text-align: left; }
|
|
17
|
+
table.grid tbody tr:hover td { background: none; }
|
|
18
|
+
.path, .cell-sub { max-width: 58vw; }
|
|
19
|
+
}
|
|
20
|
+
@media (max-width: 640px) {
|
|
21
|
+
.panel-actions, .panel-actions input.input, .panel-actions select.input { width: 100%; max-width: none; }
|
|
22
|
+
.param-grid { grid-template-columns: 1fr; }
|
|
23
|
+
.param-grid .span-2 { grid-column: auto; }
|
|
24
|
+
.record-form-grid { grid-template-columns: 1fr; }
|
|
25
|
+
.diagnostic-banner { flex-direction: column; align-items: flex-start; }
|
|
26
|
+
}
|
|
27
|
+
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
|
|
28
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const shellCss: string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// App shell: sidebar, top bar, page frame, status helpers, detail panel, palette.
|
|
2
|
+
export const shellCss = String.raw `/* Layout */
|
|
3
|
+
.app { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); min-height: 100vh; }
|
|
4
|
+
.side { border-right: 1px solid var(--line); background: var(--surface); padding: 16px 12px; display: flex; flex-direction: column; gap: 20px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
|
|
5
|
+
.brand { display: flex; align-items: center; gap: 10px; padding: 0 6px; }
|
|
6
|
+
.logo { width: 26px; height: 26px; border-radius: 7px; background: var(--accent); color: var(--accent-fg); display: grid; place-items: center; font-weight: 700; font-size: 14px; flex: none; }
|
|
7
|
+
.brand b { font-weight: 600; white-space: nowrap; }
|
|
8
|
+
.brand .ver { margin-left: auto; font: 11px var(--mono); color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
9
|
+
.nav { display: flex; flex-direction: column; gap: 14px; }
|
|
10
|
+
.nav-group { display: flex; flex-direction: column; gap: 2px; }
|
|
11
|
+
.nav-glabel { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); padding: 0 8px 4px; }
|
|
12
|
+
.nav-item { display: flex; align-items: center; gap: 10px; min-height: 32px; padding: 7px 8px; border-radius: 7px; border: 0; background: none; text-align: left; color: var(--fg-2); width: 100%; cursor: pointer; transition: background .15s, color .15s; }
|
|
13
|
+
.nav-item svg { width: 16px; height: 16px; flex: none; }
|
|
14
|
+
.nav-item:hover { background: var(--surface-2); color: var(--fg); }
|
|
15
|
+
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
|
|
16
|
+
.nav-badge { margin-left: auto; font: 500 11px var(--font); font-variant-numeric: tabular-nums; min-width: 20px; padding: 1px 6px; border-radius: 999px; background: var(--surface-2); color: var(--fg-2); text-align: center; }
|
|
17
|
+
.nav-badge.warn { background: var(--warn-soft); color: var(--warn); }
|
|
18
|
+
.nav-badge.run { background: var(--run-soft); color: var(--run); }
|
|
19
|
+
.side-foot { margin-top: auto; font-size: 12px; color: var(--fg-3); padding: 0 8px; display: flex; flex-direction: column; gap: 4px; }
|
|
20
|
+
.side-foot > div { display: flex; flex-direction: column; gap: 4px; }
|
|
21
|
+
.side-foot .mono { color: var(--fg-2); font-size: 11px; word-break: break-all; }
|
|
22
|
+
.foot-project { color: var(--fg); font-weight: 500; }
|
|
23
|
+
.main { min-width: 0; display: flex; flex-direction: column; }
|
|
24
|
+
.top { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 20; background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 24px; }
|
|
25
|
+
.crumb { color: var(--fg-3); font-size: 13px; }
|
|
26
|
+
.crumb b { color: var(--fg); font-weight: 500; }
|
|
27
|
+
.top-right { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
28
|
+
.btn.ghost { background: none; border-color: transparent; color: var(--fg-2); box-shadow: none; }
|
|
29
|
+
.btn.ghost:hover { background: var(--surface-2); }
|
|
30
|
+
.btn svg { width: 14px; height: 14px; }
|
|
31
|
+
.kbd { font: 11px var(--mono); padding: 0 5px; border: 1px solid var(--line); border-radius: 4px; color: var(--fg-3); }
|
|
32
|
+
.live { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--fg-2); }
|
|
33
|
+
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--fg-3); }
|
|
34
|
+
.live[data-state="live"] .live-dot { background: var(--ok); }
|
|
35
|
+
.live-dot.flash { animation: live-flash .9s ease-out; }
|
|
36
|
+
@keyframes live-flash { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 65%, transparent); } 100% { box-shadow: 0 0 0 9px transparent; } }
|
|
37
|
+
@keyframes blink { 50% { opacity: .35; } }
|
|
38
|
+
.banner { margin: 0; padding: 8px 24px; background: var(--warn-soft); color: var(--warn); font-size: 13px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
39
|
+
.page { padding: 28px 24px 64px; max-width: 1240px; width: 100%; margin: 0 auto; }
|
|
40
|
+
.page:focus { outline: none; }
|
|
41
|
+
.page-view { min-width: 0; display: flex; flex-direction: column; gap: 22px; }
|
|
42
|
+
#panel-worktrees, #panel-benchmarks, #panel-database { display: block; }
|
|
43
|
+
|
|
44
|
+
/* Shared helpers for pages */
|
|
45
|
+
.num { font-variant-numeric: tabular-nums; }
|
|
46
|
+
.faint { color: var(--fg-3); }
|
|
47
|
+
.st { display: inline-grid; place-items: center; width: 16px; height: 16px; flex: none; }
|
|
48
|
+
.st svg { width: 16px; height: 16px; }
|
|
49
|
+
.st.completed { color: var(--ok); } .st.blocked { color: var(--bad); } .st.pending { color: var(--fg-3); } .st.in_progress { color: var(--run); }
|
|
50
|
+
.pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--run); box-shadow: 0 0 0 0 color-mix(in srgb, var(--run) 50%, transparent); animation: pulse 1.6s infinite; }
|
|
51
|
+
@keyframes pulse { 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
|
|
52
|
+
.agent { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--fg-2); white-space: nowrap; }
|
|
53
|
+
.agent i { width: 7px; height: 7px; border-radius: 2px; background: var(--c, var(--fg-3)); }
|
|
54
|
+
.status-pill { font-size: 11.5px; font-weight: 500; padding: 1px 8px; border-radius: 999px; white-space: nowrap; }
|
|
55
|
+
.status-pill.completed { background: var(--ok-soft); color: var(--ok); } .status-pill.in_progress { background: var(--run-soft); color: var(--run); }
|
|
56
|
+
.status-pill.blocked { background: var(--bad-soft); color: var(--bad); } .status-pill.pending { background: var(--surface-2); color: var(--fg-2); }
|
|
57
|
+
.sel { height: 30px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface); padding: 0 28px 0 10px; max-width: 100%; }
|
|
58
|
+
.row-btn { display: grid; grid-template-columns: 18px 88px minmax(0, 1fr) auto auto; gap: 12px; align-items: center; min-height: 32px; padding: 9px 16px; border: 0; background: none; text-align: left; border-top: 1px solid var(--line); width: 100%; cursor: pointer; }
|
|
59
|
+
.row-btn:hover { background: var(--surface-2); }
|
|
60
|
+
.row-btn .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
61
|
+
.ui-empty { padding: 36px 16px; text-align: center; color: var(--fg-2); }
|
|
62
|
+
.ui-empty b { display: block; color: var(--fg); font-weight: 600; margin-bottom: 4px; }
|
|
63
|
+
.skel { height: 14px; border-radius: 6px; margin-bottom: 10px; background: var(--surface-2); }
|
|
64
|
+
.skel-head .skel:first-child { height: 22px; }
|
|
65
|
+
.skel-block { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 16px; }
|
|
66
|
+
|
|
67
|
+
/* Detail panel */
|
|
68
|
+
.scrim { position: fixed; inset: 0; background: rgba(10,10,20,.25); z-index: 40; }
|
|
69
|
+
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(440px, 100%); background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow); z-index: 41; display: flex; flex-direction: column; padding-top: env(safe-area-inset-top, 0px); }
|
|
70
|
+
.drawer:focus { outline: none; }
|
|
71
|
+
.drawer-head { display: flex; align-items: center; gap: 8px; padding: 14px 18px; border-bottom: 1px solid var(--line); }
|
|
72
|
+
.drawer-head .close { margin-left: auto; }
|
|
73
|
+
.drawer-body { padding: 18px; overflow: auto; display: flex; flex-direction: column; gap: 18px; padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px)); }
|
|
74
|
+
.drawer h3 { margin: 0; font-size: 17px; font-weight: 600; text-wrap: balance; }
|
|
75
|
+
.drawer .kv { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 8px 12px; font-size: 13px; margin: 0; }
|
|
76
|
+
.drawer .kv dt { color: var(--fg-3); }
|
|
77
|
+
.drawer .kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
|
78
|
+
.dlabel { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); margin-bottom: 6px; }
|
|
79
|
+
.drawer .chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
80
|
+
.drawer .chip { display: inline-flex; align-items: center; gap: 6px; min-height: 26px; padding: 3px 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface); font-size: 12px; font-family: var(--font); }
|
|
81
|
+
.drawer .chip.mono { font-family: var(--mono); }
|
|
82
|
+
.drawer button.chip { cursor: pointer; }
|
|
83
|
+
.drawer button.chip:hover { border-color: var(--line-2); }
|
|
84
|
+
.drawer .code { font: 12px var(--mono); background: var(--surface-2); border-radius: 8px; padding: 10px 12px; overflow-x: auto; white-space: pre; }
|
|
85
|
+
.drawer .code.wrap { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
86
|
+
.drawer .reason { background: var(--bad-soft); color: var(--fg); border-radius: 8px; padding: 10px 12px; font-size: 13px; }
|
|
87
|
+
|
|
88
|
+
/* Command palette */
|
|
89
|
+
.pal-wrap { position: fixed; inset: 0; z-index: 50; display: flex; justify-content: center; align-items: flex-start; padding: 12vh 16px 16px; background: rgba(10,10,20,.3); }
|
|
90
|
+
.pal { width: min(620px, 100%); background: var(--surface); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); overflow: hidden; }
|
|
91
|
+
.pal input { width: 100%; border: 0; border-bottom: 1px solid var(--line); background: none; padding: 14px 16px; font-size: 15px; outline: none; }
|
|
92
|
+
.pal ul { list-style: none; margin: 0; padding: 6px; max-height: 50vh; overflow: auto; }
|
|
93
|
+
.pal li { display: grid; grid-template-columns: 18px 150px minmax(0, 1fr) auto; gap: 10px; align-items: center; min-height: 32px; padding: 8px 10px; border-radius: 7px; cursor: pointer; }
|
|
94
|
+
.pal li[aria-selected="true"] { background: var(--accent-soft); }
|
|
95
|
+
.pal li .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
96
|
+
.pal li.pal-none { display: block; cursor: default; }
|
|
97
|
+
.pal-ico svg { width: 16px; height: 16px; display: block; }
|
|
98
|
+
.pal .hint { padding: 8px 16px; border-top: 1px solid var(--line); font-size: 12px; color: var(--fg-3); display: flex; gap: 14px; }
|
|
99
|
+
.toast-host { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
|
|
100
|
+
|
|
101
|
+
@media (max-width: 760px) {
|
|
102
|
+
.app { grid-template-columns: minmax(0, 1fr); }
|
|
103
|
+
.side { position: static; height: auto; flex-direction: row; align-items: center; padding: 10px 16px; gap: 12px; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }
|
|
104
|
+
.side-foot, .brand .ver, .brand b, .nav-glabel { display: none; }
|
|
105
|
+
.nav { flex-direction: row; gap: 2px; }
|
|
106
|
+
.nav-group { flex-direction: row; }
|
|
107
|
+
.nav-item { width: auto; white-space: nowrap; }
|
|
108
|
+
.top, .page { padding-left: 16px; padding-right: 16px; }
|
|
109
|
+
.banner { padding-inline: 16px; }
|
|
110
|
+
.row-btn { grid-template-columns: 18px minmax(0, 1fr) auto; }
|
|
111
|
+
.hide-sm { display: none; }
|
|
112
|
+
.pal li { grid-template-columns: 18px minmax(0, 1fr); }
|
|
113
|
+
.drawer { width: 100%; }
|
|
114
|
+
#runner-console-drawer { inset: auto 0 0 0; }
|
|
115
|
+
}
|
|
116
|
+
@media (prefers-reduced-motion: reduce) { .pulse, .live-dot.flash { animation: none; } * { transition: none !important; } }
|
|
117
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const strategistCss: string;
|