@njeybe/nativ 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/README.md +15 -0
- package/dist/runner/agent-supervisor.d.ts +5 -3
- package/dist/runner/agent-supervisor.js +17 -12
- package/dist/server/studio-server.js +1 -130
- package/dist/server/studio-ui/document.d.ts +3 -0
- package/dist/server/studio-ui/document.js +22 -0
- package/dist/server/studio-ui/pages/benchmarks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/benchmarks/index.js +11 -0
- package/dist/server/studio-ui/pages/benchmarks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/script.js +104 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.js +30 -0
- package/dist/server/studio-ui/pages/database/browser.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/browser.js +326 -0
- package/dist/server/studio-ui/pages/database/connection.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/connection.js +158 -0
- package/dist/server/studio-ui/pages/database/data-shell.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/data-shell.js +165 -0
- package/dist/server/studio-ui/pages/database/drift.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/drift.js +301 -0
- package/dist/server/studio-ui/pages/database/events.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/events.js +231 -0
- package/dist/server/studio-ui/pages/database/explorer.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/explorer.js +183 -0
- package/dist/server/studio-ui/pages/database/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/index.js +28 -0
- package/dist/server/studio-ui/pages/database/markup.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/markup.js +32 -0
- package/dist/server/studio-ui/pages/database/state.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/state.js +57 -0
- package/dist/server/studio-ui/pages/database/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/styles.js +118 -0
- package/dist/server/studio-ui/pages/flow/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/flow/index.js +11 -0
- package/dist/server/studio-ui/pages/flow/layout.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/layout.js +105 -0
- package/dist/server/studio-ui/pages/flow/plan-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/plan-view.js +67 -0
- package/dist/server/studio-ui/pages/flow/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/script.js +61 -0
- package/dist/server/studio-ui/pages/flow/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/styles.js +59 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.js +95 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.js +92 -0
- package/dist/server/studio-ui/pages/home/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/home/index.js +11 -0
- package/dist/server/studio-ui/pages/home/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/script.js +160 -0
- package/dist/server/studio-ui/pages/home/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/styles.js +48 -0
- package/dist/server/studio-ui/pages/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/index.js +17 -0
- package/dist/server/studio-ui/pages/tasks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/tasks/index.js +11 -0
- package/dist/server/studio-ui/pages/tasks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/script.js +96 -0
- package/dist/server/studio-ui/pages/tasks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/styles.js +37 -0
- package/dist/server/studio-ui/pages/team/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/team/index.js +11 -0
- package/dist/server/studio-ui/pages/team/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/script.js +112 -0
- package/dist/server/studio-ui/pages/team/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/styles.js +22 -0
- package/dist/server/studio-ui/pages/types.d.ts +13 -0
- package/dist/server/studio-ui/pages/types.js +1 -0
- package/dist/server/studio-ui/pages/worktrees/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/worktrees/index.js +11 -0
- package/dist/server/studio-ui/pages/worktrees/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/script.js +104 -0
- package/dist/server/studio-ui/pages/worktrees/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/styles.js +15 -0
- package/dist/server/studio-ui/shell/actions.d.ts +1 -0
- package/dist/server/studio-ui/shell/actions.js +49 -0
- package/dist/server/studio-ui/shell/boot.d.ts +2 -0
- package/dist/server/studio-ui/shell/boot.js +13 -0
- package/dist/server/studio-ui/shell/console.d.ts +1 -0
- package/dist/server/studio-ui/shell/console.js +194 -0
- package/dist/server/studio-ui/shell/core.d.ts +1 -0
- package/dist/server/studio-ui/shell/core.js +50 -0
- package/dist/server/studio-ui/shell/detail-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail-view.js +80 -0
- package/dist/server/studio-ui/shell/detail.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail.js +83 -0
- package/dist/server/studio-ui/shell/dispatch.d.ts +1 -0
- package/dist/server/studio-ui/shell/dispatch.js +150 -0
- package/dist/server/studio-ui/shell/events-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/events-tools.js +94 -0
- package/dist/server/studio-ui/shell/format.d.ts +1 -0
- package/dist/server/studio-ui/shell/format.js +151 -0
- package/dist/server/studio-ui/shell/icons.d.ts +2 -0
- package/dist/server/studio-ui/shell/icons.js +20 -0
- package/dist/server/studio-ui/shell/markup-head.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-head.js +43 -0
- package/dist/server/studio-ui/shell/markup-panels.d.ts +2 -0
- package/dist/server/studio-ui/shell/markup-panels.js +7 -0
- package/dist/server/studio-ui/shell/markup-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-tools.js +222 -0
- package/dist/server/studio-ui/shell/model.d.ts +1 -0
- package/dist/server/studio-ui/shell/model.js +192 -0
- package/dist/server/studio-ui/shell/paint.d.ts +1 -0
- package/dist/server/studio-ui/shell/paint.js +154 -0
- package/dist/server/studio-ui/shell/palette-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette-view.js +60 -0
- package/dist/server/studio-ui/shell/palette.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette.js +80 -0
- package/dist/server/studio-ui/shell/pipeline-state.d.ts +1 -0
- package/dist/server/studio-ui/shell/pipeline-state.js +152 -0
- package/dist/server/studio-ui/shell/proposals.d.ts +1 -0
- package/dist/server/studio-ui/shell/proposals.js +197 -0
- package/dist/server/studio-ui/shell/pure.d.ts +3 -0
- package/dist/server/studio-ui/shell/pure.js +9 -0
- package/dist/server/studio-ui/shell/router.d.ts +1 -0
- package/dist/server/studio-ui/shell/router.js +95 -0
- package/dist/server/studio-ui/shell/sidebar-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +38 -0
- package/dist/server/studio-ui/shell/sync.d.ts +1 -0
- package/dist/server/studio-ui/shell/sync.js +120 -0
- package/dist/server/studio-ui/shell/toasts-format.d.ts +1 -0
- package/dist/server/studio-ui/shell/toasts-format.js +89 -0
- package/dist/server/studio-ui/shell/triage.d.ts +1 -0
- package/dist/server/studio-ui/shell/triage.js +210 -0
- package/dist/server/studio-ui/styles/console.d.ts +1 -0
- package/dist/server/studio-ui/styles/console.js +83 -0
- package/dist/server/studio-ui/styles/dialogs.d.ts +1 -0
- package/dist/server/studio-ui/styles/dialogs.js +118 -0
- package/dist/server/studio-ui/styles/responsive.d.ts +1 -0
- package/dist/server/studio-ui/styles/responsive.js +28 -0
- package/dist/server/studio-ui/styles/shell.d.ts +1 -0
- package/dist/server/studio-ui/styles/shell.js +117 -0
- package/dist/server/studio-ui/styles/strategist.d.ts +1 -0
- package/dist/server/studio-ui/styles/strategist.js +77 -0
- package/dist/server/studio-ui/styles/tokens-base.d.ts +1 -0
- package/dist/server/studio-ui/styles/tokens-base.js +131 -0
- package/dist/server/studio-ui.d.ts +1 -10
- package/dist/server/studio-ui.js +63 -5314
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// Runner console drawer and worktree diff tab.
|
|
2
|
+
export const consoleScript = String.raw ` // ─── Live runner console drawer ────────────────────────────────────────────
|
|
3
|
+
var RC_STEPS = ['Worktree', 'Claude', 'Verify', 'Merge'];
|
|
4
|
+
var RC_STAGE = { spawning_worktree: 0, running: 1, verifying: 2, merging: 3 };
|
|
5
|
+
var RC_MAX_NODES = 3000;
|
|
6
|
+
var rc = { taskId: null, autoscroll: true, minimized: false, stage: 0, ticker: null, backfilled: false, tab: 'logs', diffSeq: 0, diffTimer: null, heal: null };
|
|
7
|
+
|
|
8
|
+
/** Minimal SGR parser: escapes the chunk, then maps the colors agents actually emit. */
|
|
9
|
+
var ANSI_CLASS = {
|
|
10
|
+
'0': null, '39': null, '1': 'rc-bold', '2': 'rc-fg-muted', '90': 'rc-fg-muted',
|
|
11
|
+
'31': 'rc-fg-danger', '91': 'rc-fg-danger', '32': 'rc-fg-ok', '92': 'rc-fg-ok',
|
|
12
|
+
'33': 'rc-fg-warn', '93': 'rc-fg-warn', '34': 'rc-fg-info', '94': 'rc-fg-info',
|
|
13
|
+
'36': 'rc-fg-info', '96': 'rc-fg-info'
|
|
14
|
+
};
|
|
15
|
+
function ansiToHtml(text, fallbackClass) {
|
|
16
|
+
var out = '', open = 0, cls = fallbackClass || '';
|
|
17
|
+
var parts = String(text == null ? '' : text).split(/\x1b\[([0-9;]*)m/);
|
|
18
|
+
for (var i = 0; i < parts.length; i++) {
|
|
19
|
+
if (i % 2 === 1) {
|
|
20
|
+
var codes = parts[i].split(';');
|
|
21
|
+
for (var c = 0; c < codes.length; c++) {
|
|
22
|
+
var code = codes[c] || '0';
|
|
23
|
+
if (!Object.prototype.hasOwnProperty.call(ANSI_CLASS, code)) continue;
|
|
24
|
+
while (open > 0) { out += '</span>'; open--; }
|
|
25
|
+
cls = ANSI_CLASS[code] ? ANSI_CLASS[code] : (fallbackClass || '');
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Other CSI sequences (cursor moves, clears) carry no meaning in a log pane.
|
|
30
|
+
var chunk = parts[i].replace(/\x1b\[[0-9;?]*[A-Za-z]/g, '').replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, '');
|
|
31
|
+
if (!chunk) continue;
|
|
32
|
+
if (cls) { out += '<span class="' + cls + '">' + esc(chunk) + '</span>'; }
|
|
33
|
+
else out += esc(chunk);
|
|
34
|
+
}
|
|
35
|
+
while (open > 0) { out += '</span>'; open--; }
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function rcStepper(run) {
|
|
40
|
+
var status = run ? run.status : null;
|
|
41
|
+
var stage = RC_STAGE[status] != null ? RC_STAGE[status] : rc.stage;
|
|
42
|
+
var settled = !!status && !RUN_ACTIVE[status];
|
|
43
|
+
var failed = status === 'failed' || status === 'aborted';
|
|
44
|
+
if (RC_STAGE[status] != null) rc.stage = stage;
|
|
45
|
+
return RC_STEPS.map(function (label, i) {
|
|
46
|
+
var cls = 'rc-step';
|
|
47
|
+
// Never dispatched (e.g. opened from a proposal banner): no phase is active.
|
|
48
|
+
if (!status) return '<li class="' + cls + '">' + esc(label) + '</li>';
|
|
49
|
+
if (status === 'completed') cls += ' is-done';
|
|
50
|
+
else if (settled && failed) cls += i < stage ? ' is-done' : (i === stage ? ' is-failed' : '');
|
|
51
|
+
else if (i < stage) cls += ' is-done';
|
|
52
|
+
else if (i === stage) cls += ' is-active';
|
|
53
|
+
return '<li class="' + cls + '">' + esc(label) + '</li>';
|
|
54
|
+
}).join('<li class="rc-sep" aria-hidden="true">›</li>');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function syncConsole() {
|
|
58
|
+
var run = rc.taskId ? runFor(rc.taskId) : null;
|
|
59
|
+
var task = rc.taskId ? taskById(rc.taskId) : null;
|
|
60
|
+
$('rc-task').textContent = rc.taskId || '–';
|
|
61
|
+
$('rc-title').textContent = task ? task.title : '';
|
|
62
|
+
$('rc-steps').innerHTML = rcStepper(run);
|
|
63
|
+
$('rc-abort').disabled = !isRunActive(run);
|
|
64
|
+
$('rc-elapsed').textContent = mmss(elapsedOf(run) || 0);
|
|
65
|
+
$('rc-bytes').textContent = formatBytes((run && run.logBytes) || 0);
|
|
66
|
+
var gate = 'Idle';
|
|
67
|
+
if (run && run.verification) gate = run.verification.success ? 'Passed' : 'Failed';
|
|
68
|
+
else if (run && run.status === 'verifying') gate = 'Running';
|
|
69
|
+
$('rc-gate').textContent = gate;
|
|
70
|
+
// Native runs report grounded usage; cli runs have none to show.
|
|
71
|
+
var usage = run && run.usage;
|
|
72
|
+
$('rc-spend-wrap').hidden = !usage;
|
|
73
|
+
$('rc-cache-wrap').hidden = !usage;
|
|
74
|
+
if (usage) {
|
|
75
|
+
$('rc-spend').textContent = usdSpend(usage.costUsd);
|
|
76
|
+
$('rc-cache').textContent = Math.round((Number(usage.cacheHitRate) || 0) * 100) + '%';
|
|
77
|
+
}
|
|
78
|
+
var exit = '';
|
|
79
|
+
if (run && !isRunActive(run)) {
|
|
80
|
+
exit = RUN_LABEL[run.status] || run.status;
|
|
81
|
+
if (typeof run.exitCode === 'number') exit += ' (exit ' + run.exitCode + ')';
|
|
82
|
+
if (run.error) exit += ' · ' + run.error;
|
|
83
|
+
}
|
|
84
|
+
$('rc-exit').textContent = exit;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function rcTick() {
|
|
88
|
+
clearInterval(rc.ticker);
|
|
89
|
+
rc.ticker = setInterval(function () {
|
|
90
|
+
var run = rc.taskId ? runFor(rc.taskId) : null;
|
|
91
|
+
if (!rc.taskId || !isRunActive(run)) { clearInterval(rc.ticker); rc.ticker = null; return; }
|
|
92
|
+
$('rc-elapsed').textContent = mmss(elapsedOf(run) || 0);
|
|
93
|
+
}, 1000);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function appendConsole(html) {
|
|
97
|
+
var body = $('rc-body');
|
|
98
|
+
var stick = rc.autoscroll || body.scrollTop + body.clientHeight >= body.scrollHeight - 4;
|
|
99
|
+
var frag = document.createElement('span');
|
|
100
|
+
frag.innerHTML = html;
|
|
101
|
+
body.appendChild(frag);
|
|
102
|
+
while (body.childElementCount > RC_MAX_NODES) body.removeChild(body.firstChild);
|
|
103
|
+
if (stick) body.scrollTop = body.scrollHeight;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function loadConsoleLogs(taskId) {
|
|
107
|
+
return api('/api/pipeline/tasks/logs?taskId=' + encodeURIComponent(taskId) + '&tailLines=500').then(function (body) {
|
|
108
|
+
if (rc.taskId !== taskId) return;
|
|
109
|
+
$('rc-body').innerHTML = body.log ? ansiToHtml(body.log) : '<span class="rc-empty">No output captured yet.</span>';
|
|
110
|
+
$('rc-body').scrollTop = $('rc-body').scrollHeight;
|
|
111
|
+
rc.backfilled = true;
|
|
112
|
+
syncConsole();
|
|
113
|
+
}, function () {
|
|
114
|
+
if (rc.taskId !== taskId) return;
|
|
115
|
+
$('rc-body').innerHTML = '<span class="rc-empty">Waiting for the runner to emit output…</span>';
|
|
116
|
+
rc.backfilled = true;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── Console tab 2: worktree git diff (GET /api/pipeline/worktrees/diff) ───
|
|
121
|
+
function diffToHtml(diff) {
|
|
122
|
+
return String(diff).split('\n').map(function (line) {
|
|
123
|
+
var cls = '';
|
|
124
|
+
if (/^(diff --git|\+\+\+ |--- )/.test(line)) cls = /^diff --git/.test(line) ? 'df-file' : 'df-meta';
|
|
125
|
+
else if (/^@@/.test(line)) cls = 'df-hunk';
|
|
126
|
+
else if (/^\+/.test(line)) cls = 'df-add';
|
|
127
|
+
else if (/^-/.test(line)) cls = 'df-del';
|
|
128
|
+
else if (/^(index |new file mode|deleted file mode|similarity |rename |Binary files)/.test(line)) cls = 'df-meta';
|
|
129
|
+
return cls ? '<span class="' + cls + '">' + esc(line) + '</span>' : esc(line) + '\n';
|
|
130
|
+
}).join('');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function setDiffState(summary, files, bodyHtml, count) {
|
|
134
|
+
$('rc-diff-summary').innerHTML = summary;
|
|
135
|
+
$('rc-diff-files').innerHTML = (files || []).map(function (f) { return '<li title="' + esc(f) + '">' + esc(f) + '</li>'; }).join('');
|
|
136
|
+
$('rc-diff-files').hidden = !(files && files.length);
|
|
137
|
+
$('rc-diff-body').innerHTML = bodyHtml;
|
|
138
|
+
$('rc-diff-count').textContent = count == null ? '–' : String(count);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function loadConsoleDiff(taskId) {
|
|
142
|
+
var seq = ++rc.diffSeq;
|
|
143
|
+
$('rc-diff-refresh').disabled = true;
|
|
144
|
+
if (!$('rc-diff-body').textContent) setDiffState('Loading worktree changes…', [], '<span class="rc-empty">Reading git status…</span>', null);
|
|
145
|
+
return api('/api/pipeline/worktrees/diff?taskId=' + encodeURIComponent(taskId)).then(function (body) {
|
|
146
|
+
if (seq !== rc.diffSeq || rc.taskId !== taskId) return;
|
|
147
|
+
var files = Array.isArray(body.filesChanged) ? body.filesChanged : [];
|
|
148
|
+
var summary = '<code>' + esc(body.branch || '') + '</code> · ' + (body.hasChanges ? files.length + ' uncommitted file' + (files.length === 1 ? '' : 's') : 'working tree clean');
|
|
149
|
+
setDiffState(summary, files, body.diff ? diffToHtml(body.diff) : '<span class="rc-empty">No uncommitted changes in this worktree yet.</span>', files.length);
|
|
150
|
+
}, function (e) {
|
|
151
|
+
if (seq !== rc.diffSeq || rc.taskId !== taskId) return;
|
|
152
|
+
var missing = e.code === 'WORKTREE_NOT_FOUND';
|
|
153
|
+
setDiffState(missing ? 'No isolated worktree' : 'Could not load the diff',
|
|
154
|
+
[], '<span class="rc-empty">' + esc(missing ? 'This task has no agent worktree. Dispatch it with Isolated Worktree on, or run nativ worktree create ' + taskId + '.' : e.message) + '</span>', null);
|
|
155
|
+
}).then(function () {
|
|
156
|
+
if (seq === rc.diffSeq) $('rc-diff-refresh').disabled = false;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Throttled refresh (at most every 2s) while an agent streams output or git state changes. */
|
|
161
|
+
function queueConsoleDiff() {
|
|
162
|
+
if (!rc.taskId || rc.tab !== 'diff' || rc.minimized || rc.diffTimer) return;
|
|
163
|
+
var id = rc.taskId;
|
|
164
|
+
rc.diffTimer = setTimeout(function () {
|
|
165
|
+
rc.diffTimer = null;
|
|
166
|
+
if (rc.taskId === id && rc.tab === 'diff') loadConsoleDiff(id);
|
|
167
|
+
}, 2000);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function setConsoleTab(tab, focus) {
|
|
171
|
+
if (tab === 'heal' && $('rc-tab-heal').hidden) tab = 'logs';
|
|
172
|
+
rc.tab = tab;
|
|
173
|
+
['logs', 'diff', 'heal'].forEach(function (name) {
|
|
174
|
+
var btn = $('rc-tab-' + name);
|
|
175
|
+
var on = name === tab;
|
|
176
|
+
btn.setAttribute('aria-selected', String(on));
|
|
177
|
+
btn.setAttribute('tabindex', on ? '0' : '-1');
|
|
178
|
+
});
|
|
179
|
+
$('rc-body').hidden = tab !== 'logs';
|
|
180
|
+
$('rc-diff').hidden = tab !== 'diff';
|
|
181
|
+
$('rc-heal').hidden = tab !== 'heal';
|
|
182
|
+
$('rc-autoscroll').hidden = tab !== 'logs';
|
|
183
|
+
$('rc-clear').hidden = tab !== 'logs';
|
|
184
|
+
if (tab === 'diff' && rc.taskId) loadConsoleDiff(rc.taskId);
|
|
185
|
+
if (tab === 'heal') renderHeal();
|
|
186
|
+
if (focus) $('rc-tab-' + tab).focus();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Console tabs in DOM order, skipping the proposal tab while it is hidden. */
|
|
190
|
+
function visibleConsoleTabs() {
|
|
191
|
+
return ['logs', 'diff', 'heal'].filter(function (name) { return !$('rc-tab-' + name).hidden; });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const coreScript: string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Script opening, DOM lookup, fetch helpers and the icons used by the kept tools.
|
|
2
|
+
export const coreScript = String.raw `<script>
|
|
3
|
+
(function () {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
var $ = function (id) { return document.getElementById(id); };
|
|
7
|
+
|
|
8
|
+
var ICON = {
|
|
9
|
+
spark: '<svg class="icon t1-spark" width="14" height="14" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 1.5l1.6 4.9 4.9 1.6-4.9 1.6L8 14.5l-1.6-4.9L1.5 8l4.9-1.6z"/></svg>',
|
|
10
|
+
check: '<svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>',
|
|
11
|
+
x: '<svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7"/></svg>',
|
|
12
|
+
shield: '<svg class="icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 1.8l5.2 2.1v3.7c0 3.1-2.2 5.6-5.2 6.6-3-1-5.2-3.5-5.2-6.6V3.9z"/><path d="M5.6 8.1l1.7 1.7 3.2-3.3"/></svg>',
|
|
13
|
+
play: '<svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M4.5 2.8v10.4L13 8z"/></svg>',
|
|
14
|
+
alert: '<svg class="icon" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7.5v5.5M12 16.5v.01"/></svg>',
|
|
15
|
+
branch: '<svg class="icon" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="5" r="2"/><circle cx="6" cy="19" r="2"/><circle cx="18" cy="8" r="2"/><path d="M6 7v10M18 10c0 4-6 3-11.2 7.4"/></svg>',
|
|
16
|
+
gauge: '<svg class="icon" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M4 16a8 8 0 1 1 16 0"/><path d="M12 16l4-5"/></svg>'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function formatBytes(n) {
|
|
20
|
+
if (n == null) return 'unknown';
|
|
21
|
+
if (n < 1024) return n + ' B';
|
|
22
|
+
if (n < 1048576) return (n / 1024).toFixed(1) + ' KB';
|
|
23
|
+
return (n / 1048576).toFixed(2) + ' MB';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function api(path, options) {
|
|
27
|
+
return fetch(path, options).then(function (res) {
|
|
28
|
+
return res.json().catch(function () { return {}; }).then(function (body) {
|
|
29
|
+
// DB routes answer { error: { code, message } }; pipeline routes answer { ok: false, error: "..." }.
|
|
30
|
+
if (!res.ok || body.ok === false) {
|
|
31
|
+
var message = typeof body.error === 'string' ? body.error : (body.error && body.error.message) || body.message;
|
|
32
|
+
var err = new Error(message || ('Request failed (' + res.status + ')'));
|
|
33
|
+
err.code = (body.error && body.error.code) || body.code;
|
|
34
|
+
err.status = res.status;
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
return body;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function postJson(path, body) {
|
|
43
|
+
return api(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function openDialog(dlg) {
|
|
47
|
+
if (typeof dlg.showModal === 'function') dlg.showModal(); else dlg.setAttribute('open', '');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const detailViewScript: string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Pure task detail panel markup: sections and actions depend on the task status.
|
|
2
|
+
export const detailViewScript = String.raw ` // ─── Task detail panel (pure) ───────────────────────────────────────────────
|
|
3
|
+
var BUSY_LABEL = { 'task-start': 'Starting…', 'task-dispatch': 'Dispatching…', 'task-abort': 'Stopping…', 'task-ask': 'Asking…' };
|
|
4
|
+
|
|
5
|
+
function dBtn(act, label, opts) {
|
|
6
|
+
opts = opts || {};
|
|
7
|
+
var busy = opts.busy === act;
|
|
8
|
+
var off = opts.disabled || (opts.busy && !busy);
|
|
9
|
+
return '<button type="button" class="btn' + (opts.primary ? ' primary' : '') + (opts.danger ? ' danger' : '') + '" data-act="' + act + '"' +
|
|
10
|
+
(off || busy ? ' disabled' : '') + (opts.title ? ' title="' + esc(opts.title) + '"' : '') + '>' +
|
|
11
|
+
(busy ? '<span class="spinner" aria-hidden="true"></span>' + BUSY_LABEL[act] : esc(label)) + '</button>';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function depChip(model, id) {
|
|
15
|
+
var x = model.byId[id];
|
|
16
|
+
if (!x) return '<span class="chip mono">' + esc(id) + '</span>';
|
|
17
|
+
return '<button type="button" class="chip" data-task="' + esc(id) + '">' + ui.statusIcon(x.status) +
|
|
18
|
+
'<span class="mono">' + esc(id) + '</span></button>';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function detailActions(t, env) {
|
|
22
|
+
var b = env.busy ? 'task-' + env.busy : null;
|
|
23
|
+
if (t.status === 'blocked') {
|
|
24
|
+
var out = dBtn('task-output', 'Show check output', { primary: true, busy: b }) + dBtn('task-start', 'Try again', { busy: b });
|
|
25
|
+
if (t.hasProposal) return out + dBtn('task-proposal', 'Review proposal', { busy: b });
|
|
26
|
+
if (t.escalation) out += dBtn('task-ask', 'Ask the architect', { busy: env.triaging ? 'task-ask' : b });
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
if (t.status === 'in_progress') {
|
|
30
|
+
var live = t.run && isRunActive(t.run);
|
|
31
|
+
return dBtn('task-logs', 'Open live logs', { busy: b }) +
|
|
32
|
+
dBtn('task-abort', 'Stop', { danger: true, busy: b, disabled: !live, title: live ? '' : 'No runner is attached to this task' });
|
|
33
|
+
}
|
|
34
|
+
if (t.status === 'pending' && !t.waitingOn.length) {
|
|
35
|
+
return dBtn('task-start', 'Start', { primary: true, busy: b }) + dBtn('task-dispatch', 'Dispatch', { busy: b });
|
|
36
|
+
}
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function detailTook(t) {
|
|
41
|
+
if (t.status === 'in_progress' && t.startT) {
|
|
42
|
+
return '<span data-since="' + t.startT + '">' + fmt.dur(Studio.now() - t.startT) + '</span> so far';
|
|
43
|
+
}
|
|
44
|
+
var check = t.checkMs ? ' <span class="faint">(check ' + fmt.dur(t.checkMs) + ')</span>' : '';
|
|
45
|
+
return fmt.dur(t.durationMs) + check;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function detailFacts(t, model) {
|
|
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>' : '–';
|
|
51
|
+
return '<dl class="kv"><dt>Milestone</dt><dd>' + ms + '</dd><dt>Agent</dt><dd>' + ui.agentChip(t.agent) + '</dd>' +
|
|
52
|
+
'<dt>Started</dt><dd class="num">' + esc(fmt.full(t.startT)) + '</dd><dt>Took</dt><dd class="num">' + detailTook(t) + '</dd>' +
|
|
53
|
+
'<dt>Est. cost</dt><dd class="num">' + esc(fmt.money(t.costUsd)) + '</dd></dl>';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function chipList(label, html) { return '<div><div class="dlabel">' + label + '</div><div class="chips">' + html + '</div></div>'; }
|
|
57
|
+
|
|
58
|
+
/** env = { busy: running action key or null, triaging: bool }. Returns the drawer content. */
|
|
59
|
+
Studio.detailHtml = function (id, env) {
|
|
60
|
+
env = env || {};
|
|
61
|
+
var model = Studio.model, t = model && model.byId[id];
|
|
62
|
+
if (!t) return '';
|
|
63
|
+
var reason = t.status === 'blocked'
|
|
64
|
+
? '<div class="reason">' + esc(t.reason || 'Paused after ' + (t.attempt || t.maxAttempts) + ' of ' + t.maxAttempts + ' attempts.') + '</div>' : '';
|
|
65
|
+
var step = t.status === 'in_progress'
|
|
66
|
+
? '<div><div class="dlabel">Latest step</div><div class="code wrap">' + esc(t.latestLog || 'No output yet.') + '</div></div>' : '';
|
|
67
|
+
var actions = detailActions(t, env);
|
|
68
|
+
var files = t.files.map(function (f) { return '<span class="chip mono">' + esc(f) + '</span>'; }).join('') || '<span class="faint">None listed.</span>';
|
|
69
|
+
return '<div class="drawer-head">' + ui.statusIcon(t.status) + '<span class="mono faint">' + esc(t.id) + '</span>' +
|
|
70
|
+
ui.pill(t.status) + '<button type="button" class="btn ghost close" data-act="close-detail" aria-label="Close">' + ui.icon('x') + '</button></div>' +
|
|
71
|
+
'<div class="drawer-body"><h3>' + esc(t.title) + '</h3>' + reason + (actions ? '<div class="chips">' + actions + '</div>' : '') + step +
|
|
72
|
+
detailFacts(t, model) +
|
|
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
|
+
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
|
+
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>' +
|
|
77
|
+
'<div class="chips"><button type="button" class="btn" data-act="show-flow">' + ui.icon('flow') + 'Show in Flow</button></div></div>';
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const detailScript: string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Task detail panel: opens from any data-task, closes with Esc, returns focus to its opener.
|
|
2
|
+
export const detailScript = String.raw ` // ─── Task detail panel ─────────────────────────────────────────────────────
|
|
3
|
+
var detail = { opener: null, html: '' };
|
|
4
|
+
|
|
5
|
+
function detailEnv(id) {
|
|
6
|
+
var esc1 = escalationFor(id);
|
|
7
|
+
return { busy: Studio.busyAction(id), triaging: !!(esc1 && pipe.triageRunning[esc1.id]) };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function showDetail(id) {
|
|
11
|
+
var drawer = $('task-drawer');
|
|
12
|
+
var html = Studio.detailHtml(id, detailEnv(id));
|
|
13
|
+
var memo = focusMemo(drawer);
|
|
14
|
+
if (html !== detail.html) { drawer.innerHTML = html; detail.html = html; restoreFocus(drawer, memo); }
|
|
15
|
+
drawer.hidden = false;
|
|
16
|
+
$('scrim').hidden = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function openDetail(id) {
|
|
20
|
+
if (!Studio.model || !Studio.model.byId[id]) return;
|
|
21
|
+
if (!Studio.state.detailTaskId) detail.opener = document.activeElement;
|
|
22
|
+
Studio.state.detailTaskId = id;
|
|
23
|
+
showDetail(id);
|
|
24
|
+
if (!$('task-drawer').contains(document.activeElement)) {
|
|
25
|
+
var close = $('task-drawer').querySelector('[data-act="close-detail"]');
|
|
26
|
+
if (close) close.focus();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
Studio.openTask = openDetail;
|
|
30
|
+
|
|
31
|
+
/** Re-renders the open panel after a model change; closes it if the task disappeared. */
|
|
32
|
+
function refreshDetail() {
|
|
33
|
+
var id = Studio.state.detailTaskId;
|
|
34
|
+
if (!id) return;
|
|
35
|
+
if (!Studio.model || !Studio.model.byId[id]) closeDetail(false);
|
|
36
|
+
else showDetail(id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function closeDetail(quiet) {
|
|
40
|
+
var S = Studio.state;
|
|
41
|
+
var wasOpen = !!S.detailTaskId;
|
|
42
|
+
S.detailTaskId = null;
|
|
43
|
+
$('task-drawer').hidden = true;
|
|
44
|
+
$('scrim').hidden = true;
|
|
45
|
+
$('task-drawer').innerHTML = '';
|
|
46
|
+
detail.html = '';
|
|
47
|
+
var hadFocus = !!S.focusTaskId;
|
|
48
|
+
S.focusTaskId = null;
|
|
49
|
+
if (quiet) return;
|
|
50
|
+
if (hadFocus) repaintFor(null);
|
|
51
|
+
var opener = detail.opener;
|
|
52
|
+
detail.opener = null;
|
|
53
|
+
if (wasOpen && opener && document.body.contains(opener) && opener.focus) opener.focus();
|
|
54
|
+
}
|
|
55
|
+
Studio.closeDetail = function () { closeDetail(false); };
|
|
56
|
+
|
|
57
|
+
$('scrim').addEventListener('click', function () { closeDetail(false); });
|
|
58
|
+
$('task-drawer').addEventListener('click', function (e) {
|
|
59
|
+
var t = e.target;
|
|
60
|
+
var task = t.closest('[data-task]');
|
|
61
|
+
if (task) { openDetail(task.getAttribute('data-task')); return; }
|
|
62
|
+
var ms = t.closest('[data-ms]');
|
|
63
|
+
if (ms) { Studio.go('tasks', { milestoneId: ms.getAttribute('data-ms') }); return; }
|
|
64
|
+
var act = t.closest('[data-act]');
|
|
65
|
+
if (!act || act.disabled) return;
|
|
66
|
+
var name = act.getAttribute('data-act');
|
|
67
|
+
var id = Studio.state.detailTaskId;
|
|
68
|
+
if (name === 'close-detail') closeDetail(false);
|
|
69
|
+
else if (name === 'show-flow') Studio.taskAction('flow', id);
|
|
70
|
+
else if (name.indexOf('task-') === 0) Studio.taskAction(name.slice(5), id);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Keep Tab inside the panel while it is open.
|
|
74
|
+
$('task-drawer').addEventListener('keydown', function (e) {
|
|
75
|
+
if (e.key !== 'Tab') return;
|
|
76
|
+
var items = $('task-drawer').querySelectorAll('button:not([disabled]), [href], select, input');
|
|
77
|
+
if (!items.length) return;
|
|
78
|
+
var first = items[0], last = items[items.length - 1];
|
|
79
|
+
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
80
|
+
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const dispatchScript: string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Dispatch requests and the dispatch modal.
|
|
2
|
+
export const dispatchScript = String.raw ` // ─── Autonomous dispatch: POST /tasks/dispatch and /tasks/abort ────────────
|
|
3
|
+
function runDispatch(taskId, customOptions) {
|
|
4
|
+
var key = 'task:' + taskId;
|
|
5
|
+
if (pipe.busy[key]) return;
|
|
6
|
+
pipe.busy[key] = 'dispatch';
|
|
7
|
+
refreshUi([]);
|
|
8
|
+
var payload = Object.assign({ taskId: taskId }, customOptions || {});
|
|
9
|
+
postJson('/api/pipeline/tasks/dispatch', payload).then(function (body) {
|
|
10
|
+
upsertRun(body && body.run);
|
|
11
|
+
var engine = body && body.run && body.run.engine === 'native' ? 'native engine' : 'CLI runner';
|
|
12
|
+
toast('Dispatched ' + taskId + ' to the ' + engine, 'ok');
|
|
13
|
+
openConsole(taskId, true);
|
|
14
|
+
}, function (e) {
|
|
15
|
+
toast('Could not dispatch ' + taskId + ': ' + e.message);
|
|
16
|
+
}).then(function () {
|
|
17
|
+
delete pipe.busy[key];
|
|
18
|
+
return fetchPipeline(['status', 'tasks', 'runs', 'worktrees']);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function runAbort(taskId) {
|
|
23
|
+
var key = 'task:' + taskId;
|
|
24
|
+
if (pipe.busy[key]) return;
|
|
25
|
+
pipe.busy[key] = 'abort';
|
|
26
|
+
refreshUi([]);
|
|
27
|
+
postJson('/api/pipeline/tasks/abort', { taskId: taskId, reason: 'Aborted from Nativ Studio' }).then(function () {
|
|
28
|
+
toast('Abort signal sent to ' + taskId, 'ok');
|
|
29
|
+
}, function (e) {
|
|
30
|
+
toast('Could not abort ' + taskId + ': ' + e.message);
|
|
31
|
+
}).then(function () {
|
|
32
|
+
delete pipe.busy[key];
|
|
33
|
+
return fetchPipeline(['status', 'tasks', 'runs']);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var pendingConfirm = null;
|
|
38
|
+
function confirmDialog(opts, onConfirm) {
|
|
39
|
+
$('confirm-title').textContent = opts.title;
|
|
40
|
+
$('confirm-body').textContent = opts.body;
|
|
41
|
+
var ok = $('btn-confirm-ok');
|
|
42
|
+
ok.textContent = opts.confirmLabel;
|
|
43
|
+
ok.className = 'btn ' + (opts.danger ? 'danger-solid' : 'primary');
|
|
44
|
+
pendingConfirm = onConfirm;
|
|
45
|
+
openDialog($('confirm-dialog'));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function confirmAbort(taskId) {
|
|
49
|
+
confirmDialog({
|
|
50
|
+
title: 'Abort agent run',
|
|
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: 'Abort Run',
|
|
53
|
+
danger: true
|
|
54
|
+
}, function () { runAbort(taskId); });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ─── Intelligent dispatch modal (#dispatch-dialog) ─────────────────────────
|
|
58
|
+
var pendingDispatch = null;
|
|
59
|
+
|
|
60
|
+
/** Mirrors buildDefaultClaudeCommand() in agent-supervisor.ts so the preview matches what the server runs. */
|
|
61
|
+
function defaultClaudeCommand(t) {
|
|
62
|
+
// The task prompt goes to the agent on stdin, so it is not part of the command.
|
|
63
|
+
return 'claude -p --output-format stream-json --verbose ' +
|
|
64
|
+
'--permission-mode acceptEdits --settings ".nativ/runs/permissions/' + t.id + '.json"';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function syncDispatchSwitches() {
|
|
68
|
+
var isolated = $('dispatch-worktree').checked;
|
|
69
|
+
var merge = $('dispatch-merge');
|
|
70
|
+
merge.disabled = !isolated || !$('dispatch-verify-gate').checked;
|
|
71
|
+
if (merge.disabled) merge.checked = false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function checkedValue(name) {
|
|
75
|
+
var el = document.querySelector('input[name="' + name + '"]:checked');
|
|
76
|
+
return el ? el.value : '';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Current Claude models reject a fixed thinking budget, so the native engine maps it onto an
|
|
81
|
+
* effort level (same buckets as thinkingBudgetToEffort in agent-supervisor.ts). Say so here
|
|
82
|
+
* rather than implying an exact token cap.
|
|
83
|
+
*/
|
|
84
|
+
function budgetHint(engine, budget) {
|
|
85
|
+
if (engine === 'cli') {
|
|
86
|
+
return budget ? 'Passed to Claude Code as MAX_THINKING_TOKENS=' + budget + '.' : 'Claude Code chooses its own thinking budget.';
|
|
87
|
+
}
|
|
88
|
+
if (!budget) return 'Runs at low effort, the fastest setting (Claude Opus 5.5 cannot switch thinking off entirely).';
|
|
89
|
+
var effort = budget <= 2048 ? 'medium' : budget <= 8192 ? 'high' : budget <= 32768 ? 'xhigh' : 'max';
|
|
90
|
+
return 'Runs at ' + effort + ' effort: the native engine maps token budgets onto effort levels.';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function syncDispatchEngine() {
|
|
94
|
+
var engine = checkedValue('dispatch-engine') || 'native';
|
|
95
|
+
$('dispatch-command-field').hidden = engine !== 'cli';
|
|
96
|
+
$('dispatch-budget-hint').textContent = budgetHint(engine, Number(checkedValue('dispatch-budget')) || 0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function openDispatchDialog(taskId) {
|
|
100
|
+
var t = taskById(taskId);
|
|
101
|
+
if (!t) { runDispatch(taskId); return; }
|
|
102
|
+
var files = t.targetFiles || [];
|
|
103
|
+
pendingDispatch = { taskId: t.id, preview: defaultClaudeCommand(t) };
|
|
104
|
+
$('dispatch-task-id').textContent = t.id;
|
|
105
|
+
$('dispatch-agent').textContent = t.assignedSubagent || 'unassigned';
|
|
106
|
+
$('dispatch-task-title').textContent = t.title || '';
|
|
107
|
+
$('dispatch-files').innerHTML = files.map(function (f) { return '<li class="file" title="' + esc(f) + '">' + esc(f) + '</li>'; }).join('');
|
|
108
|
+
$('dispatch-files').hidden = !files.length;
|
|
109
|
+
$('dispatch-verify').innerHTML = t.verificationCommand ? '<span class="cmd-label">Test command: </span>' + esc(t.verificationCommand) : 'no test command';
|
|
110
|
+
$('dispatch-command').value = pendingDispatch.preview;
|
|
111
|
+
$('dispatch-engine-native').checked = true;
|
|
112
|
+
$('dispatch-budget-none').checked = true;
|
|
113
|
+
syncDispatchEngine();
|
|
114
|
+
$('dispatch-worktree').checked = true;
|
|
115
|
+
$('dispatch-verify-gate').checked = !!t.verificationCommand;
|
|
116
|
+
$('dispatch-verify-gate').disabled = !t.verificationCommand;
|
|
117
|
+
$('dispatch-merge').checked = false;
|
|
118
|
+
$('dispatch-error').textContent = '';
|
|
119
|
+
syncDispatchSwitches();
|
|
120
|
+
openDialog($('dispatch-dialog'));
|
|
121
|
+
$('btn-launch-agent').focus();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function launchDispatch() {
|
|
125
|
+
if (!pendingDispatch) return;
|
|
126
|
+
var engine = checkedValue('dispatch-engine') || 'native';
|
|
127
|
+
var budget = Number(checkedValue('dispatch-budget')) || 0;
|
|
128
|
+
var command = $('dispatch-command').value.trim();
|
|
129
|
+
if (engine === 'cli' && !command) {
|
|
130
|
+
$('dispatch-error').textContent = 'Enter a runner command, or reopen the dialog to restore the generated one.';
|
|
131
|
+
$('dispatch-command').focus();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
var opts = {
|
|
135
|
+
runnerEngine: engine,
|
|
136
|
+
useWorktree: $('dispatch-worktree').checked,
|
|
137
|
+
verify: $('dispatch-verify-gate').checked,
|
|
138
|
+
autoMerge: $('dispatch-merge').checked
|
|
139
|
+
};
|
|
140
|
+
// Always sent: 0 ("None") asks for the least thinking, which differs from leaving the model default.
|
|
141
|
+
opts.thinkingBudget = budget;
|
|
142
|
+
// An untouched preview is the server's own default, which may be overridden by NATIV_RUNNER_COMMAND.
|
|
143
|
+
if (engine === 'cli' && command !== pendingDispatch.preview) opts.runnerCommand = command;
|
|
144
|
+
var id = pendingDispatch.taskId;
|
|
145
|
+
pendingDispatch = null;
|
|
146
|
+
$('dispatch-dialog').close();
|
|
147
|
+
runDispatch(id, opts);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const eventsToolsScript: string;
|