@njeybe/nativ 2.6.0 → 2.8.0
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 +50 -0
- package/README.md +71 -1
- package/dist/commands/design-check.d.ts +4 -0
- package/dist/commands/design-check.js +76 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +53 -1
- package/dist/commands/update.js +46 -0
- package/dist/core/design-rules.d.ts +23 -0
- package/dist/core/design-rules.js +115 -0
- package/dist/core/harness-integrity.js +26 -7
- package/dist/core/setup/pm-playbook.d.ts +1 -1
- package/dist/core/setup/pm-playbook.js +1 -1
- package/dist/index.js +11 -0
- package/dist/server/studio-ui/pages/benchmarks/script.js +9 -8
- package/dist/server/studio-ui/pages/benchmarks/styles.js +11 -6
- package/dist/server/studio-ui/pages/database/browser.js +2 -2
- package/dist/server/studio-ui/pages/database/connection.js +6 -5
- package/dist/server/studio-ui/pages/database/data-shell.js +12 -17
- package/dist/server/studio-ui/pages/database/drift.js +2 -2
- package/dist/server/studio-ui/pages/database/events.js +1 -2
- package/dist/server/studio-ui/pages/database/explorer.js +6 -6
- package/dist/server/studio-ui/pages/database/styles.js +5 -5
- package/dist/server/studio-ui/pages/flow/layout.js +1 -1
- package/dist/server/studio-ui/pages/flow/styles.js +4 -4
- package/dist/server/studio-ui/pages/flow/timeline-view.js +1 -1
- package/dist/server/studio-ui/pages/home/script.js +108 -92
- package/dist/server/studio-ui/pages/home/styles.js +29 -45
- package/dist/server/studio-ui/pages/tasks/script.js +146 -14
- package/dist/server/studio-ui/pages/tasks/styles.js +63 -6
- package/dist/server/studio-ui/pages/team/script.js +69 -53
- package/dist/server/studio-ui/pages/team/styles.js +20 -20
- package/dist/server/studio-ui/pages/worktrees/script.js +47 -35
- package/dist/server/studio-ui/pages/worktrees/styles.js +12 -10
- package/dist/server/studio-ui/shell/brand.d.ts +4 -0
- package/dist/server/studio-ui/shell/brand.js +16 -0
- package/dist/server/studio-ui/shell/console.js +71 -6
- package/dist/server/studio-ui/shell/core.js +8 -8
- package/dist/server/studio-ui/shell/detail-view.js +4 -4
- package/dist/server/studio-ui/shell/dispatch.js +23 -4
- package/dist/server/studio-ui/shell/events-tools.js +16 -1
- package/dist/server/studio-ui/shell/format.js +36 -8
- package/dist/server/studio-ui/shell/icons.js +23 -15
- package/dist/server/studio-ui/shell/markup-head.js +11 -6
- package/dist/server/studio-ui/shell/markup-tools.js +29 -15
- package/dist/server/studio-ui/shell/model.js +8 -2
- package/dist/server/studio-ui/shell/paint.js +4 -3
- package/dist/server/studio-ui/shell/pipeline-state.js +2 -11
- package/dist/server/studio-ui/shell/proposals.js +6 -2
- package/dist/server/studio-ui/shell/pulse.d.ts +1 -0
- package/dist/server/studio-ui/shell/pulse.js +68 -0
- package/dist/server/studio-ui/shell/router.js +25 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +7 -5
- package/dist/server/studio-ui/shell/toasts-format.js +4 -4
- package/dist/server/studio-ui/shell/triage.js +1 -1
- package/dist/server/studio-ui/styles/console.js +36 -13
- package/dist/server/studio-ui/styles/dialogs.js +4 -4
- package/dist/server/studio-ui/styles/responsive.js +8 -0
- package/dist/server/studio-ui/styles/shell.js +23 -6
- package/dist/server/studio-ui/styles/strategist.js +10 -10
- package/dist/server/studio-ui/styles/tokens-base.js +23 -23
- package/dist/server/studio-ui.js +2 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/architect.md +11 -12
- package/plugin/agents/verifier.md +4 -1
- package/plugin/skills/nativ/SKILL.md +7 -7
- package/templates/AGENTS.md +7 -7
- package/templates/GEMINI.md +4 -3
- package/templates/claude-agents/architect.md +11 -12
- package/templates/claude-agents/verifier.md +4 -1
- package/templates/design/taste/LICENSE +21 -0
- package/templates/design/taste/SOURCE.md +28 -0
- package/templates/design/taste/v1/DIGEST.md +57 -0
- package/templates/design/taste/v1/SKILL.md +226 -0
- package/templates/design/taste/v2/DIGEST.md +62 -0
- package/templates/design/taste/v2/SKILL.md +1206 -0
- package/templates/dot-ai/subagents/architect.md +8 -2
- package/templates/dot-ai/subagents/flutter-developer.md +2 -11
- package/templates/dot-ai/subagents/frontend.md +47 -44
- package/templates/dot-ai/ui_specs.md +15 -36
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export const modelScript = String.raw ` // ─── Studio client model: buildModel(api) is pure ──────────────────────────
|
|
3
3
|
var RUN_ACTIVE = { spawning_worktree: 1, running: 1, verifying: 1, merging: 1 };
|
|
4
4
|
function isRunActive(run) { return !!run && !!RUN_ACTIVE[run.status]; }
|
|
5
|
+
var STALE_MS = 4 * 3600 * 1000;
|
|
5
6
|
|
|
6
7
|
/** Text before the first colon, at most 46 characters. */
|
|
7
8
|
function shortName(name) {
|
|
@@ -46,11 +47,14 @@ export const modelScript = String.raw ` // ─── Studio client model: build
|
|
|
46
47
|
if (startT == null && run && isRunActive(run)) startT = toTime(run.startedAt);
|
|
47
48
|
var cost = b && b.actual ? positive(b.actual.costUsd) : null;
|
|
48
49
|
if (cost == null && b && b.estimated) cost = positive(b.estimated.costUsd);
|
|
50
|
+
var claimT = toTime(t.claimedAt);
|
|
51
|
+
var stale = running && claimT != null && Studio.now() - claimT > STALE_MS && !isRunActive(run);
|
|
49
52
|
return {
|
|
50
53
|
id: t.id,
|
|
51
54
|
title: t.title || t.id,
|
|
52
55
|
description: t.description || '',
|
|
53
|
-
status: t.status,
|
|
56
|
+
status: stale ? 'pending' : t.status,
|
|
57
|
+
claimedStatus: t.status,
|
|
54
58
|
agent: t.assignedSubagent || null,
|
|
55
59
|
deps: t.dependencies || [],
|
|
56
60
|
files: t.targetFiles || [],
|
|
@@ -62,6 +66,8 @@ export const modelScript = String.raw ` // ─── Studio client model: build
|
|
|
62
66
|
reason: t.status === 'blocked' && t.notes ? String(t.notes).replace(/^\s+|\s+$/g, '') || null : null,
|
|
63
67
|
attempt: attemptsOf(t, running),
|
|
64
68
|
maxAttempts: (t.circuitBreaker && t.circuitBreaker.maxThreshold) || 3,
|
|
69
|
+
claimT: claimT,
|
|
70
|
+
stale: stale,
|
|
65
71
|
startT: startT,
|
|
66
72
|
endT: t.status === 'completed' && b ? toTime(b.completedAt) : null,
|
|
67
73
|
durationMs: b ? positive(b.durationMs) : null,
|
|
@@ -175,7 +181,7 @@ export const modelScript = String.raw ` // ─── Studio client model: build
|
|
|
175
181
|
tasks: tasks,
|
|
176
182
|
byId: byId,
|
|
177
183
|
activeMilestoneId: active,
|
|
178
|
-
running: tasks.filter(function (t) { return t.status === 'in_progress'; }),
|
|
184
|
+
running: tasks.filter(function (t) { return t.status === 'in_progress' && !t.stale; }),
|
|
179
185
|
stuck: tasks.filter(function (t) { return t.status === 'blocked'; }),
|
|
180
186
|
needsYou: needsYouItems(tasks, byId, api.escalations),
|
|
181
187
|
summary: summaryOf(api, milestones, tasks)
|
|
@@ -67,11 +67,9 @@ export const paintScript = String.raw ` // ─── Painting ─────
|
|
|
67
67
|
var side = $('side-nav');
|
|
68
68
|
var main = mainWorktree();
|
|
69
69
|
var agents = pipe.worktrees.filter(function (w) { return w.isAgentWorktree; }).length;
|
|
70
|
-
var s = pipe.report && pipe.report.summary;
|
|
71
70
|
var navHtml = Studio.sidebarHtml({
|
|
72
71
|
model: Studio.model, view: Studio.state.view,
|
|
73
|
-
worktreeCount: pipe.loaded.worktrees && !pipe.errors.worktrees ? agents : null
|
|
74
|
-
benchmarkText: s ? compactNum(Number(s.averageThroughputOpsPerSec) || 0) : ''
|
|
72
|
+
worktreeCount: pipe.loaded.worktrees && !pipe.errors.worktrees ? agents : null
|
|
75
73
|
});
|
|
76
74
|
if (side.__html !== navHtml) { side.innerHTML = navHtml; side.__html = navHtml; }
|
|
77
75
|
var foot = $('side-foot');
|
|
@@ -79,7 +77,10 @@ export const paintScript = String.raw ` // ─── Painting ─────
|
|
|
79
77
|
if (foot.__html !== footHtml) { foot.innerHTML = footHtml; foot.__html = footHtml; }
|
|
80
78
|
var lost = !!(pipe.errors.tasks || pipe.errors.status) || live.mode === 'offline';
|
|
81
79
|
$('banner').hidden = !lost;
|
|
80
|
+
Studio.afterPaint.forEach(function (fn) { try { fn(); } catch (e) { /* one hook must not break painting */ } });
|
|
82
81
|
}
|
|
82
|
+
Studio.afterPaint = Studio.afterPaint || [];
|
|
83
|
+
Studio.onPaint = function (fn) { Studio.afterPaint.push(fn); };
|
|
83
84
|
|
|
84
85
|
/** One entry point after data or state changes: model, sidebar, current page, panel, palette. */
|
|
85
86
|
function refreshUi(parts) {
|
|
@@ -117,18 +117,9 @@ export const pipelineStateScript = String.raw ` // ─── Pipeline state ─
|
|
|
117
117
|
return main;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
/** 1234 becomes "1.2k" so the sidebar badge stays small. */
|
|
121
|
-
function compactNum(n) {
|
|
122
|
-
if (!isFinite(n)) return '–';
|
|
123
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
|
|
124
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1).replace(/\.0$/, '') + 'k';
|
|
125
|
-
return String(Math.round(n));
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Newest Just-finished style helpers live in pages; here only what the runner tools need. */
|
|
129
120
|
var RUN_LABEL = {
|
|
130
|
-
spawning_worktree: '
|
|
131
|
-
completed: '
|
|
121
|
+
spawning_worktree: 'Running', running: 'Running', verifying: 'Running', merging: 'Running',
|
|
122
|
+
completed: 'Done', failed: 'Stuck', aborted: 'Up next'
|
|
132
123
|
};
|
|
133
124
|
function runFor(taskId) {
|
|
134
125
|
var found = null;
|
|
@@ -111,6 +111,7 @@ export const proposalsScript = String.raw ` // ─── Console tab 3: self-he
|
|
|
111
111
|
|
|
112
112
|
function openConsole(taskId, quiet, tab) {
|
|
113
113
|
var drawer = $('runner-console-drawer');
|
|
114
|
+
rememberInspectorOpener();
|
|
114
115
|
if (rc.taskId !== taskId) {
|
|
115
116
|
rc.taskId = taskId;
|
|
116
117
|
rc.backfilled = false;
|
|
@@ -130,10 +131,11 @@ export const proposalsScript = String.raw ` // ─── Console tab 3: self-he
|
|
|
130
131
|
rc.minimized = false;
|
|
131
132
|
drawer.hidden = false;
|
|
132
133
|
drawer.classList.remove('is-min');
|
|
133
|
-
$('rc-minimize').textContent = '
|
|
134
|
+
$('rc-minimize').textContent = 'Collapse';
|
|
134
135
|
$('rc-minimize').setAttribute('aria-expanded', 'true');
|
|
135
136
|
document.body.classList.add('has-console');
|
|
136
137
|
document.body.classList.remove('has-console-min');
|
|
138
|
+
applyInspectorMode();
|
|
137
139
|
syncConsole();
|
|
138
140
|
syncHealTab();
|
|
139
141
|
rcTick();
|
|
@@ -149,6 +151,8 @@ export const proposalsScript = String.raw ` // ─── Console tab 3: self-he
|
|
|
149
151
|
rc.diffTimer = null;
|
|
150
152
|
$('runner-console-drawer').hidden = true;
|
|
151
153
|
document.body.classList.remove('has-console', 'has-console-min');
|
|
154
|
+
applyInspectorMode();
|
|
155
|
+
restoreInspectorFocus();
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
function toggleConsoleMinimized() {
|
|
@@ -158,7 +162,7 @@ export const proposalsScript = String.raw ` // ─── Console tab 3: self-he
|
|
|
158
162
|
document.body.classList.toggle('has-console', !rc.minimized);
|
|
159
163
|
document.body.classList.toggle('has-console-min', rc.minimized);
|
|
160
164
|
var btn = $('rc-minimize');
|
|
161
|
-
btn.textContent = rc.minimized ? 'Expand' : '
|
|
165
|
+
btn.textContent = rc.minimized ? 'Expand' : 'Collapse';
|
|
162
166
|
btn.setAttribute('aria-expanded', String(!rc.minimized));
|
|
163
167
|
if (!rc.minimized && rc.tab === 'diff' && rc.taskId) loadConsoleDiff(rc.taskId);
|
|
164
168
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const pulseScript: string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Pulse strip: active milestone plus running, blocked and decision counts under the header.
|
|
2
|
+
export const pulseScript = String.raw ` // ─── Pulse strip ───────────────────────────────────────────────────────────
|
|
3
|
+
/** Pure: turns raw counts into the strip's parts. in = { loaded, offline, ms, running, blocked, decisions }. */
|
|
4
|
+
function pulseParts(s) {
|
|
5
|
+
if (s.offline) return { kind: 'offline', text: 'Offline, retrying' };
|
|
6
|
+
if (!s.loaded) return { kind: 'loading', text: '-- -- -- --' };
|
|
7
|
+
var counts = [
|
|
8
|
+
{ key: 'running', label: 'running', n: s.running, tone: 'run' },
|
|
9
|
+
{ key: 'stuck', label: 'stuck', n: s.blocked, tone: 'bad' },
|
|
10
|
+
{ key: 'decisions', label: s.decisions === 1 ? 'decision' : 'decisions', n: s.decisions, tone: 'warn' }
|
|
11
|
+
];
|
|
12
|
+
counts = counts.filter(function (c) { return c.n > 0; });
|
|
13
|
+
counts.forEach(function (c) { c.zero = false; });
|
|
14
|
+
return { kind: 'ready', ms: s.ms, counts: counts };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function pulseHtml(p) {
|
|
18
|
+
if (p.kind !== 'ready') {
|
|
19
|
+
return '<span class="pulse-note ' + p.kind + '">' + esc(p.text) + '</span>';
|
|
20
|
+
}
|
|
21
|
+
if (!p.counts.length) return '';
|
|
22
|
+
var out = '<span class="pulse-ms num">' + esc(p.ms) + '</span>';
|
|
23
|
+
p.counts.forEach(function (c) {
|
|
24
|
+
out += '<button type="button" class="pulse-item ' + c.tone + '" data-pulse="' + c.key + '">' +
|
|
25
|
+
'<span class="num">' + c.n + '</span> ' + c.label + '</button>';
|
|
26
|
+
});
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function pulseInput() {
|
|
31
|
+
var m = Studio.model;
|
|
32
|
+
var ms = null;
|
|
33
|
+
if (m) m.milestones.forEach(function (x) { if (x.id === m.activeMilestoneId) ms = x; });
|
|
34
|
+
// Same source as the Home decision queue, so the two counts agree.
|
|
35
|
+
var decisions = m && m.needsYou ? m.needsYou : [];
|
|
36
|
+
return {
|
|
37
|
+
loaded: !!(m && pipe.loaded.tasks),
|
|
38
|
+
offline: live.mode === 'offline',
|
|
39
|
+
ms: ms ? ms.id + ' ' + ms.done + '/' + ms.total : '',
|
|
40
|
+
running: m ? m.running.length : 0,
|
|
41
|
+
blocked: m ? m.stuck.length : 0,
|
|
42
|
+
decisions: decisions.length
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var pulseEl = $('pulse');
|
|
47
|
+
function paintPulse() {
|
|
48
|
+
if (!pulseEl) return;
|
|
49
|
+
var html = pulseHtml(pulseParts(pulseInput()));
|
|
50
|
+
if (pulseEl.__html === html) return;
|
|
51
|
+
pulseEl.innerHTML = html;
|
|
52
|
+
pulseEl.hidden = !html;
|
|
53
|
+
pulseEl.__html = html;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Studio.taskFilter ('running' or 'stuck') is read by the Tasks page when it opens.
|
|
57
|
+
if (pulseEl) pulseEl.addEventListener('click', function (e) {
|
|
58
|
+
var b = e.target.closest ? e.target.closest('[data-pulse]') : null;
|
|
59
|
+
if (!b) return;
|
|
60
|
+
var key = b.getAttribute('data-pulse');
|
|
61
|
+
if (key === 'decisions') { location.hash = '#home'; return; }
|
|
62
|
+
Studio.taskFilter = key;
|
|
63
|
+
location.hash = '#tasks';
|
|
64
|
+
});
|
|
65
|
+
Studio.onPaint(paintPulse);
|
|
66
|
+
paintPulse();
|
|
67
|
+
|
|
68
|
+
`;
|
|
@@ -88,6 +88,31 @@ export const routerScript = String.raw ` // ─── Router and shell-wide eve
|
|
|
88
88
|
});
|
|
89
89
|
}, 1000);
|
|
90
90
|
|
|
91
|
+
// Active milestone: the one with running tasks, else the highest-index one.
|
|
92
|
+
Studio.activeMilestone = function (model) {
|
|
93
|
+
var list = (model && model.milestones) || [];
|
|
94
|
+
var run = list.filter(function (m) {
|
|
95
|
+
return m.tasks.some(function (t) { return t.status === 'in_progress'; });
|
|
96
|
+
});
|
|
97
|
+
var pool = run.length ? run : list;
|
|
98
|
+
return pool.length ? pool[pool.length - 1] : null;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
var autoNavDone = false;
|
|
102
|
+
Studio.autoNav = function () {
|
|
103
|
+
if (autoNavDone || !pipe.loaded.tasks || !Studio.model) return;
|
|
104
|
+
var ms = Studio.activeMilestone(Studio.model);
|
|
105
|
+
if (!ms) return;
|
|
106
|
+
autoNavDone = true;
|
|
107
|
+
var S = Studio.state;
|
|
108
|
+
var opts = { milestoneId: ms.id, keepDetail: true, scroll: false };
|
|
109
|
+
if (!S.view) Studio.go('tasks', opts);
|
|
110
|
+
else { S.milestoneId = ms.id; paintPage(S.view); }
|
|
111
|
+
var el = document.querySelector('[data-milestone="' + cssEsc(ms.id) + '"], [data-ms-group="' + cssEsc(ms.id) + '"]');
|
|
112
|
+
if (el && el.scrollIntoView) el.scrollIntoView({ block: 'start' });
|
|
113
|
+
};
|
|
114
|
+
if (typeof Studio.onPaint === 'function') { Studio.onPaint(function () { Studio.autoNav(); }); }
|
|
115
|
+
|
|
91
116
|
Studio.api = api;
|
|
92
117
|
Studio.postJson = postJson;
|
|
93
118
|
Studio.toast = function (message, kind) { toast(message, kind); };
|
|
@@ -5,19 +5,21 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
5
5
|
function navBadges(env) {
|
|
6
6
|
var badges = {}, model = env.model;
|
|
7
7
|
if (model && model.needsYou.length) badges.home = ['warn', model.needsYou.length];
|
|
8
|
-
|
|
8
|
+
var ready = model ? model.tasks.filter(Studio.status.isReady).length : 0;
|
|
9
|
+
var active = model ? model.running.length + ready : 0;
|
|
10
|
+
if (active) badges.tasks = [model.running.length ? 'run' : '', active];
|
|
9
11
|
if (env.worktreeCount != null) badges.worktrees = ['', env.worktreeCount];
|
|
10
|
-
if (env.benchmarkText) badges.benchmarks = ['', env.benchmarkText];
|
|
11
12
|
return badges;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
/** env = { model, view, worktreeCount
|
|
15
|
+
/** env = { model, view, worktreeCount }. */
|
|
15
16
|
Studio.sidebarHtml = function (env) {
|
|
16
17
|
var badges = navBadges(env);
|
|
17
18
|
var item = function (p) {
|
|
18
19
|
var b = badges[p.id];
|
|
19
20
|
return '<button type="button" class="nav-item" data-go="' + esc(p.id) + '"' +
|
|
20
|
-
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
21
|
+
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
22
|
+
' aria-label="' + esc(p.label) + '" title="' + esc(p.label) + '"' + '>' + ui.svg(p.icon) +
|
|
21
23
|
'<span class="nav-text">' + esc(p.label) + '</span>' +
|
|
22
24
|
(b ? '<span class="nav-badge' + (b[0] ? ' ' + b[0] : '') + '">' + esc(b[1]) + '</span>' : '') + '</button>';
|
|
23
25
|
};
|
|
@@ -32,7 +34,7 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
32
34
|
/** env = { root, branch }. */
|
|
33
35
|
Studio.sideFootHtml = function (env) {
|
|
34
36
|
return '<span>Workspace</span><span class="mono" id="sb-root" title="' + esc(env.root || '') + '">' +
|
|
35
|
-
esc(env.root || '
|
|
37
|
+
esc(env.root || '-') + '</span><span>branch <span class="mono" id="sb-branch-name">' + esc(env.branch || '-') + '</span></span>';
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
`;
|
|
@@ -48,16 +48,16 @@ export const toastsFormatScript = String.raw ` // ─── Toasts ────
|
|
|
48
48
|
|
|
49
49
|
// ─── Formatting ────────────────────────────────────────────────────────────
|
|
50
50
|
function num(n) {
|
|
51
|
-
if (n == null || n === '' || isNaN(n)) return '
|
|
51
|
+
if (n == null || n === '' || isNaN(n)) return '-';
|
|
52
52
|
return Number(n).toLocaleString('en-US', { maximumFractionDigits: 3 });
|
|
53
53
|
}
|
|
54
54
|
function usd(n) {
|
|
55
|
-
if (n == null || isNaN(n)) return '
|
|
55
|
+
if (n == null || isNaN(n)) return '-';
|
|
56
56
|
n = Number(n);
|
|
57
57
|
return '$' + (n >= 100 ? n.toFixed(0) : n >= 1 ? n.toFixed(2) : n.toFixed(3));
|
|
58
58
|
}
|
|
59
59
|
function fmtMs(ms) {
|
|
60
|
-
if (ms == null || isNaN(ms)) return '
|
|
60
|
+
if (ms == null || isNaN(ms)) return '-';
|
|
61
61
|
if (ms < 1000) return Math.round(ms) + ' ms';
|
|
62
62
|
if (ms < 60000) return (ms / 1000).toFixed(2) + ' s';
|
|
63
63
|
return Math.floor(ms / 60000) + 'm ' + Math.round((ms % 60000) / 1000) + 's';
|
|
@@ -83,7 +83,7 @@ export const toastsFormatScript = String.raw ` // ─── Toasts ────
|
|
|
83
83
|
if (typeof v === 'number') return num(v);
|
|
84
84
|
if (Array.isArray(v)) return v.map(String).join(', ');
|
|
85
85
|
if (v && typeof v === 'object') return JSON.stringify(v);
|
|
86
|
-
return String(v == null ? '
|
|
86
|
+
return String(v == null ? '-' : v);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
`;
|
|
@@ -35,7 +35,7 @@ export const triageScript = String.raw ` // ─── Tier 1 AI Strategist (/ap
|
|
|
35
35
|
$('t1-chip-model').textContent = modelName(model);
|
|
36
36
|
$('t1-model').textContent = model;
|
|
37
37
|
var last = lastTriage();
|
|
38
|
-
$('t1-latency').textContent = last ? fmtMs(last.latencyMs) + '
|
|
38
|
+
$('t1-latency').textContent = last ? fmtMs(last.latencyMs) + ', ' + modelName(last.model || model) : 'No evaluations yet';
|
|
39
39
|
$('t1-key').textContent = pipe.errors.triage && !t ? 'Status unavailable' : !t ? 'Checking' : t.hasApiKey ? 'Configured' : 'Not set (offline rules)';
|
|
40
40
|
var sw = $('t1-auto');
|
|
41
41
|
var on = !!(t && t.autoTriageEnabled);
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
// Runner console drawer and proposal review styles.
|
|
2
|
-
export const consoleCss = String.raw `/*
|
|
3
|
-
|
|
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); }
|
|
2
|
+
export const consoleCss = String.raw `/* Runner inspector: right pane at 1024px and up, modal sheet below. */
|
|
3
|
+
#runner-console-drawer { position: fixed; top: var(--inspector-top, 96px); right: 0; bottom: 0; z-index: 30; width: 320px; display: flex; flex-direction: column; background: var(--term-bg); color: var(--term-text); border-left: 1px solid var(--line); transition: width .2s ease; }
|
|
6
4
|
#runner-console-drawer[hidden] { display: none; }
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.
|
|
5
|
+
/* Content reflows beside the pane instead of sitting under it. */
|
|
6
|
+
body.has-console main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 320px; }
|
|
7
|
+
body.has-console-min main { margin-right: 56px; }
|
|
8
|
+
@media (min-width: 1280px) {
|
|
9
|
+
#runner-console-drawer { width: 360px; }
|
|
10
|
+
body.has-console main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 360px; }
|
|
11
|
+
}
|
|
12
|
+
#runner-console-drawer.is-min { width: 56px; overflow: hidden; }
|
|
13
|
+
#runner-console-drawer.is-min .rc-body, #runner-console-drawer.is-min .rc-foot, #runner-console-drawer.is-min .rc-title, #runner-console-drawer.is-min .rc-steps, #runner-console-drawer.is-min .rc-status, #runner-console-drawer.is-min .rc-clock { display: none; }
|
|
14
|
+
@media (max-width: 1023px) {
|
|
15
|
+
#runner-console-drawer { top: 0; width: min(420px, 92vw); max-width: 92vw; z-index: 40; border-radius: 6px 0 0 6px; box-shadow: var(--shadow); }
|
|
16
|
+
body.has-console main, body.has-console-min main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 0; }
|
|
17
|
+
}
|
|
18
|
+
/* The task detail dialog stays modal above the inspector. */
|
|
19
|
+
#task-drawer { z-index: 45; }
|
|
20
|
+
.rc-id-row { display: flex; align-items: center; gap: 10px; width: 100%; }
|
|
21
|
+
.rc-status { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--term-muted); }
|
|
22
|
+
.rc-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--term-muted); }
|
|
23
|
+
.rc-status[data-tone="ok"] .rc-dot { background: var(--ok); }
|
|
24
|
+
.rc-status[data-tone="err"] .rc-dot { background: var(--danger); }
|
|
25
|
+
.rc-status[data-tone="run"] .rc-dot { background: var(--warn); }
|
|
26
|
+
.rc-clock { margin-left: auto; font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; color: var(--term-muted); }
|
|
10
27
|
.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:
|
|
12
|
-
.rc-steps { display: flex; align-items: center; gap: 6px; margin: 0
|
|
28
|
+
.rc-title { font-size: 12.5px; color: var(--term-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; flex: 1 1 100%; }
|
|
29
|
+
.rc-steps { display: flex; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; flex-wrap: wrap; }
|
|
13
30
|
.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
31
|
.rc-step.is-done { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 55%, transparent); }
|
|
15
32
|
.rc-step.is-active { color: var(--term-text); background: color-mix(in srgb, var(--primary) 32%, transparent); border-color: var(--primary); }
|
|
16
33
|
.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:
|
|
34
|
+
.rc-controls { display: flex; gap: 6px; flex-wrap: wrap; }
|
|
35
|
+
.rc-more { position: relative; }
|
|
36
|
+
.rc-menu { position: absolute; top: calc(100% + 4px); left: 0; z-index: 2; display: flex; flex-direction: column; gap: 4px; padding: 6px; background: var(--term-bg); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
37
|
+
.rc-menu[hidden], .rc-btn[hidden], .rc-steps[hidden], .rc-foot[hidden] { display: none; }
|
|
18
38
|
.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
39
|
.rc-btn:hover { background: color-mix(in srgb, var(--term-muted) 22%, transparent); }
|
|
20
40
|
.rc-btn:disabled { opacity: .45; cursor: not-allowed; }
|
|
@@ -22,7 +42,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
22
42
|
.rc-btn.danger { color: var(--term-text); border-color: var(--danger); }
|
|
23
43
|
.rc-btn.danger:hover { background: color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
24
44
|
.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; }
|
|
45
|
+
.rc-body { flex: 1 1 auto; min-height: 120px; margin: 0; padding: 10px 14px; overflow: auto; font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
26
46
|
.rc-body:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
27
47
|
.rc-empty { color: var(--term-muted); }
|
|
28
48
|
.rc-fg-muted { color: var(--term-muted); }
|
|
@@ -31,10 +51,10 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
31
51
|
.rc-fg-info { color: var(--accent); }
|
|
32
52
|
.rc-fg-danger { color: color-mix(in srgb, var(--danger) 55%, #fff); }
|
|
33
53
|
.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); }
|
|
54
|
+
.rc-foot { font-variant-numeric: tabular-nums; 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
55
|
.rc-foot strong { font-family: var(--mono); font-weight: 600; color: var(--term-text); }
|
|
36
56
|
#runner-console-drawer.is-min .rc-tabs { display: none; }
|
|
37
|
-
.rc-tabs { display: flex; gap: 2px; padding: 0
|
|
57
|
+
.rc-tabs { display: flex; gap: 2px; padding: 0 10px; overflow-x: auto; border-bottom: 1px solid var(--line); }
|
|
38
58
|
.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
59
|
.rc-tab:hover { color: var(--term-text); }
|
|
40
60
|
.rc-tab[aria-selected="true"] { color: var(--term-text); border-bottom-color: var(--primary); }
|
|
@@ -80,4 +100,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
80
100
|
.heal-result.is-error { color: color-mix(in srgb, var(--danger) 55%, #fff); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
81
101
|
.heal-skel { height: 12px; margin: 8px 0; border-radius: 4px; background: var(--term-line); animation: blink 1.4s ease-in-out infinite; }
|
|
82
102
|
@media (max-width: 768px) { .heal-grid { grid-template-columns: 1fr; } }
|
|
103
|
+
@media (prefers-reduced-motion: reduce) {
|
|
104
|
+
#runner-console-drawer, #runner-console-drawer * { transition: none !important; animation: none !important; }
|
|
105
|
+
}
|
|
83
106
|
`;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export const dialogsCss = String.raw `/* Toasts */
|
|
3
3
|
/* Bottom-right so notifications never cover the sticky header and navigation. */
|
|
4
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(--
|
|
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(--line-2); border-left: 3px solid var(--danger); border-radius: var(--r-card); box-shadow: var(--shadow); animation: toast-in .18s ease-out; }
|
|
6
6
|
.toast.ok { border-left-color: var(--success); }
|
|
7
7
|
.toast .t-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
8
8
|
.toast .t-hint { color: var(--muted); font-size: 12.5px; }
|
|
@@ -12,8 +12,8 @@ export const dialogsCss = String.raw `/* Toasts */
|
|
|
12
12
|
/* Dialogs */
|
|
13
13
|
dialog { border: none; padding: 0; background: transparent; color: var(--text); width: min(640px, calc(100vw - 32px)); max-height: calc(100vh - 32px); }
|
|
14
14
|
dialog.narrow { width: min(460px, calc(100vw - 32px)); }
|
|
15
|
-
dialog::backdrop { background:
|
|
16
|
-
.modal { padding: 22px; background: var(--surface); border: 1px solid var(--
|
|
15
|
+
dialog::backdrop { background: color-mix(in srgb, var(--text) 40%, transparent); backdrop-filter: blur(2px); }
|
|
16
|
+
.modal { padding: 22px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-card); box-shadow: var(--shadow); }
|
|
17
17
|
.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; }
|
|
18
18
|
.modal .lead { color: var(--muted); margin: 0 0 16px; font-size: 14px; line-height: 1.55; }
|
|
19
19
|
.field { margin-bottom: 16px; }
|
|
@@ -112,7 +112,7 @@ textarea.cmd-preview { min-height: 92px; font-family: var(--mono); font-size: 12
|
|
|
112
112
|
.switch-text { display: flex; flex-direction: column; font-size: 13.5px; }
|
|
113
113
|
.switch-text b { font-weight: 600; }
|
|
114
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:
|
|
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: var(--r-control); }
|
|
116
116
|
.btn.primary kbd { color: var(--accent-fg); background: transparent; border-color: color-mix(in srgb, var(--accent-fg) 45%, transparent); }
|
|
117
117
|
|
|
118
118
|
`;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// Responsive rules for the kept pages and dialogs.
|
|
2
2
|
export const responsiveCss = String.raw `/* Responsive */
|
|
3
|
+
@media (max-width: 1023px) and (min-width: 761px) {
|
|
4
|
+
:root { --sidebar-w: 56px; }
|
|
5
|
+
.side { padding: 16px 8px; align-items: center; }
|
|
6
|
+
.brand { padding: 0; justify-content: center; }
|
|
7
|
+
.brand .wordmark { height: 16px; width: 16px; overflow: hidden; }
|
|
8
|
+
.brand b, .brand .ver, .nav-glabel, .nav-text, .nav-badge, .side-foot { display: none; }
|
|
9
|
+
.nav-item { justify-content: center; padding: 6px; width: 40px; }
|
|
10
|
+
}
|
|
3
11
|
@media (max-width: 900px) {
|
|
4
12
|
#runner-console-drawer { inset: auto 0 0 0; }
|
|
5
13
|
.panes { grid-template-columns: 1fr; }
|
|
@@ -3,22 +3,23 @@ export const shellCss = String.raw `/* Layout */
|
|
|
3
3
|
.app { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); min-height: 100vh; }
|
|
4
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
5
|
.brand { display: flex; align-items: center; gap: 10px; padding: 0 6px; }
|
|
6
|
-
.
|
|
6
|
+
.wordmark { height: 18px; width: auto; color: var(--fg); display: block; flex: none; }
|
|
7
|
+
.wordmark.is-rail { height: 16px; }
|
|
7
8
|
.brand b { font-weight: 600; white-space: nowrap; }
|
|
8
|
-
.
|
|
9
|
+
.side-foot .ver { font: 11px var(--mono); color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
9
10
|
.nav { display: flex; flex-direction: column; gap: 14px; }
|
|
10
11
|
.nav-group { display: flex; flex-direction: column; gap: 2px; }
|
|
11
12
|
.nav-glabel { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); padding: 0 8px 4px; }
|
|
12
13
|
.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:
|
|
14
|
+
.nav-item svg { width: 20px; height: 20px; flex: none; }
|
|
14
15
|
.nav-item:hover { background: var(--surface-2); color: var(--fg); }
|
|
15
|
-
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--
|
|
16
|
+
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--fg); font-weight: 600; }
|
|
16
17
|
.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
18
|
.nav-badge.warn { background: var(--warn-soft); color: var(--warn); }
|
|
18
19
|
.nav-badge.run { background: var(--run-soft); color: var(--run); }
|
|
19
20
|
.side-foot { margin-top: auto; font-size: 12px; color: var(--fg-3); padding: 0 8px; display: flex; flex-direction: column; gap: 4px; }
|
|
20
21
|
.side-foot > div { display: flex; flex-direction: column; gap: 4px; }
|
|
21
|
-
.side-foot .mono { color: var(--fg-2); font-size: 11px;
|
|
22
|
+
.side-foot .mono { color: var(--fg-2); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
22
23
|
.foot-project { color: var(--fg); font-weight: 500; }
|
|
23
24
|
.main { min-width: 0; display: flex; flex-direction: column; }
|
|
24
25
|
.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; }
|
|
@@ -27,6 +28,22 @@ export const shellCss = String.raw `/* Layout */
|
|
|
27
28
|
.top-right { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
28
29
|
.btn.ghost { background: none; border-color: transparent; color: var(--fg-2); box-shadow: none; }
|
|
29
30
|
.btn.ghost:hover { background: var(--surface-2); }
|
|
31
|
+
.spacer { flex: 1; }
|
|
32
|
+
.ic-sun, .ic-moon { display: inline-flex; }
|
|
33
|
+
.ic-moon { display: none; }
|
|
34
|
+
:root[data-theme="light"] .ic-sun { display: none; }
|
|
35
|
+
:root[data-theme="light"] .ic-moon { display: inline-flex; }
|
|
36
|
+
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .ic-sun { display: none; } :root:not([data-theme="dark"]) .ic-moon { display: inline-flex; } }
|
|
37
|
+
#pulse[hidden] { display: none; }
|
|
38
|
+
.pulse-strip { min-height: 32px; height: auto; width: auto; border-radius: 0; background: none; box-shadow: none; animation: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0 20px; padding: 0 24px; border-bottom: 1px solid var(--line); font: 12.5px var(--mono); color: var(--fg-2); }
|
|
39
|
+
#pulse .num { font-variant-numeric: tabular-nums; }
|
|
40
|
+
#pulse .pulse-ms { color: var(--fg); padding-right: 20px; border-right: 1px solid var(--line); }
|
|
41
|
+
#pulse .pulse-item { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
|
|
42
|
+
#pulse .pulse-note.loading { color: var(--fg-3); }
|
|
43
|
+
#pulse .pulse-item.run { color: var(--run); } #pulse .pulse-item.bad { color: var(--bad); } #pulse .pulse-item.warn, #pulse .pulse-note.offline { color: var(--warn); }
|
|
44
|
+
@media (max-width: 1023px) { .pulse-strip { padding-top: 4px; padding-bottom: 4px; gap: 0 16px; } #pulse .pulse-ms { flex-basis: 100%; border-right: 0; padding-right: 0; } }
|
|
45
|
+
.wordmark.is-rail { display: none; }
|
|
46
|
+
@media (max-width: 1023px) { .wordmark { display: none; } .wordmark.is-rail { display: block; } }
|
|
30
47
|
.btn svg { width: 14px; height: 14px; }
|
|
31
48
|
.kbd { font: 11px var(--mono); padding: 0 5px; border: 1px solid var(--line); border-radius: 4px; color: var(--fg-3); }
|
|
32
49
|
.live { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--fg-2); }
|
|
@@ -113,5 +130,5 @@ export const shellCss = String.raw `/* Layout */
|
|
|
113
130
|
.drawer { width: 100%; }
|
|
114
131
|
#runner-console-drawer { inset: auto 0 0 0; }
|
|
115
132
|
}
|
|
116
|
-
@media (prefers-reduced-motion: reduce) { .pulse, .live-dot.flash { animation: none; } * { transition: none !important; } }
|
|
133
|
+
@media (prefers-reduced-motion: reduce) { .pulse, .live-dot.flash { animation: none !important; } * { transition: none !important; } }
|
|
117
134
|
`;
|
|
@@ -12,30 +12,30 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
12
12
|
.t1-chip-label { color: var(--muted); }
|
|
13
13
|
.t1-caret { color: var(--muted); transition: transform .15s; }
|
|
14
14
|
.t1-chip[aria-expanded="true"] .t1-caret { transform: rotate(180deg); }
|
|
15
|
-
.t1-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 300px; padding: 12px; font-size: 12.5px; background: var(--surface); border: 1px solid var(--
|
|
15
|
+
.t1-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 300px; padding: 12px; font-size: 12.5px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-card); box-shadow: var(--shadow); }
|
|
16
16
|
.t1-menu:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
17
17
|
.t1-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 28px; color: var(--muted); }
|
|
18
18
|
.t1-row b, .t1-row code { color: var(--text); font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
19
19
|
.t1-row code { font-family: var(--mono); font-size: 12px; }
|
|
20
|
-
.t1-switch { position: relative; width: 54px; height: 24px; padding: 0 8px; font: 600 10.5px/22px var(--mono); color: var(--muted); text-align: right; background: var(--chip); border: 1px solid var(--chip-border); border-radius:
|
|
20
|
+
.t1-switch { position: relative; width: 54px; height: 24px; padding: 0 8px; font: 600 10.5px/22px var(--mono); color: var(--muted); text-align: right; background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); cursor: pointer; transition: background .15s, border-color .15s; }
|
|
21
21
|
.t1-switch::before { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: var(--surface); box-shadow: var(--shadow); transition: transform .15s; }
|
|
22
|
-
.t1-switch[aria-checked="true"] { color:
|
|
22
|
+
.t1-switch[aria-checked="true"] { color: var(--accent-fg); text-align: left; background: var(--success); border-color: var(--success); }
|
|
23
23
|
.t1-switch[aria-checked="true"]::before { transform: translateX(30px); }
|
|
24
24
|
.t1-switch:disabled { opacity: .5; cursor: not-allowed; }
|
|
25
25
|
.t1-policy { display: flex; gap: 6px; margin: 8px 0; padding: 8px; line-height: 1.45; color: var(--muted); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-control); }
|
|
26
26
|
.t1-policy .icon { flex: none; margin-top: 1px; color: var(--success); }
|
|
27
27
|
.t1-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin: 0; }
|
|
28
|
-
.t1-stats div { min-width: 0; padding: 6px 8px; border: 1px solid var(--
|
|
28
|
+
.t1-stats div { min-width: 0; padding: 6px 8px; border: 0; border-left: 1px solid var(--line); border-radius: 0; font-variant-numeric: tabular-nums; }
|
|
29
29
|
.t1-stats dt { font-size: 11px; color: var(--muted); }
|
|
30
30
|
.t1-stats dd { margin: 2px 0 0; font: 600 15px/1.2 var(--mono); font-variant-numeric: tabular-nums; color: var(--text); }
|
|
31
31
|
.t1-strip { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; color: var(--term-muted); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
32
32
|
.t1-strip > span { display: inline-flex; align-items: center; gap: 6px; }
|
|
33
33
|
.t1-strip strong { color: var(--term-text); font-weight: 600; }
|
|
34
34
|
.t1-strip.is-triaging { border-color: color-mix(in srgb, var(--active) 60%, transparent); background: color-mix(in srgb, var(--active) 14%, transparent); }
|
|
35
|
-
.rc-btn.t1-run { color:
|
|
36
|
-
.rc-btn.t1-run:hover:not(:disabled) { background: color-mix(in srgb, var(--active) 88%,
|
|
35
|
+
.rc-btn.t1-run { color: var(--accent-fg); background: var(--active); border-color: var(--active); }
|
|
36
|
+
.rc-btn.t1-run:hover:not(:disabled) { background: color-mix(in srgb, var(--active) 88%, var(--text)); }
|
|
37
37
|
.t1-banner { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; padding: 8px 10px; font-weight: 600; border-radius: var(--r-control); }
|
|
38
|
-
.t1-banner.is-resolved { color:
|
|
38
|
+
.t1-banner.is-resolved { color: var(--accent-fg); background: var(--success); }
|
|
39
39
|
.t1-banner.is-safe { color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent); }
|
|
40
40
|
.t1-card { margin: 0 0 12px; padding: 12px 12px 12px 16px; border: 1px solid var(--term-line); border-left: 4px solid var(--proposal); border-radius: var(--r-card); }
|
|
41
41
|
.t1-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
@@ -53,10 +53,10 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
53
53
|
.t1-opt:hover { border-color: var(--term-text); }
|
|
54
54
|
.t1-opt.is-recommended { background: var(--primary); border-color: var(--primary); }
|
|
55
55
|
.t1-opt.is-recommended:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
|
|
56
|
-
.t1-opt.is-recommended span { color: color-mix(in srgb,
|
|
56
|
+
.t1-opt.is-recommended span { color: color-mix(in srgb, var(--accent-fg) 82%, var(--primary)); }
|
|
57
57
|
.t1-opt[aria-checked="true"] { box-shadow: 0 0 0 2px var(--term-bg), 0 0 0 4px var(--proposal); }
|
|
58
58
|
.t1-custom { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; font-size: 12px; color: var(--term-muted); }
|
|
59
|
-
.t1-custom textarea { width: 100%; box-sizing: border-box; min-height: 52px; padding: 6px 8px; font: 12.5px/1.45 var(--font); color: var(--term-text); background:
|
|
59
|
+
.t1-custom textarea { width: 100%; box-sizing: border-box; min-height: 52px; padding: 6px 8px; font: 12.5px/1.45 var(--font); color: var(--term-text); background: color-mix(in srgb, var(--term-text) 8%, transparent); border: 1px solid var(--term-line); border-radius: var(--r-control); resize: vertical; }
|
|
60
60
|
.t1-custom textarea:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
|
|
61
61
|
.t1-decided { margin: 8px 0 0; font-size: 12px; color: var(--term-muted); }
|
|
62
62
|
@media (prefers-reduced-motion: reduce) { .t1-chip[data-state="triaging"] .t1-spark { animation: none; } }
|
|
@@ -65,7 +65,7 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
65
65
|
.t1-menu { position: fixed; top: 56px; left: 16px; right: 16px; width: auto; }
|
|
66
66
|
}
|
|
67
67
|
.df-add { display: block; color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
|
|
68
|
-
.df-del { display: block; color: color-mix(in srgb, var(--danger) 55%,
|
|
68
|
+
.df-del { display: block; color: color-mix(in srgb, var(--danger) 55%, var(--accent-fg)); background: color-mix(in srgb, var(--danger) 14%, transparent); }
|
|
69
69
|
.df-hunk { display: block; color: var(--accent); }
|
|
70
70
|
.df-file { display: block; margin-top: 8px; font-weight: 700; color: var(--term-text); }
|
|
71
71
|
.df-meta { display: block; color: var(--term-muted); }
|