@njeybe/nativ 2.5.1 → 2.7.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 +67 -0
- package/README.md +100 -5
- 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 +55 -11
- package/dist/commands/notify.d.ts +2 -0
- package/dist/commands/notify.js +25 -0
- package/dist/commands/session.d.ts +22 -0
- package/dist/commands/session.js +106 -0
- package/dist/commands/task/task-add.js +1 -1
- package/dist/commands/task/task-common.js +6 -6
- package/dist/commands/task/task-escalate.js +8 -10
- package/dist/commands/task/task-lifecycle.d.ts +7 -1
- package/dist/commands/task/task-lifecycle.js +30 -5
- package/dist/commands/task/task-query.d.ts +2 -0
- package/dist/commands/task/task-query.js +27 -12
- package/dist/commands/task/task-reclaim.d.ts +20 -0
- package/dist/commands/task/task-reclaim.js +87 -0
- package/dist/commands/task.d.ts +2 -0
- package/dist/commands/task.js +1 -0
- package/dist/commands/triage.js +3 -3
- package/dist/commands/update.js +46 -0
- package/dist/commands/validate.js +1 -0
- package/dist/commands/verify.js +21 -5
- package/dist/core/design-rules.d.ts +23 -0
- package/dist/core/design-rules.js +115 -0
- package/dist/core/enforcement.js +18 -17
- package/dist/core/harness-integrity.js +26 -7
- package/dist/core/lock-manager.d.ts +6 -0
- package/dist/core/lock-manager.js +50 -41
- package/dist/core/notify.d.ts +38 -0
- package/dist/core/notify.js +133 -0
- package/dist/core/profiles.js +7 -16
- package/dist/core/session-memory.d.ts +42 -0
- package/dist/core/session-memory.js +121 -0
- package/dist/core/setup/pm-playbook.d.ts +5 -0
- package/dist/core/setup/pm-playbook.js +26 -0
- package/dist/core/setup/session-context.js +35 -2
- package/dist/core/setup/setup-planner.js +2 -2
- package/dist/core/setup/types.d.ts +2 -0
- package/dist/core/setup/types.js +5 -1
- package/dist/core/task-claims.d.ts +15 -0
- package/dist/core/task-claims.js +32 -0
- package/dist/core/tier1-liaison.d.ts +1 -0
- package/dist/core/tier1-liaison.js +25 -27
- package/dist/core/verifier/output-digest.d.ts +19 -0
- package/dist/core/verifier/output-digest.js +48 -0
- package/dist/db/data-engine.js +33 -32
- package/dist/db/introspector.js +61 -60
- package/dist/db/sqlite.d.ts +3 -0
- package/dist/db/sqlite.js +10 -0
- package/dist/governor/circuit-breaker.js +12 -0
- package/dist/governor/patch-applier.d.ts +1 -0
- package/dist/governor/patch-applier.js +3 -7
- package/dist/index.js +40 -6
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +53 -14
- package/dist/providers/claude-api.js +3 -0
- package/dist/providers/gemini.js +4 -1
- package/dist/providers/registry.d.ts +6 -2
- package/dist/providers/registry.js +28 -16
- package/dist/providers/types.d.ts +4 -1
- package/dist/runner/agent-supervisor.js +2 -2
- package/dist/runner/cli-config.js +1 -1
- package/dist/scanner/types.d.ts +5 -1
- package/dist/scanner/types.js +7 -0
- package/dist/server/routes/task-routes.d.ts +2 -0
- package/dist/server/routes/triage-routes.js +3 -18
- package/dist/server/studio-ui/pages/benchmarks/styles.js +8 -5
- package/dist/server/studio-ui/pages/database/browser.js +1 -1
- package/dist/server/studio-ui/pages/database/connection.js +1 -1
- package/dist/server/studio-ui/pages/database/data-shell.js +5 -5
- package/dist/server/studio-ui/pages/database/drift.js +1 -1
- package/dist/server/studio-ui/pages/database/explorer.js +2 -2
- package/dist/server/studio-ui/pages/database/styles.js +5 -5
- package/dist/server/studio-ui/pages/flow/styles.js +3 -3
- package/dist/server/studio-ui/pages/home/script.js +110 -91
- package/dist/server/studio-ui/pages/home/styles.js +33 -45
- package/dist/server/studio-ui/pages/tasks/script.js +150 -3
- package/dist/server/studio-ui/pages/tasks/styles.js +63 -6
- package/dist/server/studio-ui/pages/team/script.js +49 -52
- package/dist/server/studio-ui/pages/team/styles.js +21 -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 +61 -2
- package/dist/server/studio-ui/shell/core.js +8 -8
- package/dist/server/studio-ui/shell/detail-view.js +1 -1
- package/dist/server/studio-ui/shell/dispatch.js +18 -0
- package/dist/server/studio-ui/shell/events-tools.js +5 -1
- package/dist/server/studio-ui/shell/format.js +5 -6
- 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 +19 -10
- package/dist/server/studio-ui/shell/paint.js +3 -0
- package/dist/server/studio-ui/shell/pipeline-state.js +1 -1
- 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 +67 -0
- package/dist/server/studio-ui/shell/router.js +25 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +6 -3
- package/dist/server/studio-ui/shell/toasts-format.js +4 -4
- package/dist/server/studio-ui/styles/console.js +33 -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 +24 -5
- 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 +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/architect.md +11 -12
- package/plugin/agents/explorer.md +1 -1
- package/plugin/agents/verifier.md +2 -2
- package/plugin/agents/worker.md +5 -7
- package/plugin/skills/nativ/SKILL.md +36 -49
- package/templates/AGENTS.md +36 -49
- package/templates/CLAUDE.md +1 -41
- package/templates/GEMINI.md +3 -2
- package/templates/claude-agents/architect.md +11 -12
- package/templates/claude-agents/explorer.md +1 -1
- package/templates/claude-agents/verifier.md +2 -2
- package/templates/claude-agents/worker.md +5 -7
- 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/api_contracts.json +66 -66
- package/templates/dot-ai/context.md +38 -38
- package/templates/dot-ai/db_schema.json +39 -39
- package/templates/dot-ai/subagents/architect.md +6 -0
- 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
|
@@ -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>';
|
|
@@ -147,4 +147,22 @@ 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 x.status === 'pending' && x.isAvailable; })[0];
|
|
156
|
+
var key = t ? t.id : '';
|
|
157
|
+
if (key === nextSeen) return;
|
|
158
|
+
nextSeen = key;
|
|
159
|
+
nextId = t ? t.id : null;
|
|
160
|
+
nextBtn.disabled = !t;
|
|
161
|
+
$('dispatch-next-label').textContent = t ? 'Dispatch ' + t.id : 'Nothing ready';
|
|
162
|
+
nextBtn.title = t ? 'Open the dispatch dialog for ' + t.id : 'No pending task has its dependencies met';
|
|
163
|
+
}
|
|
164
|
+
nextBtn.addEventListener('click', function () { if (nextId) openDispatchDialog(nextId); });
|
|
165
|
+
Studio.onPaint(syncDispatchNext);
|
|
166
|
+
syncDispatchNext();
|
|
167
|
+
|
|
150
168
|
`;
|
|
@@ -81,7 +81,11 @@ export const eventsToolsScript = String.raw ` // ─── Events: live runner
|
|
|
81
81
|
$('rc-minimize').addEventListener('click', toggleConsoleMinimized);
|
|
82
82
|
$('rc-close').addEventListener('click', closeConsole);
|
|
83
83
|
$('runner-console-drawer').addEventListener('keydown', function (e) {
|
|
84
|
-
if (e.key
|
|
84
|
+
if (e.key !== 'Escape') return;
|
|
85
|
+
e.stopPropagation();
|
|
86
|
+
var opener = rc.opener;
|
|
87
|
+
closeConsole();
|
|
88
|
+
if (!(opener && document.contains(opener))) $('main').focus();
|
|
85
89
|
});
|
|
86
90
|
|
|
87
91
|
$('btn-confirm-ok').addEventListener('click', function () {
|
|
@@ -50,7 +50,7 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
50
50
|
|
|
51
51
|
var fmt = {
|
|
52
52
|
dur: function (ms) {
|
|
53
|
-
if (ms == null || isNaN(ms)) return '
|
|
53
|
+
if (ms == null || isNaN(ms)) return '-';
|
|
54
54
|
var s = Math.round(ms / 1000);
|
|
55
55
|
if (s < 60) return s + 's';
|
|
56
56
|
if (s < 3600) return Math.floor(s / 60) + 'm ' + pad2(s % 60) + 's';
|
|
@@ -70,20 +70,19 @@ export const formatScript = String.raw ` // ─── Studio client core: state
|
|
|
70
70
|
if (!t) return 'not recorded';
|
|
71
71
|
return new Date(t).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
72
72
|
},
|
|
73
|
-
money: function (v) { return v == null || isNaN(v) ? '
|
|
73
|
+
money: function (v) { return v == null || isNaN(v) ? '-' : '$' + Number(v).toFixed(2); }
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
/** Grounded spend is small per task: four decimals below a dollar. */
|
|
77
77
|
function usdSpend(n) {
|
|
78
|
-
if (n == null || isNaN(n)) return '
|
|
78
|
+
if (n == null || isNaN(n)) return '-';
|
|
79
79
|
n = Number(n);
|
|
80
80
|
return '$' + (n >= 1 ? n.toFixed(2) : n.toFixed(4));
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/** Wraps inner SVG paths (
|
|
83
|
+
/** Wraps inner SVG paths (256-unit box, fill icon) in an svg element. */
|
|
84
84
|
function svgWrap(inner, width) {
|
|
85
|
-
return '<svg viewBox="0 0
|
|
86
|
-
'" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + (inner || '') + '</svg>';
|
|
85
|
+
return '<svg viewBox="0 0 256 256" fill="currentColor" aria-hidden="true">' + (inner || '') + '</svg>';
|
|
87
86
|
}
|
|
88
87
|
function svgIcon(name, width) { return svgWrap(Studio.icons[name], width); }
|
|
89
88
|
|
|
@@ -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" disabled title="Loading tasks">${svg('play')}<span id="dispatch-next-label">Nothing ready</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,26 @@ 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">Idle</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">
|
|
23
|
+
<button class="rc-btn danger" type="button" id="rc-abort" aria-label="Abort the running agent">Abort</button>
|
|
24
|
+
<button class="rc-btn" type="button" id="rc-open-diff" aria-label="Open the worktree diff">Open diff</button>
|
|
15
25
|
<button class="rc-btn" type="button" id="rc-autoscroll" aria-pressed="true" aria-label="Toggle console auto-scroll">Auto-scroll</button>
|
|
16
26
|
<button class="rc-btn" type="button" id="rc-clear" aria-label="Clear the console buffer">Clear</button>
|
|
17
|
-
<button class="rc-btn
|
|
18
|
-
<button class="rc-btn" type="button" id="rc-minimize" aria-expanded="true" aria-controls="rc-body">Minimize</button>
|
|
27
|
+
<button class="rc-btn" type="button" id="rc-minimize" aria-expanded="true" aria-controls="rc-body" aria-label="Collapse the inspector">Collapse</button>
|
|
19
28
|
<button class="rc-btn" type="button" id="rc-close" aria-label="Close the runner console">Close</button>
|
|
20
29
|
</div>
|
|
21
30
|
</header>
|
|
22
31
|
<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
|
|
32
|
+
<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>
|
|
33
|
+
<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>
|
|
34
|
+
<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
35
|
</div>
|
|
27
36
|
<pre class="rc-body" id="rc-body" role="log" aria-live="polite" aria-label="Runner output" tabindex="0"></pre>
|
|
28
37
|
<div class="rc-diff" id="rc-diff" role="tabpanel" aria-labelledby="rc-tab-diff" hidden>
|
|
@@ -57,8 +66,8 @@ export const markupTools = String.raw `</main>
|
|
|
57
66
|
<fieldset class="choice-group">
|
|
58
67
|
<legend>Engine</legend>
|
|
59
68
|
<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"
|
|
69
|
+
<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>
|
|
70
|
+
<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
71
|
</div>
|
|
63
72
|
</fieldset>
|
|
64
73
|
<fieldset class="choice-group">
|
|
@@ -83,7 +92,7 @@ export const markupTools = String.raw `</main>
|
|
|
83
92
|
<p class="field-error" id="dispatch-error" aria-live="polite"></p>
|
|
84
93
|
<div class="modal-foot">
|
|
85
94
|
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
86
|
-
<button class="btn primary" type="button" id="btn-launch-agent" aria-keyshortcuts="Control+Enter"
|
|
95
|
+
<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
96
|
</div>
|
|
88
97
|
</form>
|
|
89
98
|
</dialog>
|
|
@@ -79,7 +79,10 @@ export const paintScript = String.raw ` // ─── Painting ─────
|
|
|
79
79
|
if (foot.__html !== footHtml) { foot.innerHTML = footHtml; foot.__html = footHtml; }
|
|
80
80
|
var lost = !!(pipe.errors.tasks || pipe.errors.status) || live.mode === 'offline';
|
|
81
81
|
$('banner').hidden = !lost;
|
|
82
|
+
Studio.afterPaint.forEach(function (fn) { try { fn(); } catch (e) { /* one hook must not break painting */ } });
|
|
82
83
|
}
|
|
84
|
+
Studio.afterPaint = Studio.afterPaint || [];
|
|
85
|
+
Studio.onPaint = function (fn) { Studio.afterPaint.push(fn); };
|
|
83
86
|
|
|
84
87
|
/** One entry point after data or state changes: model, sidebar, current page, panel, palette. */
|
|
85
88
|
function refreshUi(parts) {
|
|
@@ -119,7 +119,7 @@ export const pipelineStateScript = String.raw ` // ─── Pipeline state ─
|
|
|
119
119
|
|
|
120
120
|
/** 1234 becomes "1.2k" so the sidebar badge stays small. */
|
|
121
121
|
function compactNum(n) {
|
|
122
|
-
if (!isFinite(n)) return '
|
|
122
|
+
if (!isFinite(n)) return '-';
|
|
123
123
|
if (n >= 1e6) return (n / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
|
|
124
124
|
if (n >= 1e3) return (n / 1e3).toFixed(1).replace(/\.0$/, '') + 'k';
|
|
125
125
|
return String(Math.round(n));
|
|
@@ -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,67 @@
|
|
|
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: 'blocked', label: 'blocked', n: s.blocked, tone: 'bad' },
|
|
10
|
+
{ key: 'decisions', label: 'decisions', n: s.decisions, tone: 'warn' }
|
|
11
|
+
];
|
|
12
|
+
counts.forEach(function (c) { c.zero = !c.n; });
|
|
13
|
+
return { kind: 'ready', ms: s.ms, counts: counts };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function pulseHtml(p) {
|
|
17
|
+
if (p.kind !== 'ready') {
|
|
18
|
+
return '<span class="pulse-note ' + p.kind + '">' + esc(p.text) + '</span>';
|
|
19
|
+
}
|
|
20
|
+
var out = '<span class="pulse-ms num">' + esc(p.ms) + '</span>';
|
|
21
|
+
p.counts.forEach(function (c) {
|
|
22
|
+
var tone = c.zero ? 'zero' : c.tone;
|
|
23
|
+
out += '<button type="button" class="pulse-item ' + tone + '" data-pulse="' + c.key + '">' +
|
|
24
|
+
(c.zero ? '' : '<span class="pdot"></span>') +
|
|
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.__html = html;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Studio.taskFilter ('running' or 'blocked') is read by the Tasks page when it opens.
|
|
56
|
+
if (pulseEl) pulseEl.addEventListener('click', function (e) {
|
|
57
|
+
var b = e.target.closest ? e.target.closest('[data-pulse]') : null;
|
|
58
|
+
if (!b) return;
|
|
59
|
+
var key = b.getAttribute('data-pulse');
|
|
60
|
+
if (key === 'decisions') { location.hash = '#home'; return; }
|
|
61
|
+
Studio.taskFilter = key;
|
|
62
|
+
location.hash = '#tasks';
|
|
63
|
+
});
|
|
64
|
+
Studio.onPaint(paintPulse);
|
|
65
|
+
paintPulse();
|
|
66
|
+
|
|
67
|
+
`;
|
|
@@ -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,7 +5,9 @@ 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(function (t) { return t.status === 'pending' && t.isAvailable; }).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
12
|
if (env.benchmarkText) badges.benchmarks = ['', env.benchmarkText];
|
|
11
13
|
return badges;
|
|
@@ -17,7 +19,8 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
17
19
|
var item = function (p) {
|
|
18
20
|
var b = badges[p.id];
|
|
19
21
|
return '<button type="button" class="nav-item" data-go="' + esc(p.id) + '"' +
|
|
20
|
-
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
22
|
+
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
23
|
+
' aria-label="' + esc(p.label) + '" title="' + esc(p.label) + '"' + '>' + ui.svg(p.icon) +
|
|
21
24
|
'<span class="nav-text">' + esc(p.label) + '</span>' +
|
|
22
25
|
(b ? '<span class="nav-badge' + (b[0] ? ' ' + b[0] : '') + '">' + esc(b[1]) + '</span>' : '') + '</button>';
|
|
23
26
|
};
|
|
@@ -32,7 +35,7 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
32
35
|
/** env = { root, branch }. */
|
|
33
36
|
Studio.sideFootHtml = function (env) {
|
|
34
37
|
return '<span>Workspace</span><span class="mono" id="sb-root" title="' + esc(env.root || '') + '">' +
|
|
35
|
-
esc(env.root || '
|
|
38
|
+
esc(env.root || '-') + '</span><span>branch <span class="mono" id="sb-branch-name">' + esc(env.branch || '-') + '</span></span>';
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
`;
|
|
@@ -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
|
`;
|
|
@@ -1,20 +1,37 @@
|
|
|
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; }
|
|
18
35
|
.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
36
|
.rc-btn:hover { background: color-mix(in srgb, var(--term-muted) 22%, transparent); }
|
|
20
37
|
.rc-btn:disabled { opacity: .45; cursor: not-allowed; }
|
|
@@ -22,7 +39,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
22
39
|
.rc-btn.danger { color: var(--term-text); border-color: var(--danger); }
|
|
23
40
|
.rc-btn.danger:hover { background: color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
24
41
|
.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; }
|
|
42
|
+
.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
43
|
.rc-body:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
27
44
|
.rc-empty { color: var(--term-muted); }
|
|
28
45
|
.rc-fg-muted { color: var(--term-muted); }
|
|
@@ -31,10 +48,10 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
31
48
|
.rc-fg-info { color: var(--accent); }
|
|
32
49
|
.rc-fg-danger { color: color-mix(in srgb, var(--danger) 55%, #fff); }
|
|
33
50
|
.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); }
|
|
51
|
+
.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
52
|
.rc-foot strong { font-family: var(--mono); font-weight: 600; color: var(--term-text); }
|
|
36
53
|
#runner-console-drawer.is-min .rc-tabs { display: none; }
|
|
37
|
-
.rc-tabs { display: flex; gap: 2px; padding: 0
|
|
54
|
+
.rc-tabs { display: flex; gap: 2px; padding: 0 10px; overflow-x: auto; border-bottom: 1px solid var(--line); }
|
|
38
55
|
.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
56
|
.rc-tab:hover { color: var(--term-text); }
|
|
40
57
|
.rc-tab[aria-selected="true"] { color: var(--term-text); border-bottom-color: var(--primary); }
|
|
@@ -80,4 +97,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
80
97
|
.heal-result.is-error { color: color-mix(in srgb, var(--danger) 55%, #fff); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
81
98
|
.heal-skel { height: 12px; margin: 8px 0; border-radius: 4px; background: var(--term-line); animation: blink 1.4s ease-in-out infinite; }
|
|
82
99
|
@media (max-width: 768px) { .heal-grid { grid-template-columns: 1fr; } }
|
|
100
|
+
@media (prefers-reduced-motion: reduce) {
|
|
101
|
+
#runner-console-drawer, #runner-console-drawer * { transition: none !important; animation: none !important; }
|
|
102
|
+
}
|
|
83
103
|
`;
|