@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
|
@@ -38,6 +38,7 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
38
38
|
|
|
39
39
|
function rcStepper(run) {
|
|
40
40
|
var status = run ? run.status : null;
|
|
41
|
+
if (!run) return '';
|
|
41
42
|
var stage = RC_STAGE[status] != null ? RC_STAGE[status] : rc.stage;
|
|
42
43
|
var settled = !!status && !RUN_ACTIVE[status];
|
|
43
44
|
var failed = status === 'failed' || status === 'aborted';
|
|
@@ -57,16 +58,22 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
57
58
|
function syncConsole() {
|
|
58
59
|
var run = rc.taskId ? runFor(rc.taskId) : null;
|
|
59
60
|
var task = rc.taskId ? taskById(rc.taskId) : null;
|
|
60
|
-
$('rc-task').textContent = rc.taskId || '
|
|
61
|
+
$('rc-task').textContent = rc.taskId || '';
|
|
61
62
|
$('rc-title').textContent = task ? task.title : '';
|
|
62
63
|
$('rc-steps').innerHTML = rcStepper(run);
|
|
63
|
-
$('rc-abort').
|
|
64
|
+
$('rc-abort').hidden = !isRunActive(run);
|
|
65
|
+
$('rc-steps').hidden = !run;
|
|
66
|
+
$('rc-foot').hidden = !run;
|
|
64
67
|
$('rc-elapsed').textContent = mmss(elapsedOf(run) || 0);
|
|
68
|
+
$('rc-clock').textContent = $('rc-elapsed').textContent;
|
|
69
|
+
syncInspectorStatus(run);
|
|
65
70
|
$('rc-bytes').textContent = formatBytes((run && run.logBytes) || 0);
|
|
66
|
-
|
|
71
|
+
$('rc-bytes-wrap').hidden = !(run && run.logBytes > 0);
|
|
72
|
+
var gate = '';
|
|
67
73
|
if (run && run.verification) gate = run.verification.success ? 'Passed' : 'Failed';
|
|
68
74
|
else if (run && run.status === 'verifying') gate = 'Running';
|
|
69
75
|
$('rc-gate').textContent = gate;
|
|
76
|
+
$('rc-gate-wrap').hidden = !gate;
|
|
70
77
|
// Native runs report grounded usage; cli runs have none to show.
|
|
71
78
|
var usage = run && run.usage;
|
|
72
79
|
$('rc-spend-wrap').hidden = !usage;
|
|
@@ -79,7 +86,7 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
79
86
|
if (run && !isRunActive(run)) {
|
|
80
87
|
exit = RUN_LABEL[run.status] || run.status;
|
|
81
88
|
if (typeof run.exitCode === 'number') exit += ' (exit ' + run.exitCode + ')';
|
|
82
|
-
if (run.error) exit += '
|
|
89
|
+
if (run.error) exit += ', ' + run.error;
|
|
83
90
|
}
|
|
84
91
|
$('rc-exit').textContent = exit;
|
|
85
92
|
}
|
|
@@ -90,6 +97,7 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
90
97
|
var run = rc.taskId ? runFor(rc.taskId) : null;
|
|
91
98
|
if (!rc.taskId || !isRunActive(run)) { clearInterval(rc.ticker); rc.ticker = null; return; }
|
|
92
99
|
$('rc-elapsed').textContent = mmss(elapsedOf(run) || 0);
|
|
100
|
+
$('rc-clock').textContent = $('rc-elapsed').textContent;
|
|
93
101
|
}, 1000);
|
|
94
102
|
}
|
|
95
103
|
|
|
@@ -135,7 +143,7 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
135
143
|
$('rc-diff-files').innerHTML = (files || []).map(function (f) { return '<li title="' + esc(f) + '">' + esc(f) + '</li>'; }).join('');
|
|
136
144
|
$('rc-diff-files').hidden = !(files && files.length);
|
|
137
145
|
$('rc-diff-body').innerHTML = bodyHtml;
|
|
138
|
-
$('rc-diff-count').textContent = count == null ? '
|
|
146
|
+
$('rc-diff-count').textContent = count == null ? '-' : String(count);
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
function loadConsoleDiff(taskId) {
|
|
@@ -145,7 +153,7 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
145
153
|
return api('/api/pipeline/worktrees/diff?taskId=' + encodeURIComponent(taskId)).then(function (body) {
|
|
146
154
|
if (seq !== rc.diffSeq || rc.taskId !== taskId) return;
|
|
147
155
|
var files = Array.isArray(body.filesChanged) ? body.filesChanged : [];
|
|
148
|
-
var summary = '<code>' + esc(body.branch || '') + '</code
|
|
156
|
+
var summary = '<code>' + esc(body.branch || '') + '</code>, ' + (body.hasChanges ? files.length + ' uncommitted file' + (files.length === 1 ? '' : 's') : 'working tree clean');
|
|
149
157
|
setDiffState(summary, files, body.diff ? diffToHtml(body.diff) : '<span class="rc-empty">No uncommitted changes in this worktree yet.</span>', files.length);
|
|
150
158
|
}, function (e) {
|
|
151
159
|
if (seq !== rc.diffSeq || rc.taskId !== taskId) return;
|
|
@@ -191,4 +199,61 @@ export const consoleScript = String.raw ` // ─── Live runner console draw
|
|
|
191
199
|
return ['logs', 'diff', 'heal'].filter(function (name) { return !$('rc-tab-' + name).hidden; });
|
|
192
200
|
}
|
|
193
201
|
|
|
202
|
+
// Inspector header status: dot color follows the run state only.
|
|
203
|
+
function syncInspectorStatus(run) {
|
|
204
|
+
var task = rc.taskId ? taskById(rc.taskId) : null;
|
|
205
|
+
var bucket = Studio.status.runBucket(run) || (task ? Studio.status.bucket(task) : 'next');
|
|
206
|
+
var tone = { done: 'ok', stuck: 'err', running: 'run' }[bucket] || 'idle';
|
|
207
|
+
$('rc-status').setAttribute('data-tone', tone);
|
|
208
|
+
$('rc-status-text').textContent = Studio.status.word(bucket);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Below 1024px the inspector is a modal sheet over the content.
|
|
212
|
+
function inspectorIsSheet() {
|
|
213
|
+
return window.matchMedia && window.matchMedia('(max-width: 1023px)').matches;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Remembers the opener so closing hands focus back to it.
|
|
217
|
+
function rememberInspectorOpener() {
|
|
218
|
+
var drawer = $('runner-console-drawer');
|
|
219
|
+
var active = document.activeElement;
|
|
220
|
+
if (drawer.hidden && active && !drawer.contains(active)) rc.opener = active;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function applyInspectorMode() {
|
|
224
|
+
var drawer = $('runner-console-drawer');
|
|
225
|
+
var sheet = inspectorIsSheet() && !drawer.hidden;
|
|
226
|
+
if (sheet) drawer.setAttribute('aria-modal', 'true');
|
|
227
|
+
else drawer.removeAttribute('aria-modal');
|
|
228
|
+
drawer.setAttribute('role', sheet ? 'dialog' : 'region');
|
|
229
|
+
if ($('task-drawer').hidden) $('scrim').hidden = !sheet;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function restoreInspectorFocus() {
|
|
233
|
+
if ($('task-drawer').hidden) $('scrim').hidden = true;
|
|
234
|
+
var opener = rc.opener;
|
|
235
|
+
rc.opener = null;
|
|
236
|
+
if (opener && document.contains(opener) && opener.focus) opener.focus();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Keeps Tab inside the sheet while it is modal.
|
|
240
|
+
function trapInspectorFocus(e) {
|
|
241
|
+
var drawer = $('runner-console-drawer');
|
|
242
|
+
if (e.key !== 'Tab' || drawer.hidden || !inspectorIsSheet()) return;
|
|
243
|
+
var items = Array.prototype.filter.call(
|
|
244
|
+
drawer.querySelectorAll('button, [href], [tabindex]:not([tabindex="-1"]), textarea, input'),
|
|
245
|
+
function (el) { return !el.disabled && el.offsetParent !== null; });
|
|
246
|
+
if (!items.length) return;
|
|
247
|
+
var first = items[0], last = items[items.length - 1];
|
|
248
|
+
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
249
|
+
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
document.addEventListener('keydown', trapInspectorFocus);
|
|
253
|
+
document.addEventListener('click', function (e) {
|
|
254
|
+
var t = e.target && e.target.closest ? e.target.closest('#rc-open-diff') : null;
|
|
255
|
+
if (t) setConsoleTab('diff', true);
|
|
256
|
+
});
|
|
257
|
+
window.addEventListener('resize', applyInspectorMode);
|
|
258
|
+
|
|
194
259
|
`;
|
|
@@ -6,14 +6,14 @@ export const coreScript = String.raw `<script>
|
|
|
6
6
|
var $ = function (id) { return document.getElementById(id); };
|
|
7
7
|
|
|
8
8
|
var ICON = {
|
|
9
|
-
spark: '<svg class="icon t1-spark" width="14" height="14" viewBox="0 0
|
|
10
|
-
check: '<svg class="icon" width="12" height="12" viewBox="0 0
|
|
11
|
-
x: '<svg class="icon" width="12" height="12" viewBox="0 0
|
|
12
|
-
shield: '<svg class="icon" width="14" height="14" viewBox="0 0
|
|
13
|
-
play: '<svg class="icon" width="12" height="12" viewBox="0 0
|
|
14
|
-
alert: '<svg class="icon" width="28" height="28" viewBox="0 0
|
|
15
|
-
branch: '<svg class="icon" width="28" height="28" viewBox="0 0
|
|
16
|
-
gauge: '<svg class="icon" width="28" height="28" viewBox="0 0
|
|
9
|
+
spark: '<svg class="icon t1-spark" width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M197.58,129.06,146,110l-19-51.62a15.92,15.92,0,0,0-29.88,0L78,110l-51.62,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0L146,178l51.62-19a15.92,15.92,0,0,0,0-29.88ZM137,164.22a8,8,0,0,0-4.74,4.74L112,223.85,91.78,169A8,8,0,0,0,87,164.22L32.15,144,87,123.78A8,8,0,0,0,91.78,119L112,64.15,132.22,119a8,8,0,0,0,4.74,4.74L191.85,144ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"/></svg>',
|
|
10
|
+
check: '<svg class="icon" width="12" height="12" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"/></svg>',
|
|
11
|
+
x: '<svg class="icon" width="12" height="12" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/></svg>',
|
|
12
|
+
shield: '<svg class="icon" width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M208,40H48A16,16,0,0,0,32,56v56c0,52.72,25.52,84.67,46.93,102.19,23.06,18.86,46,25.26,47,25.53a8,8,0,0,0,4.2,0c1-.27,23.91-6.67,47-25.53C198.48,196.67,224,164.72,224,112V56A16,16,0,0,0,208,40Zm0,72c0,37.07-13.66,67.16-40.6,89.42A129.3,129.3,0,0,1,128,223.62a128.25,128.25,0,0,1-38.92-21.81C61.82,179.51,48,149.3,48,112l0-56,160,0ZM82.34,141.66a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35a8,8,0,0,1,11.32,11.32l-56,56a8,8,0,0,1-11.32,0Z"/></svg>',
|
|
13
|
+
play: '<svg class="icon" width="12" height="12" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"/></svg>',
|
|
14
|
+
alert: '<svg class="icon" width="28" height="28" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"/></svg>',
|
|
15
|
+
branch: '<svg class="icon" width="28" height="28" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M232,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H96a23.84,23.84,0,0,0-8,1.38V95a32,32,0,1,0-16,0v66a32,32,0,1,0,16,0V144a8,8,0,0,1,8-8h88a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,232,64ZM64,64A16,16,0,1,1,80,80,16,16,0,0,1,64,64ZM96,192a16,16,0,1,1-16-16A16,16,0,0,1,96,192ZM200,80a16,16,0,1,1,16-16A16,16,0,0,1,200,80Z"/></svg>',
|
|
16
|
+
gauge: '<svg class="icon" width="28" height="28" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M207.06,72.67A111.24,111.24,0,0,0,128,40h-.4C66.07,40.21,16,91,16,153.13V176a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V152A111.25,111.25,0,0,0,207.06,72.67ZM224,176H119.71l54.76-75.3a8,8,0,0,0-12.94-9.42L99.92,176H32V153.13c0-3.08.15-6.12.43-9.13H56a8,8,0,0,0,0-16H35.27c10.32-38.86,44-68.24,84.73-71.66V80a8,8,0,0,0,16,0V56.33A96.14,96.14,0,0,1,221,128H200a8,8,0,0,0,0,16h23.67c.21,2.65.33,5.31.33,8Z"/></svg>'
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
function formatBytes(n) {
|
|
@@ -28,8 +28,8 @@ export const detailViewScript = String.raw ` // ─── Task detail panel (pu
|
|
|
28
28
|
}
|
|
29
29
|
if (t.status === 'in_progress') {
|
|
30
30
|
var live = t.run && isRunActive(t.run);
|
|
31
|
-
return dBtn('task-logs', '
|
|
32
|
-
dBtn('task-abort', 'Stop', { danger: true, busy: b
|
|
31
|
+
return (t.run ? dBtn('task-logs', 'Watch live', { busy: b }) : '') +
|
|
32
|
+
(live ? dBtn('task-abort', 'Stop', { danger: true, busy: b }) : '');
|
|
33
33
|
}
|
|
34
34
|
if (t.status === 'pending' && !t.waitingOn.length) {
|
|
35
35
|
return dBtn('task-start', 'Start', { primary: true, busy: b }) + dBtn('task-dispatch', 'Dispatch', { busy: b });
|
|
@@ -47,7 +47,7 @@ export const detailViewScript = String.raw ` // ─── Task detail panel (pu
|
|
|
47
47
|
|
|
48
48
|
function detailFacts(t, model) {
|
|
49
49
|
var m = model.milestones.filter(function (x) { return x.id === t.milestoneId; })[0];
|
|
50
|
-
var ms = m ? '<button type="button" class="chip" data-ms="' + esc(m.id) + '"><span class="mono">' + esc(m.id) + '</span>' + esc(m.short) + '</button>' : '
|
|
50
|
+
var ms = m ? '<button type="button" class="chip" data-ms="' + esc(m.id) + '"><span class="mono">' + esc(m.id) + '</span>' + esc(m.short) + '</button>' : '-';
|
|
51
51
|
return '<dl class="kv"><dt>Milestone</dt><dd>' + ms + '</dd><dt>Agent</dt><dd>' + ui.agentChip(t.agent) + '</dd>' +
|
|
52
52
|
'<dt>Started</dt><dd class="num">' + esc(fmt.full(t.startT)) + '</dd><dt>Took</dt><dd class="num">' + detailTook(t) + '</dd>' +
|
|
53
53
|
'<dt>Est. cost</dt><dd class="num">' + esc(fmt.money(t.costUsd)) + '</dd></dl>';
|
|
@@ -73,7 +73,7 @@ export const detailViewScript = String.raw ` // ─── Task detail panel (pu
|
|
|
73
73
|
chipList('Needs first', t.deps.length ? t.deps.map(function (d) { return depChip(model, d); }).join('') : '<span class="faint">Nothing. It can start right away.</span>') +
|
|
74
74
|
chipList('Unblocks', t.children.length ? t.children.map(function (d) { return depChip(model, d); }).join('') : '<span class="faint">No later task depends on this.</span>') +
|
|
75
75
|
chipList('Files it may change', files) +
|
|
76
|
-
'<div><div class="dlabel">How it is checked</div><div class="code">' + esc(t.verify || 'No check command.') + '</div></div>' +
|
|
76
|
+
'<div><div class="dlabel">How it is checked</div><div class="code wrap">' + esc(t.verify || 'No check command.') + '</div></div>' +
|
|
77
77
|
'<div class="chips"><button type="button" class="btn" data-act="show-flow">' + ui.icon('flow') + 'Show in Flow</button></div></div>';
|
|
78
78
|
};
|
|
79
79
|
|
|
@@ -25,9 +25,9 @@ export const dispatchScript = String.raw ` // ─── Autonomous dispatch: PO
|
|
|
25
25
|
pipe.busy[key] = 'abort';
|
|
26
26
|
refreshUi([]);
|
|
27
27
|
postJson('/api/pipeline/tasks/abort', { taskId: taskId, reason: 'Aborted from Nativ Studio' }).then(function () {
|
|
28
|
-
toast('
|
|
28
|
+
toast('Stop signal sent to ' + taskId, 'ok');
|
|
29
29
|
}, function (e) {
|
|
30
|
-
toast('Could not
|
|
30
|
+
toast('Could not stop ' + taskId + ': ' + e.message);
|
|
31
31
|
}).then(function () {
|
|
32
32
|
delete pipe.busy[key];
|
|
33
33
|
return fetchPipeline(['status', 'tasks', 'runs']);
|
|
@@ -47,9 +47,9 @@ export const dispatchScript = String.raw ` // ─── Autonomous dispatch: PO
|
|
|
47
47
|
|
|
48
48
|
function confirmAbort(taskId) {
|
|
49
49
|
confirmDialog({
|
|
50
|
-
title: '
|
|
50
|
+
title: 'Stop agent run',
|
|
51
51
|
body: 'Terminate the Claude process tree for ' + taskId + '? The isolated worktree and its branch are left in place so the partial work can be inspected.',
|
|
52
|
-
confirmLabel: '
|
|
52
|
+
confirmLabel: 'Stop',
|
|
53
53
|
danger: true
|
|
54
54
|
}, function () { runAbort(taskId); });
|
|
55
55
|
}
|
|
@@ -147,4 +147,23 @@ export const dispatchScript = String.raw ` // ─── Autonomous dispatch: PO
|
|
|
147
147
|
runDispatch(id, opts);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// ─── Top bar: Dispatch next ────────────────────────────────────────────────
|
|
151
|
+
var nextBtn = $('btn-dispatch-next'), nextId = null, nextSeen = null;
|
|
152
|
+
function syncDispatchNext() {
|
|
153
|
+
var m = Studio.model;
|
|
154
|
+
if (!m) return;
|
|
155
|
+
var t = m.tasks.filter(function (x) { return Studio.status.isReady(x); })[0];
|
|
156
|
+
var key = t ? t.id : '';
|
|
157
|
+
if (key === nextSeen) return;
|
|
158
|
+
nextSeen = key;
|
|
159
|
+
nextId = t ? t.id : null;
|
|
160
|
+
nextBtn.hidden = !t;
|
|
161
|
+
if (!t) return;
|
|
162
|
+
$('dispatch-next-label').textContent = 'Dispatch ' + t.id;
|
|
163
|
+
nextBtn.title = 'Open the dispatch dialog for ' + t.id;
|
|
164
|
+
}
|
|
165
|
+
nextBtn.addEventListener('click', function () { if (nextId) openDispatchDialog(nextId); });
|
|
166
|
+
Studio.onPaint(syncDispatchNext);
|
|
167
|
+
syncDispatchNext();
|
|
168
|
+
|
|
150
169
|
`;
|
|
@@ -8,6 +8,17 @@ export const eventsToolsScript = String.raw ` // ─── Events: live runner
|
|
|
8
8
|
$('rc-clear').addEventListener('click', function () {
|
|
9
9
|
$('rc-body').innerHTML = '<span class="rc-empty">Console cleared. New output will stream in here.</span>';
|
|
10
10
|
});
|
|
11
|
+
function setMoreMenu(open) {
|
|
12
|
+
$('rc-more-menu').hidden = !open;
|
|
13
|
+
$('rc-more').setAttribute('aria-expanded', String(open));
|
|
14
|
+
}
|
|
15
|
+
$('rc-more').addEventListener('click', function () { setMoreMenu($('rc-more-menu').hidden); });
|
|
16
|
+
$('rc-more-menu').addEventListener('click', function (e) {
|
|
17
|
+
if (e.target.closest('#rc-open-diff')) setMoreMenu(false);
|
|
18
|
+
});
|
|
19
|
+
document.addEventListener('click', function (e) {
|
|
20
|
+
if (!$('rc-more-menu').hidden && !e.target.closest('.rc-more')) setMoreMenu(false);
|
|
21
|
+
});
|
|
11
22
|
$('rc-abort').addEventListener('click', function () { if (rc.taskId) confirmAbort(rc.taskId); });
|
|
12
23
|
document.querySelectorAll('.rc-tab').forEach(function (btn) {
|
|
13
24
|
btn.addEventListener('click', function () { setConsoleTab(btn.getAttribute('data-rc-tab')); });
|
|
@@ -81,7 +92,11 @@ export const eventsToolsScript = String.raw ` // ─── Events: live runner
|
|
|
81
92
|
$('rc-minimize').addEventListener('click', toggleConsoleMinimized);
|
|
82
93
|
$('rc-close').addEventListener('click', closeConsole);
|
|
83
94
|
$('runner-console-drawer').addEventListener('keydown', function (e) {
|
|
84
|
-
if (e.key
|
|
95
|
+
if (e.key !== 'Escape') return;
|
|
96
|
+
e.stopPropagation();
|
|
97
|
+
var opener = rc.opener;
|
|
98
|
+
closeConsole();
|
|
99
|
+
if (!(opener && document.contains(opener))) $('main').focus();
|
|
85
100
|
});
|
|
86
101
|
|
|
87
102
|
$('btn-confirm-ok').addEventListener('click', function () {
|
|
@@ -24,7 +24,34 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var BUCKETS = [['next', 'Up next'], ['running', 'Running'], ['done', 'Done'], ['stuck', 'Stuck']];
|
|
28
|
+
var BUCKET_WORD = {};
|
|
29
|
+
BUCKETS.forEach(function (b) { BUCKET_WORD[b[0]] = b[1]; });
|
|
30
|
+
var STATUS_BUCKET = { completed: 'done', in_progress: 'running', pending: 'next', blocked: 'stuck' };
|
|
31
|
+
var STATUS_LABEL = {};
|
|
32
|
+
Object.keys(STATUS_BUCKET).forEach(function (k) { STATUS_LABEL[k] = BUCKET_WORD[STATUS_BUCKET[k]]; });
|
|
33
|
+
var RUN_BUCKET = { spawning_worktree: 'running', running: 'running', verifying: 'running',
|
|
34
|
+
merging: 'running', completed: 'done', failed: 'stuck', aborted: 'next' };
|
|
35
|
+
|
|
36
|
+
var status = {
|
|
37
|
+
buckets: BUCKETS,
|
|
38
|
+
isReady: function (t) {
|
|
39
|
+
return t.status === 'pending' && (!!t.isAvailable || !(t.waitingOn || []).length);
|
|
40
|
+
},
|
|
41
|
+
bucket: function (t) {
|
|
42
|
+
if (t.status === 'completed') return 'done';
|
|
43
|
+
if (t.status === 'in_progress') return t.stale ? 'next' : 'running';
|
|
44
|
+
if (t.status === 'blocked') return 'stuck';
|
|
45
|
+
return 'next';
|
|
46
|
+
},
|
|
47
|
+
runBucket: function (run) { return run ? (RUN_BUCKET[run.status] || null) : null; },
|
|
48
|
+
word: function (key) { return BUCKET_WORD[key] || STATUS_LABEL[key] || 'Unknown'; },
|
|
49
|
+
waitText: function (t) {
|
|
50
|
+
if (t.status !== 'pending' || status.isReady(t)) return '';
|
|
51
|
+
var n = (t.waitingOn || []).length;
|
|
52
|
+
return n === 1 ? 'Waits for 1 task' : 'Waits for ' + n + ' tasks';
|
|
53
|
+
}
|
|
54
|
+
};
|
|
28
55
|
var AGENTS = {
|
|
29
56
|
'backend': ['Backend', '--ag-backend'],
|
|
30
57
|
'frontend': ['Frontend', '--ag-frontend'],
|
|
@@ -50,7 +77,7 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
50
77
|
|
|
51
78
|
var fmt = {
|
|
52
79
|
dur: function (ms) {
|
|
53
|
-
if (ms == null || isNaN(ms)) return '
|
|
80
|
+
if (ms == null || isNaN(ms)) return '-';
|
|
54
81
|
var s = Math.round(ms / 1000);
|
|
55
82
|
if (s < 60) return s + 's';
|
|
56
83
|
if (s < 3600) return Math.floor(s / 60) + 'm ' + pad2(s % 60) + 's';
|
|
@@ -70,20 +97,19 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
70
97
|
if (!t) return 'not recorded';
|
|
71
98
|
return new Date(t).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
72
99
|
},
|
|
73
|
-
money: function (v) { return v == null || isNaN(v) ? '
|
|
100
|
+
money: function (v) { return v == null || isNaN(v) ? '-' : '$' + Number(v).toFixed(2); }
|
|
74
101
|
};
|
|
75
102
|
|
|
76
103
|
/** Grounded spend is small per task: four decimals below a dollar. */
|
|
77
104
|
function usdSpend(n) {
|
|
78
|
-
if (n == null || isNaN(n)) return '
|
|
105
|
+
if (n == null || isNaN(n)) return '-';
|
|
79
106
|
n = Number(n);
|
|
80
107
|
return '$' + (n >= 1 ? n.toFixed(2) : n.toFixed(4));
|
|
81
108
|
}
|
|
82
109
|
|
|
83
|
-
/** Wraps inner SVG paths (
|
|
110
|
+
/** Wraps inner SVG paths (256-unit box, fill icon) in an svg element. */
|
|
84
111
|
function svgWrap(inner, width) {
|
|
85
|
-
return '<svg viewBox="0 0
|
|
86
|
-
'" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + (inner || '') + '</svg>';
|
|
112
|
+
return '<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true">' + (inner || '') + '</svg>';
|
|
87
113
|
}
|
|
88
114
|
function svgIcon(name, width) { return svgWrap(Studio.icons[name], width); }
|
|
89
115
|
|
|
@@ -119,7 +145,8 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
119
145
|
if (!model) return '';
|
|
120
146
|
var current = Studio.state.milestoneId;
|
|
121
147
|
var opts = model.milestones.slice().reverse().map(function (m) {
|
|
122
|
-
var
|
|
148
|
+
var count = m.done + '/' + m.total + (m.id === model.activeMilestoneId ? ', active' : '');
|
|
149
|
+
var text = m.id + ' ' + m.short + ' (' + count + ')';
|
|
123
150
|
return '<option value="' + esc(m.id) + '"' + (m.id === current ? ' selected' : '') + '>' + esc(text) + '</option>';
|
|
124
151
|
}).join('');
|
|
125
152
|
return '<select class="sel" data-ms-select aria-label="Milestone">' + opts + '</select>';
|
|
@@ -137,6 +164,7 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
137
164
|
|
|
138
165
|
Studio.fmt = fmt;
|
|
139
166
|
Studio.ui = ui;
|
|
167
|
+
Studio.status = status;
|
|
140
168
|
Studio.agentInfo = agentInfo;
|
|
141
169
|
Studio.statusLabel = function (status) { return STATUS_LABEL[status] || 'Unknown'; };
|
|
142
170
|
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Phosphor Regular (MIT) icon paths and status marks shared by the shell and pages.
|
|
2
2
|
export const ICON_PATHS = {
|
|
3
|
-
home: '<path d="
|
|
4
|
-
tasks: '<
|
|
5
|
-
flow: '<
|
|
6
|
-
team: '<
|
|
7
|
-
worktrees: '<
|
|
8
|
-
benchmarks: '<path d="
|
|
9
|
-
database: '<
|
|
10
|
-
search: '<
|
|
11
|
-
sun: '<
|
|
12
|
-
x: '<path d="
|
|
13
|
-
chev: '<path d="
|
|
3
|
+
home: '<path d="M219.31,108.68l-80-80a16,16,0,0,0-22.62,0l-80,80A15.87,15.87,0,0,0,32,120v96a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V160h32v56a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V120A15.87,15.87,0,0,0,219.31,108.68ZM208,208H160V152a8,8,0,0,0-8-8H104a8,8,0,0,0-8,8v56H48V120l80-80,80,80Z"/>',
|
|
4
|
+
tasks: '<path d="M224,128a8,8,0,0,1-8,8H128a8,8,0,0,1,0-16h88A8,8,0,0,1,224,128ZM128,72h88a8,8,0,0,0,0-16H128a8,8,0,0,0,0,16Zm88,112H128a8,8,0,0,0,0,16h88a8,8,0,0,0,0-16ZM82.34,42.34,56,68.69,45.66,58.34A8,8,0,0,0,34.34,69.66l16,16a8,8,0,0,0,11.32,0l32-32A8,8,0,0,0,82.34,42.34Zm0,64L56,132.69,45.66,122.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Zm0,64L56,196.69,45.66,186.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Z"/>',
|
|
5
|
+
flow: '<path d="M245.66,74.34l-32-32a8,8,0,0,0-11.32,11.32L220.69,72H208c-49.33,0-61.05,28.12-71.38,52.92-9.38,22.51-16.92,40.59-49.48,42.84a40,40,0,1,0,.1,16c43.26-2.65,54.34-29.15,64.14-52.69C161.41,107,169.33,88,208,88h12.69l-18.35,18.34a8,8,0,0,0,11.32,11.32l32-32A8,8,0,0,0,245.66,74.34ZM48,200a24,24,0,1,1,24-24A24,24,0,0,1,48,200Z"/>',
|
|
6
|
+
team: '<path d="M244.8,150.4a8,8,0,0,1-11.2-1.6A51.6,51.6,0,0,0,192,128a8,8,0,0,1-7.37-4.89,8,8,0,0,1,0-6.22A8,8,0,0,1,192,112a24,24,0,1,0-23.24-30,8,8,0,1,1-15.5-4A40,40,0,1,1,219,117.51a67.94,67.94,0,0,1,27.43,21.68A8,8,0,0,1,244.8,150.4ZM190.92,212a8,8,0,1,1-13.84,8,57,57,0,0,0-98.16,0,8,8,0,1,1-13.84-8,72.06,72.06,0,0,1,33.74-29.92,48,48,0,1,1,58.36,0A72.06,72.06,0,0,1,190.92,212ZM128,176a32,32,0,1,0-32-32A32,32,0,0,0,128,176ZM72,120a8,8,0,0,0-8-8A24,24,0,1,1,87.24,82a8,8,0,1,0,15.5-4A40,40,0,1,0,37,117.51,67.94,67.94,0,0,0,9.6,139.19a8,8,0,1,0,12.8,9.61A51.6,51.6,0,0,1,64,128,8,8,0,0,0,72,120Z"/>',
|
|
7
|
+
worktrees: '<path d="M232,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H96a23.84,23.84,0,0,0-8,1.38V95a32,32,0,1,0-16,0v66a32,32,0,1,0,16,0V144a8,8,0,0,1,8-8h88a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,232,64ZM64,64A16,16,0,1,1,80,80,16,16,0,0,1,64,64ZM96,192a16,16,0,1,1-16-16A16,16,0,0,1,96,192ZM200,80a16,16,0,1,1,16-16A16,16,0,0,1,200,80Z"/>',
|
|
8
|
+
benchmarks: '<path d="M207.06,72.67A111.24,111.24,0,0,0,128,40h-.4C66.07,40.21,16,91,16,153.13V176a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V152A111.25,111.25,0,0,0,207.06,72.67ZM224,176H119.71l54.76-75.3a8,8,0,0,0-12.94-9.42L99.92,176H32V153.13c0-3.08.15-6.12.43-9.13H56a8,8,0,0,0,0-16H35.27c10.32-38.86,44-68.24,84.73-71.66V80a8,8,0,0,0,16,0V56.33A96.14,96.14,0,0,1,221,128H200a8,8,0,0,0,0,16h23.67c.21,2.65.33,5.31.33,8Z"/>',
|
|
9
|
+
database: '<path d="M128,24C74.17,24,32,48.6,32,80v96c0,31.4,42.17,56,96,56s96-24.6,96-56V80C224,48.6,181.83,24,128,24Zm80,104c0,9.62-7.88,19.43-21.61,26.92C170.93,163.35,150.19,168,128,168s-42.93-4.65-58.39-13.08C55.88,147.43,48,137.62,48,128V111.36c17.06,15,46.23,24.64,80,24.64s62.94-9.68,80-24.64ZM69.61,53.08C85.07,44.65,105.81,40,128,40s42.93,4.65,58.39,13.08C200.12,60.57,208,70.38,208,80s-7.88,19.43-21.61,26.92C170.93,115.35,150.19,120,128,120s-42.93-4.65-58.39-13.08C55.88,99.43,48,89.62,48,80S55.88,60.57,69.61,53.08ZM186.39,202.92C170.93,211.35,150.19,216,128,216s-42.93-4.65-58.39-13.08C55.88,195.43,48,185.62,48,176V159.36c17.06,15,46.23,24.64,80,24.64s62.94-9.68,80-24.64V176C208,185.62,200.12,195.43,186.39,202.92Z"/>',
|
|
10
|
+
search: '<path d="M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z"/>',
|
|
11
|
+
sun: '<path d="M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"/>',
|
|
12
|
+
x: '<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/>',
|
|
13
|
+
chev: '<path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"/>',
|
|
14
|
+
play: '<path d="M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"/>',
|
|
15
|
+
stop: '<path d="M200,40H56A16,16,0,0,0,40,56V200a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Zm0,160H56V56H200V200Z"/>',
|
|
16
|
+
warning: '<path d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"/>',
|
|
17
|
+
check: '<path d="M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z"/>',
|
|
18
|
+
terminal: '<path d="M128,128a8,8,0,0,1-3,6.25l-40,32a8,8,0,1,1-10-12.5L107.19,128,75,102.25a8,8,0,1,1,10-12.5l40,32A8,8,0,0,1,128,128Zm48,24H136a8,8,0,0,0,0,16h40a8,8,0,0,0,0-16Zm56-96V200a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40H216A16,16,0,0,1,232,56ZM216,200V56H40V200H216Z"/>',
|
|
19
|
+
pause: '<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM112,96v64a8,8,0,0,1-16,0V96a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V96a8,8,0,0,1,16,0Z"/>',
|
|
20
|
+
moon: '<path d="M233.54,142.23a8,8,0,0,0-8-2,88.08,88.08,0,0,1-109.8-109.8,8,8,0,0,0-10-10,104.84,104.84,0,0,0-52.91,37A104,104,0,0,0,136,224a103.09,103.09,0,0,0,62.52-20.88,104.84,104.84,0,0,0,37-52.91A8,8,0,0,0,233.54,142.23ZM188.9,190.34A88,88,0,0,1,65.66,67.11a89,89,0,0,1,31.4-26A106,106,0,0,0,96,56,104.11,104.11,0,0,0,200,160a106,106,0,0,0,14.92-1.06A89,89,0,0,1,188.9,190.34Z"/>',
|
|
21
|
+
sidebar: '<path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM40,152H56a8,8,0,0,0,0-16H40V120H56a8,8,0,0,0,0-16H40V88H56a8,8,0,0,0,0-16H40V56H80V200H40Zm176,48H96V56H216V200Z"/>',
|
|
14
22
|
};
|
|
15
23
|
// Done check, up-next dashed ring and stuck alert; running is a pulsing dot.
|
|
16
24
|
export const ST_SVG = {
|
|
17
|
-
completed: '<svg viewBox="0 0
|
|
18
|
-
pending: '<svg viewBox="0 0
|
|
19
|
-
blocked: '<svg viewBox="0 0
|
|
25
|
+
completed: '<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z"/></svg>',
|
|
26
|
+
pending: '<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M96.26,37.05A8,8,0,0,1,102,27.29a104.11,104.11,0,0,1,52,0,8,8,0,0,1-2,15.75,8.15,8.15,0,0,1-2-.26,88.09,88.09,0,0,0-44,0A8,8,0,0,1,96.26,37.05ZM53.79,55.14a104.05,104.05,0,0,0-26,45,8,8,0,0,0,15.42,4.27,88,88,0,0,1,22-38.09A8,8,0,0,0,53.79,55.14ZM43.21,151.55a8,8,0,1,0-15.42,4.28,104.12,104.12,0,0,0,26,45,8,8,0,0,0,11.41-11.22A88.14,88.14,0,0,1,43.21,151.55ZM150,213.22a88,88,0,0,1-44,0,8,8,0,1,0-4,15.49,104.11,104.11,0,0,0,52,0,8,8,0,0,0-4-15.49ZM222.65,146a8,8,0,0,0-9.85,5.58,87.91,87.91,0,0,1-22,38.08,8,8,0,1,0,11.42,11.21,104,104,0,0,0,26-45A8,8,0,0,0,222.65,146Zm-9.86-41.54a8,8,0,0,0,15.42-4.28,104,104,0,0,0-26-45,8,8,0,1,0-11.41,11.22A88,88,0,0,1,212.79,104.45Z"/></svg>',
|
|
27
|
+
blocked: '<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"/></svg>',
|
|
20
28
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ICON_PATHS } from './icons.js';
|
|
2
|
-
|
|
2
|
+
import { wordmark } from './brand.js';
|
|
3
|
+
const svg = (name) => `<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true">${ICON_PATHS[name]}</svg>`;
|
|
3
4
|
// Document head close, sidebar frame and top bar (needs version and project name).
|
|
4
5
|
export function markupHead(version, projectName, projectHidden) {
|
|
5
6
|
return String.raw `</head>
|
|
@@ -8,34 +9,38 @@ export function markupHead(version, projectName, projectHidden) {
|
|
|
8
9
|
|
|
9
10
|
<div class="app">
|
|
10
11
|
<aside class="side" aria-label="Studio navigation">
|
|
11
|
-
<div class="brand"
|
|
12
|
+
<div class="brand">${wordmark()}${wordmark({ rail: true })}<b>Studio</b></div>
|
|
12
13
|
<div id="side-nav"></div>
|
|
13
14
|
<div class="side-foot">
|
|
14
15
|
<span class="foot-project" id="project-name"${projectHidden}>${projectName}</span>
|
|
15
16
|
<div id="side-foot"></div>
|
|
17
|
+
<span class="ver">v${version}</span>
|
|
16
18
|
</div>
|
|
17
19
|
</aside>
|
|
18
20
|
|
|
19
21
|
<div class="main">
|
|
20
22
|
<header class="top">
|
|
21
23
|
<span class="crumb">Studio / <b id="crumb-view">Home</b></span>
|
|
24
|
+
<span class="spacer" aria-hidden="true"></span>
|
|
22
25
|
<div class="top-right">
|
|
23
|
-
<button class="btn" id="btn-find" type="button" aria-keyshortcuts="Control+K Meta+K">${svg('search')}<span>Find task</span><span class="kbd">Ctrl
|
|
26
|
+
<button class="btn" id="btn-find" type="button" aria-keyshortcuts="Control+K Meta+K">${svg('search')}<span>Find task</span><span class="kbd">Ctrl+K</span></button>
|
|
27
|
+
<button class="btn ghost" id="btn-theme" type="button" title="Switch light or dark" aria-label="Switch light or dark"><span class="ic-sun">${svg('sun')}</span><span class="ic-moon">${svg('moon')}</span></button>
|
|
28
|
+
<button class="btn primary" id="btn-dispatch-next" type="button" hidden>${svg('play')}<span id="dispatch-next-label">Dispatch</span></button>
|
|
24
29
|
<div class="t1" id="t1">
|
|
25
|
-
<button class="t1-chip" id="t1-chip" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="t1-menu" data-state="idle" title="Tier 1 AI Strategist"><svg class="icon t1-spark" width="14" height="14" viewBox="0 0
|
|
30
|
+
<button class="t1-chip" id="t1-chip" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="t1-menu" data-state="idle" title="Tier 1 AI Strategist"><svg class="icon t1-spark" width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M197.58,129.06,146,110l-19-51.62a15.92,15.92,0,0,0-29.88,0L78,110l-51.62,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0L146,178l51.62-19a15.92,15.92,0,0,0,0-29.88ZM137,164.22a8,8,0,0,0-4.74,4.74L112,223.85,91.78,169A8,8,0,0,0,87,164.22L32.15,144,87,123.78A8,8,0,0,0,91.78,119L112,64.15,132.22,119a8,8,0,0,0,4.74,4.74L191.85,144ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"/></svg><span class="t1-chip-label">Tier 1 AI:</span><span class="t1-chip-model" id="t1-chip-model">Gemini 3.8 Flash</span><svg class="icon t1-caret" width="12" height="12" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z"/></svg></button>
|
|
26
31
|
<div class="t1-menu" id="t1-menu" role="dialog" aria-label="Tier 1 AI Strategist" tabindex="-1" hidden>
|
|
27
32
|
<div class="t1-row"><span>Active model</span><code id="t1-model">gemini-3.8-flash</code></div>
|
|
28
33
|
<div class="t1-row"><span>Last evaluation</span><b id="t1-latency">No evaluations yet</b></div>
|
|
29
34
|
<div class="t1-row"><span>Gemini API key</span><b id="t1-key">Checking</b></div>
|
|
30
35
|
<div class="t1-row"><span id="t1-auto-label">Autonomous Auto-Triage</span><button class="t1-switch" id="t1-auto" type="button" role="switch" aria-checked="false" aria-labelledby="t1-auto-label" title="When on, fixes Tier 1 proves safe are applied without asking" disabled>OFF</button></div>
|
|
31
|
-
<p class="t1-policy"><svg class="icon" width="14" height="14" viewBox="0 0
|
|
36
|
+
<p class="t1-policy"><svg class="icon" width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M208,40H48A16,16,0,0,0,32,56v56c0,52.72,25.52,84.67,46.93,102.19,23.06,18.86,46,25.26,47,25.53a8,8,0,0,0,4.2,0c1-.27,23.91-6.67,47-25.53C198.48,196.67,224,164.72,224,112V56A16,16,0,0,0,208,40Zm0,72c0,37.07-13.66,67.16-40.6,89.42A129.3,129.3,0,0,1,128,223.62a128.25,128.25,0,0,1-38.92-21.81C61.82,179.51,48,149.3,48,112l0-56,160,0ZM82.34,141.66a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35a8,8,0,0,1,11.32,11.32l-56,56a8,8,0,0,1-11.32,0Z"/></svg>Always halts on destructive database operations & major API contract breaks.</p>
|
|
32
37
|
<dl class="t1-stats"><div><dt>Evaluated</dt><dd id="t1-evaluated">0</dd></div><div><dt>Auto-resolved</dt><dd id="t1-resolved">0</dd></div><div><dt>Human-escalated</dt><dd id="t1-human">0</dd></div></dl>
|
|
33
38
|
</div>
|
|
34
39
|
</div>
|
|
35
|
-
<button class="btn ghost" id="btn-theme" type="button" title="Switch light or dark" aria-label="Switch light or dark">${svg('sun')}</button>
|
|
36
40
|
<span class="live" id="live" data-state="connecting" role="status" aria-live="polite"><i class="live-dot" id="live-dot" aria-hidden="true"></i><span id="live-label">Connecting</span></span>
|
|
37
41
|
</div>
|
|
38
42
|
</header>
|
|
43
|
+
<div id="pulse" class="pulse-strip" aria-live="polite"></div>
|
|
39
44
|
<p class="banner" id="banner" role="alert" hidden>Studio lost contact with nativ. Retrying. <button class="btn small" id="banner-retry" type="button">Retry</button></p>
|
|
40
45
|
|
|
41
46
|
<main class="page" id="main" tabindex="-1">
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Inspector pane, dialogs and other shell overlays.
|
|
2
|
+
import { ICON_PATHS } from './icons.js';
|
|
3
|
+
// Phosphor icon in the shared 256-unit format.
|
|
4
|
+
const icon = (name) => '<svg class="icon" width="14" height="14" viewBox="0 0 256 256" fill="currentColor"'
|
|
5
|
+
+ ' aria-hidden="true">' + ICON_PATHS[name] + '</svg>';
|
|
2
6
|
export const markupTools = String.raw `</main>
|
|
3
7
|
</div>
|
|
4
8
|
</div>
|
|
@@ -8,21 +12,31 @@ export const markupTools = String.raw `</main>
|
|
|
8
12
|
|
|
9
13
|
<section id="runner-console-drawer" aria-labelledby="rc-task" hidden>
|
|
10
14
|
<header class="rc-head">
|
|
11
|
-
<
|
|
15
|
+
<div class="rc-id-row">
|
|
16
|
+
<code class="rc-task" id="rc-task"></code>
|
|
17
|
+
<span class="rc-status" id="rc-status"><span class="rc-dot" aria-hidden="true"></span><span id="rc-status-text">Up next</span></span>
|
|
18
|
+
<code class="rc-clock" id="rc-clock">00:00</code>
|
|
19
|
+
</div>
|
|
12
20
|
<span class="rc-title" id="rc-title"></span>
|
|
13
21
|
<ol class="rc-steps" id="rc-steps" aria-label="Runner lifecycle"></ol>
|
|
14
22
|
<div class="rc-controls">
|
|
15
|
-
<button class="rc-btn" type="button" id="rc-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
<button class="rc-btn danger" type="button" id="rc-abort" aria-label="Stop the running agent" hidden>Stop</button>
|
|
24
|
+
<span class="rc-more">
|
|
25
|
+
<button class="rc-btn" type="button" id="rc-more" aria-haspopup="true" aria-expanded="false" aria-controls="rc-more-menu">More</button>
|
|
26
|
+
<div class="rc-menu" id="rc-more-menu" hidden>
|
|
27
|
+
<button class="rc-btn" type="button" id="rc-open-diff" aria-label="Open the worktree diff">Open diff</button>
|
|
28
|
+
<button class="rc-btn" type="button" id="rc-clear" aria-label="Clear the console buffer">Clear</button>
|
|
29
|
+
<button class="rc-btn" type="button" id="rc-autoscroll" aria-pressed="true" aria-label="Toggle console auto-scroll">Auto-scroll</button>
|
|
30
|
+
</div>
|
|
31
|
+
</span>
|
|
32
|
+
<button class="rc-btn" type="button" id="rc-minimize" aria-expanded="true" aria-controls="rc-body" aria-label="Collapse the inspector">Collapse</button>
|
|
19
33
|
<button class="rc-btn" type="button" id="rc-close" aria-label="Close the runner console">Close</button>
|
|
20
34
|
</div>
|
|
21
35
|
</header>
|
|
22
36
|
<div class="rc-tabs" role="tablist" aria-label="Console views">
|
|
23
|
-
<button class="rc-tab" type="button" role="tab" id="rc-tab-logs" data-rc-tab="logs" aria-controls="rc-body" aria-selected="true"
|
|
24
|
-
<button class="rc-tab" type="button" role="tab" id="rc-tab-diff" data-rc-tab="diff" aria-controls="rc-diff" aria-selected="false" tabindex="-1"
|
|
25
|
-
<button class="rc-tab" type="button" role="tab" id="rc-tab-heal" data-rc-tab="heal" aria-controls="rc-heal" aria-selected="false" tabindex="-1" hidden
|
|
37
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-logs" data-rc-tab="logs" aria-controls="rc-body" aria-selected="true">${icon('terminal')}Live Logs</button>
|
|
38
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-diff" data-rc-tab="diff" aria-controls="rc-diff" aria-selected="false" tabindex="-1">${icon('worktrees')}Worktree Changes <span class="rc-count" id="rc-diff-count">-</span></button>
|
|
39
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-heal" data-rc-tab="heal" aria-controls="rc-heal" aria-selected="false" tabindex="-1" hidden>${icon('check')}Self-Healing Proposal <span class="rc-count is-proposal" id="rc-heal-count">1</span></button>
|
|
26
40
|
</div>
|
|
27
41
|
<pre class="rc-body" id="rc-body" role="log" aria-live="polite" aria-label="Runner output" tabindex="0"></pre>
|
|
28
42
|
<div class="rc-diff" id="rc-diff" role="tabpanel" aria-labelledby="rc-tab-diff" hidden>
|
|
@@ -34,12 +48,12 @@ export const markupTools = String.raw `</main>
|
|
|
34
48
|
<pre class="rc-diff-body" id="rc-diff-body" aria-label="Unified diff" tabindex="0"></pre>
|
|
35
49
|
</div>
|
|
36
50
|
<div class="rc-heal" id="rc-heal" role="tabpanel" aria-labelledby="rc-tab-heal" tabindex="0" hidden></div>
|
|
37
|
-
<footer class="rc-foot">
|
|
51
|
+
<footer class="rc-foot" id="rc-foot" hidden>
|
|
38
52
|
<span>Elapsed <strong id="rc-elapsed">00:00</strong></span>
|
|
39
|
-
<span>Output <strong id="rc-bytes">0 B</strong></span>
|
|
53
|
+
<span id="rc-bytes-wrap" hidden>Output <strong id="rc-bytes">0 B</strong></span>
|
|
40
54
|
<span id="rc-spend-wrap" hidden>Spend <strong id="rc-spend">$0.0000</strong></span>
|
|
41
55
|
<span id="rc-cache-wrap" hidden>Cache hit <strong id="rc-cache">0%</strong></span>
|
|
42
|
-
<span>Gatekeeper <strong id="rc-gate"
|
|
56
|
+
<span id="rc-gate-wrap" hidden>Gatekeeper <strong id="rc-gate"></strong></span>
|
|
43
57
|
<span id="rc-exit"></span>
|
|
44
58
|
</footer>
|
|
45
59
|
</section>
|
|
@@ -57,8 +71,8 @@ export const markupTools = String.raw `</main>
|
|
|
57
71
|
<fieldset class="choice-group">
|
|
58
72
|
<legend>Engine</legend>
|
|
59
73
|
<div class="engine-options">
|
|
60
|
-
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-native" value="native" checked
|
|
61
|
-
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-cli" value="cli"
|
|
74
|
+
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-native" value="native" checked>${icon('play')}<span><b>Native Engine</b><span>Direct API, Prompt Caching & Fast Streaming. Token spend is reported live.</span></span></label>
|
|
75
|
+
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-cli" value="cli">${icon('terminal')}<span><b>CLI Terminal Pairing</b><span>Interactive Claude Code in a terminal shell, driven by the command below.</span></span></label>
|
|
62
76
|
</div>
|
|
63
77
|
</fieldset>
|
|
64
78
|
<fieldset class="choice-group">
|
|
@@ -83,7 +97,7 @@ export const markupTools = String.raw `</main>
|
|
|
83
97
|
<p class="field-error" id="dispatch-error" aria-live="polite"></p>
|
|
84
98
|
<div class="modal-foot">
|
|
85
99
|
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
86
|
-
<button class="btn primary" type="button" id="btn-launch-agent" aria-keyshortcuts="Control+Enter"
|
|
100
|
+
<button class="btn primary" type="button" id="btn-launch-agent" aria-keyshortcuts="Control+Enter">${icon('play')}Launch Autonomous Runner <kbd>Ctrl+Enter</kbd></button>
|
|
87
101
|
</div>
|
|
88
102
|
</form>
|
|
89
103
|
</dialog>
|