@north-light/crouter 0.3.158 → 0.3.160
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/dist/api/dto/nodes.d.ts +3 -0
- package/dist/builtin-memory/internal/INDEX.md +1 -0
- package/dist/builtin-memory/internal/storage-tiers.md +2 -0
- package/dist/builtin-memory/internal/workflow-codification.md +82 -0
- package/dist/clients/attach/__tests__/bash-call-width.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/bash-call-width.test.js +38 -0
- package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +20 -0
- package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +3 -1
- package/dist/clients/attach/chrome/bash-jobs.d.ts +5 -8
- package/dist/clients/attach/chrome/bash-jobs.js +20 -32
- package/dist/clients/attach/chrome/canvas-panels.js +10 -3
- package/dist/clients/attach/chrome/roster.d.ts +10 -4
- package/dist/clients/attach/chrome/roster.js +96 -36
- package/dist/clients/attach/input/controller.d.ts +3 -0
- package/dist/clients/attach/input/controller.js +1 -0
- package/dist/clients/attach/render/assistant-message.d.ts +13 -0
- package/dist/clients/attach/render/assistant-message.js +55 -0
- package/dist/clients/attach/render/chat-view.d.ts +29 -0
- package/dist/clients/attach/render/chat-view.js +233 -12
- package/dist/clients/attach/render/context-message.js +1 -1
- package/dist/clients/attach/render/edit-diff.js +20 -1
- package/dist/clients/attach/render/tool-calls.d.ts +32 -0
- package/dist/clients/attach/render/tool-calls.js +251 -0
- package/dist/clients/attach/session/input-wiring.d.ts +3 -0
- package/dist/clients/attach/session/input-wiring.js +3 -0
- package/dist/clients/attach/slash/dispatch.d.ts +4 -0
- package/dist/clients/attach/slash/dispatch.js +8 -0
- package/dist/clients/attach/viewer.js +568 -566
- package/dist/commands/cron.js +2 -2
- package/dist/commands/node.js +141 -3
- package/dist/commands/search.js +1 -1
- package/dist/commands/surface-inspect.js +4 -3
- package/dist/commands/sys/config.js +10 -2
- package/dist/commands/sys/doctor.js +22 -1
- package/dist/commands/sys/setup-core.d.ts +5 -1
- package/dist/commands/sys/setup-core.js +16 -2
- package/dist/commands/sys/setup-wizard.d.ts +11 -0
- package/dist/commands/sys/setup-wizard.js +111 -6
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +5 -3
- package/dist/core/__tests__/tmux-surface.test.js +5 -2
- package/dist/core/bash-jobs.d.ts +11 -0
- package/dist/core/bash-jobs.js +41 -1
- package/dist/core/canvas/canvas.js +1 -1
- package/dist/core/canvas/labels.d.ts +1 -0
- package/dist/core/canvas/labels.js +3 -1
- package/dist/core/canvas/nav-render.d.ts +6 -0
- package/dist/core/canvas/nav-render.js +8 -0
- package/dist/core/canvas/types.d.ts +6 -0
- package/dist/core/config.js +3 -2
- package/dist/core/feed/inbox.d.ts +3 -3
- package/dist/core/feed/inbox.js +10 -6
- package/dist/core/inspector/core.d.ts +17 -2
- package/dist/core/inspector/core.js +172 -23
- package/dist/core/inspector/model.d.ts +30 -1
- package/dist/core/inspector/model.js +39 -0
- package/dist/core/inspector/text.js +14 -1
- package/dist/core/inspector/tui.js +71 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +2 -2
- package/dist/core/keybindings/catalog.d.ts +3 -3
- package/dist/core/keybindings/catalog.js +5 -2
- package/dist/core/preview-registry.d.ts +5 -0
- package/dist/core/preview-registry.js +10 -0
- package/dist/core/runtime/canvas-extensions.d.ts +4 -0
- package/dist/core/runtime/canvas-extensions.js +4 -0
- package/dist/core/runtime/naming-persist.d.ts +4 -3
- package/dist/core/runtime/naming-persist.js +10 -9
- package/dist/core/runtime/naming.d.ts +28 -8
- package/dist/core/runtime/naming.js +168 -32
- package/dist/core/runtime/nerd-font.d.ts +28 -0
- package/dist/core/runtime/nerd-font.js +127 -0
- package/dist/core/runtime/tmux.js +16 -0
- package/dist/core/tui/host.js +21 -6
- package/dist/daemon/api/map.js +2 -0
- package/dist/pi-extensions/canvas-bash-valve.js +5 -0
- package/dist/pi-extensions/naming-tool.d.ts +24 -0
- package/dist/pi-extensions/naming-tool.js +67 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/dist/web-client/assets/index-B76ZKfT_.js +79 -0
- package/dist/web-client/assets/{index-CpEl9LTS.css → index-CqLKj8Xu.css} +1 -1
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/web-client/assets/index-CsuwzlcQ.js +0 -79
|
@@ -13,6 +13,8 @@ export const ICON = {
|
|
|
13
13
|
artifacts: cp(0xf1da), // history/archive — what it left behind
|
|
14
14
|
paths: cp(0xf0f6), // file-text — on-disk locations
|
|
15
15
|
cron: cp(0xf017), // clock — one armed cron
|
|
16
|
+
job: cp(0xf013), // cog — one live background bash job
|
|
17
|
+
log: cp(0xf120), // terminal — the job's log stream
|
|
16
18
|
section: cp(0xf192), // dot-circle — the active tab marker
|
|
17
19
|
raw: cp(0xf121), // code — the raw record
|
|
18
20
|
empty: cp(0xf1b3), // cubes — nothing armed
|
|
@@ -42,6 +44,43 @@ export function scheduledItems(crons) {
|
|
|
42
44
|
return a.cron.cron_id.localeCompare(b.cron.cron_id);
|
|
43
45
|
});
|
|
44
46
|
}
|
|
47
|
+
/** Elapsed duration in the shape every bash-handoff surface uses: `12s`,
|
|
48
|
+
* `3m 40s`, `1h 04m`. Duplicated from core/bash-jobs.ts on purpose — a view
|
|
49
|
+
* module stays a pure read and never pulls the node:fs job scanner in. */
|
|
50
|
+
export function elapsed(ms) {
|
|
51
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
|
|
52
|
+
if (totalSeconds < 60)
|
|
53
|
+
return `${totalSeconds}s`;
|
|
54
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
55
|
+
if (totalMinutes < 60)
|
|
56
|
+
return `${totalMinutes}m ${String(totalSeconds % 60).padStart(2, '0')}s`;
|
|
57
|
+
return `${Math.floor(totalMinutes / 60)}h ${String(totalMinutes % 60).padStart(2, '0')}m`;
|
|
58
|
+
}
|
|
59
|
+
/** How a running job's age reads at a glance: an ordered ramp, not decoration.
|
|
60
|
+
* Fresh work is green, a job past 15m is amber, past an hour is red — the same
|
|
61
|
+
* good/warn/bad progression the node status glyphs use. */
|
|
62
|
+
export function jobTone(elapsedMs) {
|
|
63
|
+
if (elapsedMs >= 60 * 60_000)
|
|
64
|
+
return 'bad';
|
|
65
|
+
if (elapsedMs >= 15 * 60_000)
|
|
66
|
+
return 'warn';
|
|
67
|
+
return 'good';
|
|
68
|
+
}
|
|
69
|
+
/** Milliseconds a job has been running, live from `started_at`. */
|
|
70
|
+
export function jobElapsedMs(job, now = Date.now()) {
|
|
71
|
+
const at = Date.parse(job.started_at);
|
|
72
|
+
return Number.isFinite(at) ? now - at : job.elapsed_ms;
|
|
73
|
+
}
|
|
74
|
+
/** Live elapsed time for a job row — recomputed from `started_at` so the number
|
|
75
|
+
* keeps ticking between the view's 5s refreshes; `elapsed_ms` is the fallback. */
|
|
76
|
+
export function jobElapsed(job, now = Date.now()) {
|
|
77
|
+
return elapsed(jobElapsedMs(job, now));
|
|
78
|
+
}
|
|
79
|
+
/** First line of a command, whitespace-collapsed and capped for a one-row cell. */
|
|
80
|
+
export function commandCell(command, cap = 60) {
|
|
81
|
+
const oneLine = (command.split('\n')[0] ?? '').replace(/\s+/g, ' ').trim();
|
|
82
|
+
return oneLine.length > cap ? `${oneLine.slice(0, cap - 1)}…` : oneLine;
|
|
83
|
+
}
|
|
45
84
|
export function relativeTime(iso, now = Date.now()) {
|
|
46
85
|
if (iso === null)
|
|
47
86
|
return '—';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { overviewGroups, relativeTime, scheduledItems, value } from './model.js';
|
|
1
|
+
import { jobElapsed, overviewGroups, relativeTime, scheduledItems, value } from './model.js';
|
|
2
2
|
/** The piped path: same information and grouping as the TUI, minus the glyphs
|
|
3
3
|
* and hue a pipe cannot carry. */
|
|
4
4
|
export const inspectorText = {
|
|
@@ -27,6 +27,19 @@ export const inspectorText = {
|
|
|
27
27
|
const cron = item.cron;
|
|
28
28
|
lines.push('', ` ${cron.name} · ${item.cadence} · ${relativeTime(item.nextAt)}`, ` id ${cron.cron_id}`, ` next ${item.nextAt}`, ` state ${value(cron.state)}`, ` output ${cron.on_output}${cron.sink ? ` → ${cron.sink}` : ''}`, ` expires ${value(cron.expires_at)}`);
|
|
29
29
|
}
|
|
30
|
+
lines.push('', 'BACKGROUND BASH JOBS');
|
|
31
|
+
if (state.jobs.error) {
|
|
32
|
+
lines.push(` ${state.jobs.error.display.explanation}`, ` ${state.jobs.error.display.nextStep}`);
|
|
33
|
+
return lines.join('\n');
|
|
34
|
+
}
|
|
35
|
+
const jobs = state.jobs.data ?? [];
|
|
36
|
+
if (jobs.length === 0)
|
|
37
|
+
lines.push(' nothing running');
|
|
38
|
+
for (const job of jobs) {
|
|
39
|
+
lines.push('', ` ${job.command.split('\n')[0]} · ${jobElapsed(job)}`, ` id ${job.job_id}`, ` started ${job.started_at}`, ` log ${job.log_path}`);
|
|
40
|
+
for (const line of job.log_tail.slice(-5))
|
|
41
|
+
lines.push(` | ${line}`);
|
|
42
|
+
}
|
|
30
43
|
return lines.join('\n');
|
|
31
44
|
},
|
|
32
45
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ICON, overviewGroups, relativeTime, scheduledItems, shortPath, value, } from './model.js';
|
|
1
|
+
import { ICON, commandCell, jobElapsed, jobElapsedMs, jobTone, overviewGroups, relativeTime, scheduledItems, shortPath, value, } from './model.js';
|
|
2
2
|
// ── Visual grammar ───────────────────────────────────────────────────────────
|
|
3
3
|
//
|
|
4
4
|
// Three primitives carry the whole screen: a TAB STRIP (where am I / where can
|
|
@@ -21,6 +21,7 @@ const HEAD_STYLE = { fg: '36', bold: true };
|
|
|
21
21
|
const SECTIONS = [
|
|
22
22
|
{ id: 'overview', label: 'overview' },
|
|
23
23
|
{ id: 'schedule', label: 'schedule' },
|
|
24
|
+
{ id: 'jobs', label: 'jobs' },
|
|
24
25
|
{ id: 'raw', label: 'raw' },
|
|
25
26
|
];
|
|
26
27
|
/** `label` padded into the dim label column, then the value. */
|
|
@@ -50,7 +51,9 @@ function tabStrip(state, width) {
|
|
|
50
51
|
const active = section.id === state.section;
|
|
51
52
|
const badge = section.id === 'schedule'
|
|
52
53
|
? ` ${scheduledItems(state.schedule.data ?? []).length}`
|
|
53
|
-
: ''
|
|
54
|
+
: section.id === 'jobs'
|
|
55
|
+
? ` ${(state.jobs.data ?? []).length}`
|
|
56
|
+
: '';
|
|
54
57
|
spans.push({
|
|
55
58
|
text: active ? `${ICON.section} ${section.label}${badge}` : `${section.label}${badge}`,
|
|
56
59
|
style: active ? { fg: '36', bold: true } : { dim: true },
|
|
@@ -147,6 +150,52 @@ function cronItem(item, expanded) {
|
|
|
147
150
|
lines,
|
|
148
151
|
};
|
|
149
152
|
}
|
|
153
|
+
/** One live background job as a list item. Collapsed it shows the single thing
|
|
154
|
+
* a watcher wants — the newest log line — under the command and its running
|
|
155
|
+
* time; expanding adds the job's identity and a live tail of its log, so the
|
|
156
|
+
* Inspector answers "what is it doing right now" without a second surface. */
|
|
157
|
+
function jobItem(job, expanded, width) {
|
|
158
|
+
const tone = TONE[jobTone(jobElapsedMs(job))];
|
|
159
|
+
const last = job.log_tail[job.log_tail.length - 1];
|
|
160
|
+
const lines = [];
|
|
161
|
+
if (!expanded) {
|
|
162
|
+
lines.push([{ text: `${INDENT}${INDENT}${last === undefined ? 'no output yet' : logCell(last, width - 6)}`, style: { dim: true } }]);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
for (const [label, text] of [['job', job.job_id], ['started', job.started_at], ['log', shortPath(job.log_path)], ['watch', `tail -f ${shortPath(job.log_path)}`]]) {
|
|
166
|
+
lines.push([{ text: `${INDENT}${INDENT}${label.padEnd(LABEL_COL)}`, style: LABEL_STYLE }, { text, style: label === 'watch' ? { fg: '36' } : undefined }]);
|
|
167
|
+
}
|
|
168
|
+
lines.push([]);
|
|
169
|
+
lines.push(groupHeader(ICON.log, `last ${job.log_tail.length} lines`, width - 2));
|
|
170
|
+
if (job.log_tail.length === 0)
|
|
171
|
+
lines.push([{ text: `${INDENT}${INDENT}no output yet`, style: { dim: true } }]);
|
|
172
|
+
for (const line of job.log_tail)
|
|
173
|
+
lines.push([{ text: `${INDENT}${INDENT}${logCell(line, width - 6)}`, style: { dim: true } }]);
|
|
174
|
+
}
|
|
175
|
+
lines.push([]); // one blank row between jobs — each item reads as its own block
|
|
176
|
+
return {
|
|
177
|
+
spans: [
|
|
178
|
+
{ text: ` ${ICON.job} `, style: tone },
|
|
179
|
+
{ text: commandCell(job.command, Math.max(20, width - 26)), style: { bold: true } },
|
|
180
|
+
],
|
|
181
|
+
right: [{ text: `${jobElapsed(job)} `, style: tone }],
|
|
182
|
+
lines,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/** A log line, tabs expanded and clipped to the card — never wrapped, so one
|
|
186
|
+
* runaway line cannot push the rest of the tail off the screen. */
|
|
187
|
+
function logCell(line, width) {
|
|
188
|
+
const flat = line.replace(/\t/g, ' ').replace(/[\u0000-\u0008\u000b-\u001f]/g, '');
|
|
189
|
+
const cap = Math.max(10, width);
|
|
190
|
+
return flat.length > cap ? `${flat.slice(0, cap - 1)}…` : flat;
|
|
191
|
+
}
|
|
192
|
+
function jobsEmptyRows() {
|
|
193
|
+
return [
|
|
194
|
+
[{ text: ` ${ICON.empty} nothing running`, style: { dim: true } }],
|
|
195
|
+
[],
|
|
196
|
+
[{ text: `${INDENT}This node has no bash commands running in the background.`, style: { dim: true } }],
|
|
197
|
+
];
|
|
198
|
+
}
|
|
150
199
|
function scheduleEmptyRows() {
|
|
151
200
|
return [
|
|
152
201
|
[{ text: ` ${ICON.empty} nothing armed`, style: { dim: true } }],
|
|
@@ -185,6 +234,23 @@ export const inspectorTui = {
|
|
|
185
234
|
paint(state, rawRows(state), draw, content);
|
|
186
235
|
return;
|
|
187
236
|
}
|
|
237
|
+
if (state.section === 'jobs') {
|
|
238
|
+
if (state.jobs.error) {
|
|
239
|
+
const d = state.jobs.error.display;
|
|
240
|
+
paint(state, errorRows(d.headline, d.explanation, d.nextStep), draw, content);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const jobs = state.jobs.data ?? [];
|
|
244
|
+
if (jobs.length === 0) {
|
|
245
|
+
paint(state, jobsEmptyRows(), draw, content);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
draw.spans(content.row, content.col, tabStrip(state, content.width), content.width);
|
|
249
|
+
const cursor = Math.max(0, jobs.findIndex((job) => job.job_id === state.selectedJobId));
|
|
250
|
+
const rows = jobs.map((job, index) => jobItem(job, index === cursor && state.expanded, content.width));
|
|
251
|
+
draw.list({ ...content, row: content.row + 2, height: Math.max(0, content.height - 2) }, rows, cursor, state.scroll.jobs);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
188
254
|
if (state.schedule.error) {
|
|
189
255
|
const d = state.schedule.error.display;
|
|
190
256
|
paint(state, errorRows(d.headline, d.explanation, d.nextStep), draw, content);
|
|
@@ -209,8 +275,10 @@ export const inspectorTui = {
|
|
|
209
275
|
{ bindingId: 'crtr.view.inspector.section-prev', intent: 'sectionPrev' },
|
|
210
276
|
{ bindingId: 'crtr.view.inspector.page-down', intent: 'pageDown' },
|
|
211
277
|
{ bindingId: 'crtr.view.inspector.page-up', intent: 'pageUp' },
|
|
212
|
-
{ bindingId: 'crtr.view.inspector.toggle-detail', intent: 'toggleDetail', when: (state) => state.section === 'schedule' && state.selectedCronId !== null, hint: { label: 'details' } },
|
|
278
|
+
{ bindingId: 'crtr.view.inspector.toggle-detail', intent: 'toggleDetail', when: (state) => (state.section === 'schedule' && state.selectedCronId !== null) || (state.section === 'jobs' && state.selectedJobId !== null), hint: { label: 'details' } },
|
|
213
279
|
{ bindingId: 'crtr.view.inspector.cancel-item', intent: 'cancelItem', when: (state) => state.section === 'schedule' && state.selectedCronId !== null, hint: { label: 'cancel' } },
|
|
280
|
+
{ bindingId: 'crtr.view.inspector.cancel-item', intent: 'cancelItem', when: (state) => state.section === 'jobs' && state.selectedJobId !== null, hint: { label: 'stop job' } },
|
|
281
|
+
{ bindingId: 'crtr.view.inspector.open-log', intent: 'openLog', when: (state) => state.section === 'jobs' && state.selectedJobId !== null, hint: { label: 'open log' } },
|
|
214
282
|
{ bindingId: 'crtr.view.inspector.confirm', intent: 'confirm', when: (state) => state.pendingCancel !== null, hint: { label: 'confirm' } },
|
|
215
283
|
{ bindingId: 'crtr.view.inspector.dismiss', intent: 'dismiss', hint: { label: 'dismiss' } },
|
|
216
284
|
{ bindingId: 'crtr.view.inspector.retarget', intent: 'retarget', when: (state) => state.section === 'schedule' && state.selectedCronId !== null, hint: { label: 'retarget' } },
|
|
@@ -14,7 +14,7 @@ function ids(prefix, actions) {
|
|
|
14
14
|
return actions.map((action) => `${prefix}.${action}`);
|
|
15
15
|
}
|
|
16
16
|
const REQUIRED_IDS = [
|
|
17
|
-
...ids('crtr.tmux.menu', ['open', 'promote', 'resume', 'fork', 'demote', 'detach', 'close-subtree', 'background-bash', 'file-review', 'pin', 'show', 'metadata', 'context', 'providers', 'graph', 'focus-manager', 'copy-id', 'reload-viewer', 'issues']),
|
|
17
|
+
...ids('crtr.tmux.menu', ['open', 'promote', 'resume', 'fork', 'demote', 'detach', 'close-subtree', 'background-bash', 'file-review', 'pin', 'show', 'view-settings', 'fold-tools', 'metadata', 'context', 'providers', 'graph', 'focus-manager', 'copy-id', 'reload-viewer', 'issues']),
|
|
18
18
|
...ids('crtr.tmux.menu.issue', ['idea', 'bug']),
|
|
19
19
|
...ids('crtr.tmux.node', ['next', 'previous']),
|
|
20
20
|
'crtr.tmux.inbox.toggle',
|
|
@@ -31,7 +31,7 @@ const REQUIRED_IDS = [
|
|
|
31
31
|
...ids('crtr.view.linkedin', ['down', 'up', 'open', 'reply', 'react', 'refresh', 'quit', 'submit-reply', 'cancel', 'reaction-previous', 'reaction-next', 'submit-reaction']),
|
|
32
32
|
...ids('crtr.view.prompt-review', ['down', 'up', 'compare-previous', 'compare-next', 'toggle-mode', 'expand', 'export', 'refresh', 'quit']),
|
|
33
33
|
...ids('crtr.view.workspace-sidebar', ['down', 'up', 'open', 'refresh', 'quit']),
|
|
34
|
-
...ids('crtr.view.inspector', ['down', 'up', 'section-next', 'section-prev', 'page-down', 'page-up', 'toggle-detail', 'cancel-item', 'confirm', 'dismiss', 'retarget', 'refresh', 'quit']),
|
|
34
|
+
...ids('crtr.view.inspector', ['down', 'up', 'section-next', 'section-prev', 'page-down', 'page-up', 'toggle-detail', 'cancel-item', 'open-log', 'confirm', 'dismiss', 'retarget', 'refresh', 'quit']),
|
|
35
35
|
...ids('crtr.view-picker', ['down', 'up', 'run', 'quit']),
|
|
36
36
|
...ids('crtr.browse', ['quit', 'down', 'up', 'first', 'last', 'expand-or-child', 'collapse-or-parent', 'toggle-fold', 'tab-next', 'tab-previous', 'tab.1', 'tab.2', 'tab.3', 'tab.4', 'tab.5', 'close-subtree', 'confirm-close', 'sort', 'scope', 'profile', 'residents', 'preview', 'search', 'revive-now', 'focus', 'focus-background']),
|
|
37
37
|
...ids('crtr.browse.search', ['cancel', 'commit', 'delete', 'quit']),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BindingDefinition, SafetyRequirement } from './types.js';
|
|
2
|
-
type TmuxMenuAction = 'open' | 'show' | 'metadata' | 'promote' | 'resume' | 'fork' | 'demote' | 'detach' | 'close-subtree' | 'background-bash' | 'file-review' | 'pin' | 'reload-viewer' | 'context' | 'providers' | 'graph' | 'focus-manager' | 'copy-id' | 'issues';
|
|
2
|
+
type TmuxMenuAction = 'open' | 'show' | 'view-settings' | 'fold-tools' | 'metadata' | 'promote' | 'resume' | 'fork' | 'demote' | 'detach' | 'close-subtree' | 'background-bash' | 'file-review' | 'pin' | 'reload-viewer' | 'context' | 'providers' | 'graph' | 'focus-manager' | 'copy-id' | 'issues';
|
|
3
3
|
type GraphAction = 'down' | 'up' | 'first' | 'last' | 'collapse-or-manager' | 'expand-or-child' | 'focus' | 'revive' | 'focus-manager' | 'close-subtree' | 'dismiss';
|
|
4
4
|
type InboxAction = 'down' | 'up' | 'open' | 'reply' | 'react' | 'filter' | 'refresh' | 'connect-linkedin' | 'connect-gmail' | 'quit' | 'submit-reply' | 'cancel' | 'reaction-previous' | 'reaction-next' | 'submit-reaction';
|
|
5
5
|
type LinkedinAction = Exclude<InboxAction, 'filter' | 'connect-linkedin' | 'connect-gmail'>;
|
|
@@ -8,8 +8,8 @@ type ProfileMenuAction = 'up' | 'down' | 'select' | 'accept-default' | 'abort' |
|
|
|
8
8
|
type SetupAction = 'cancel' | 'tab-next' | 'tab-previous' | 'open' | 'list-down' | 'list-up' | 'toggle' | 'details' | 'advance' | 'cell-previous' | 'cell-next';
|
|
9
9
|
type SetupKeybindingAction = 'edit' | 'commit-edit' | 'cancel-edit' | 'unbind' | 'reset-row' | 'reset-all' | 'save' | 'discard' | 'page-up' | 'page-down' | 'filter' | 'filter-delete' | 'filter-clear';
|
|
10
10
|
type SetupModelsAction = 'open' | 'commit' | 'cancel' | 'scope-next';
|
|
11
|
-
export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | `crtr.tmux.node.${'next' | 'previous'}` | `crtr.tmux.view.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | `crtr.attach.${'detach' | 'clear-or-detach' | 'graph.toggle' | 'model-ladder.next' | 'model-ladder.previous' | 'command.inspect' | 'file-review'}` | 'crtr.mode.cycle' | `crtr.graph.${GraphAction}` | `crtr.graph.confirm.${'accept' | 'cancel'}` | `crtr.view.host.${'force-quit' | 'editor.backspace'}` | `crtr.view.canvas.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.chat.${'submit' | 'contextual-cancel' | 'reconnect' | 'quit'}` | `crtr.view.git-pr.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.inbox.${InboxAction}` | `crtr.view.linkedin.${LinkedinAction}` | `crtr.view.prompt-review.${'down' | 'up' | 'compare-previous' | 'compare-next' | 'toggle-mode' | 'expand' | 'export' | 'refresh' | 'quit'}` | `crtr.view.workspace-sidebar.${'down' | 'up' | 'open' | 'refresh' | 'quit'}` | `crtr.view.inspector.${'down' | 'up' | 'section-next' | 'section-prev' | 'page-down' | 'page-up' | 'toggle-detail' | 'cancel-item' | 'confirm' | 'dismiss' | 'retarget' | 'refresh' | 'quit'}` | `crtr.view-picker.${'down' | 'up' | 'run' | 'quit'}` | `crtr.browse.${BrowseAction}` | `crtr.browse.search.${'cancel' | 'commit' | 'delete' | 'quit'}` | `crtr.profile.menu.${ProfileMenuAction}` | `crtr.profile.search.${'up' | 'down' | 'pick' | 'back' | 'delete' | 'abort'}` | `crtr.setup.${SetupAction}` | `crtr.setup.confirm.${'accept' | 'back'}` | `crtr.setup.keybindings.${SetupKeybindingAction}` | `crtr.setup.models.${SetupModelsAction}`;
|
|
12
|
-
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.promote">, BindingDefinition<"crtr.tmux.menu.resume">, BindingDefinition<"crtr.tmux.menu.fork">, BindingDefinition<"crtr.tmux.menu.demote">, BindingDefinition<"crtr.tmux.menu.detach">, BindingDefinition<"crtr.tmux.menu.close-subtree">, BindingDefinition<"crtr.tmux.menu.background-bash">, BindingDefinition<"crtr.tmux.menu.file-review">, BindingDefinition<"crtr.tmux.menu.pin">, BindingDefinition<"crtr.tmux.menu.show">, BindingDefinition<"crtr.tmux.menu.metadata">, BindingDefinition<"crtr.tmux.menu.context">, BindingDefinition<"crtr.tmux.menu.providers">, BindingDefinition<"crtr.tmux.menu.graph">, BindingDefinition<"crtr.tmux.menu.focus-manager">, BindingDefinition<"crtr.tmux.menu.copy-id">, BindingDefinition<"crtr.tmux.menu.reload-viewer">, BindingDefinition<"crtr.tmux.menu.issues">, BindingDefinition<"crtr.tmux.menu.issue.idea">, BindingDefinition<"crtr.tmux.menu.issue.bug">, BindingDefinition<"crtr.tmux.node.next">, BindingDefinition<"crtr.tmux.node.previous">, BindingDefinition<"crtr.tmux.inbox.toggle">, BindingDefinition<"crtr.tmux.view.next">, BindingDefinition<"crtr.tmux.view.previous">, BindingDefinition<"crtr.attach.detach">, BindingDefinition<"crtr.attach.clear-or-detach">, BindingDefinition<"crtr.attach.graph.toggle">, BindingDefinition<"crtr.attach.model-ladder.next">, BindingDefinition<"crtr.attach.model-ladder.previous">, BindingDefinition<"crtr.attach.command.inspect">, BindingDefinition<"crtr.attach.file-review">, BindingDefinition<"crtr.mode.cycle">, BindingDefinition<"crtr.graph.down">, BindingDefinition<"crtr.graph.up">, BindingDefinition<"crtr.graph.first">, BindingDefinition<"crtr.graph.last">, BindingDefinition<"crtr.graph.collapse-or-manager">, BindingDefinition<"crtr.graph.expand-or-child">, BindingDefinition<"crtr.graph.focus">, BindingDefinition<"crtr.graph.revive">, BindingDefinition<"crtr.graph.focus-manager">, BindingDefinition<"crtr.graph.close-subtree">, BindingDefinition<"crtr.graph.dismiss">, BindingDefinition<"crtr.graph.confirm.accept">, BindingDefinition<"crtr.graph.confirm.cancel">, BindingDefinition<"crtr.view.host.force-quit">, BindingDefinition<"crtr.view.host.editor.backspace">, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<"crtr.view.chat.submit">, BindingDefinition<"crtr.view.chat.contextual-cancel">, BindingDefinition<"crtr.view.chat.reconnect">, BindingDefinition<"crtr.view.chat.quit">, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.view.prompt-review.down"> | BindingDefinition<"crtr.view.prompt-review.up"> | BindingDefinition<"crtr.view.prompt-review.compare-previous"> | BindingDefinition<"crtr.view.prompt-review.compare-next"> | BindingDefinition<"crtr.view.prompt-review.toggle-mode"> | BindingDefinition<"crtr.view.prompt-review.expand"> | BindingDefinition<"crtr.view.prompt-review.export"> | BindingDefinition<"crtr.view.prompt-review.refresh"> | BindingDefinition<"crtr.view.prompt-review.quit"> | BindingDefinition<"crtr.view.workspace-sidebar.down"> | BindingDefinition<"crtr.view.workspace-sidebar.up"> | BindingDefinition<"crtr.view.workspace-sidebar.open"> | BindingDefinition<"crtr.view.workspace-sidebar.refresh"> | BindingDefinition<"crtr.view.workspace-sidebar.quit"> | BindingDefinition<"crtr.view.inspector.down"> | BindingDefinition<"crtr.view.inspector.up"> | BindingDefinition<"crtr.view.inspector.section-next"> | BindingDefinition<"crtr.view.inspector.section-prev"> | BindingDefinition<"crtr.view.inspector.page-down"> | BindingDefinition<"crtr.view.inspector.page-up"> | BindingDefinition<"crtr.view.inspector.toggle-detail"> | BindingDefinition<"crtr.view.inspector.cancel-item"> | BindingDefinition<"crtr.view.inspector.confirm"> | BindingDefinition<"crtr.view.inspector.dismiss"> | BindingDefinition<"crtr.view.inspector.retarget"> | BindingDefinition<"crtr.view.inspector.refresh"> | BindingDefinition<"crtr.view.inspector.quit"> | BindingDefinition<"crtr.view-picker.down"> | BindingDefinition<"crtr.view-picker.up"> | BindingDefinition<"crtr.view-picker.run"> | BindingDefinition<"crtr.view-picker.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.9" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.7" | "crtr.profile.menu.slot.6">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
11
|
+
export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | `crtr.tmux.node.${'next' | 'previous'}` | `crtr.tmux.view.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | `crtr.attach.${'detach' | 'clear-or-detach' | 'graph.toggle' | 'model-ladder.next' | 'model-ladder.previous' | 'command.inspect' | 'file-review'}` | 'crtr.mode.cycle' | `crtr.graph.${GraphAction}` | `crtr.graph.confirm.${'accept' | 'cancel'}` | `crtr.view.host.${'force-quit' | 'editor.backspace'}` | `crtr.view.canvas.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.chat.${'submit' | 'contextual-cancel' | 'reconnect' | 'quit'}` | `crtr.view.git-pr.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.inbox.${InboxAction}` | `crtr.view.linkedin.${LinkedinAction}` | `crtr.view.prompt-review.${'down' | 'up' | 'compare-previous' | 'compare-next' | 'toggle-mode' | 'expand' | 'export' | 'refresh' | 'quit'}` | `crtr.view.workspace-sidebar.${'down' | 'up' | 'open' | 'refresh' | 'quit'}` | `crtr.view.inspector.${'down' | 'up' | 'section-next' | 'section-prev' | 'page-down' | 'page-up' | 'toggle-detail' | 'cancel-item' | 'open-log' | 'confirm' | 'dismiss' | 'retarget' | 'refresh' | 'quit'}` | `crtr.view-picker.${'down' | 'up' | 'run' | 'quit'}` | `crtr.browse.${BrowseAction}` | `crtr.browse.search.${'cancel' | 'commit' | 'delete' | 'quit'}` | `crtr.profile.menu.${ProfileMenuAction}` | `crtr.profile.search.${'up' | 'down' | 'pick' | 'back' | 'delete' | 'abort'}` | `crtr.setup.${SetupAction}` | `crtr.setup.confirm.${'accept' | 'back'}` | `crtr.setup.keybindings.${SetupKeybindingAction}` | `crtr.setup.models.${SetupModelsAction}`;
|
|
12
|
+
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.promote">, BindingDefinition<"crtr.tmux.menu.resume">, BindingDefinition<"crtr.tmux.menu.fork">, BindingDefinition<"crtr.tmux.menu.demote">, BindingDefinition<"crtr.tmux.menu.detach">, BindingDefinition<"crtr.tmux.menu.close-subtree">, BindingDefinition<"crtr.tmux.menu.background-bash">, BindingDefinition<"crtr.tmux.menu.file-review">, BindingDefinition<"crtr.tmux.menu.pin">, BindingDefinition<"crtr.tmux.menu.show">, BindingDefinition<"crtr.tmux.menu.view-settings">, BindingDefinition<"crtr.tmux.menu.fold-tools">, BindingDefinition<"crtr.tmux.menu.metadata">, BindingDefinition<"crtr.tmux.menu.context">, BindingDefinition<"crtr.tmux.menu.providers">, BindingDefinition<"crtr.tmux.menu.graph">, BindingDefinition<"crtr.tmux.menu.focus-manager">, BindingDefinition<"crtr.tmux.menu.copy-id">, BindingDefinition<"crtr.tmux.menu.reload-viewer">, BindingDefinition<"crtr.tmux.menu.issues">, BindingDefinition<"crtr.tmux.menu.issue.idea">, BindingDefinition<"crtr.tmux.menu.issue.bug">, BindingDefinition<"crtr.tmux.node.next">, BindingDefinition<"crtr.tmux.node.previous">, BindingDefinition<"crtr.tmux.inbox.toggle">, BindingDefinition<"crtr.tmux.view.next">, BindingDefinition<"crtr.tmux.view.previous">, BindingDefinition<"crtr.attach.detach">, BindingDefinition<"crtr.attach.clear-or-detach">, BindingDefinition<"crtr.attach.graph.toggle">, BindingDefinition<"crtr.attach.model-ladder.next">, BindingDefinition<"crtr.attach.model-ladder.previous">, BindingDefinition<"crtr.attach.command.inspect">, BindingDefinition<"crtr.attach.file-review">, BindingDefinition<"crtr.mode.cycle">, BindingDefinition<"crtr.graph.down">, BindingDefinition<"crtr.graph.up">, BindingDefinition<"crtr.graph.first">, BindingDefinition<"crtr.graph.last">, BindingDefinition<"crtr.graph.collapse-or-manager">, BindingDefinition<"crtr.graph.expand-or-child">, BindingDefinition<"crtr.graph.focus">, BindingDefinition<"crtr.graph.revive">, BindingDefinition<"crtr.graph.focus-manager">, BindingDefinition<"crtr.graph.close-subtree">, BindingDefinition<"crtr.graph.dismiss">, BindingDefinition<"crtr.graph.confirm.accept">, BindingDefinition<"crtr.graph.confirm.cancel">, BindingDefinition<"crtr.view.host.force-quit">, BindingDefinition<"crtr.view.host.editor.backspace">, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<"crtr.view.chat.submit">, BindingDefinition<"crtr.view.chat.contextual-cancel">, BindingDefinition<"crtr.view.chat.reconnect">, BindingDefinition<"crtr.view.chat.quit">, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, BindingDefinition<BindingId>, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.view.prompt-review.down"> | BindingDefinition<"crtr.view.prompt-review.up"> | BindingDefinition<"crtr.view.prompt-review.compare-previous"> | BindingDefinition<"crtr.view.prompt-review.compare-next"> | BindingDefinition<"crtr.view.prompt-review.toggle-mode"> | BindingDefinition<"crtr.view.prompt-review.expand"> | BindingDefinition<"crtr.view.prompt-review.export"> | BindingDefinition<"crtr.view.prompt-review.refresh"> | BindingDefinition<"crtr.view.prompt-review.quit"> | BindingDefinition<"crtr.view.workspace-sidebar.down"> | BindingDefinition<"crtr.view.workspace-sidebar.up"> | BindingDefinition<"crtr.view.workspace-sidebar.open"> | BindingDefinition<"crtr.view.workspace-sidebar.refresh"> | BindingDefinition<"crtr.view.workspace-sidebar.quit"> | BindingDefinition<"crtr.view.inspector.down"> | BindingDefinition<"crtr.view.inspector.up"> | BindingDefinition<"crtr.view.inspector.section-next"> | BindingDefinition<"crtr.view.inspector.section-prev"> | BindingDefinition<"crtr.view.inspector.page-down"> | BindingDefinition<"crtr.view.inspector.page-up"> | BindingDefinition<"crtr.view.inspector.toggle-detail"> | BindingDefinition<"crtr.view.inspector.cancel-item"> | BindingDefinition<"crtr.view.inspector.open-log"> | BindingDefinition<"crtr.view.inspector.confirm"> | BindingDefinition<"crtr.view.inspector.dismiss"> | BindingDefinition<"crtr.view.inspector.retarget"> | BindingDefinition<"crtr.view.inspector.refresh"> | BindingDefinition<"crtr.view.inspector.quit"> | BindingDefinition<"crtr.view-picker.down"> | BindingDefinition<"crtr.view-picker.up"> | BindingDefinition<"crtr.view-picker.run"> | BindingDefinition<"crtr.view-picker.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.9" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.7" | "crtr.profile.menu.slot.6">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
13
13
|
export declare const BINDING_IDS: ReadonlySet<string>;
|
|
14
14
|
export declare const SAFETY_REQUIREMENTS: readonly SafetyRequirement[];
|
|
15
15
|
export {};
|
|
@@ -37,6 +37,8 @@ export const BINDING_CATALOG = Object.freeze([
|
|
|
37
37
|
b('crtr.tmux.menu.file-review', 'Global tmux', 'Review a file', 'Open a line-anchored review of a file named in the transcript.', ['v'], 'tmux-menu-selector', ['tmux.menu']),
|
|
38
38
|
b('crtr.tmux.menu.pin', 'Global tmux', 'Pin conversation', 'Pin or unpin this conversation in the canvas navigator.', ['shift+f'], 'tmux-menu-selector', ['tmux.menu']),
|
|
39
39
|
b('crtr.tmux.menu.show', 'Global tmux', 'Show node', 'Open the focused node’s inspection menu.', ['s'], 'tmux-menu-selector', ['tmux.menu']),
|
|
40
|
+
b('crtr.tmux.menu.view-settings', 'Global tmux', 'View settings', 'Open the viewer display-settings menu.', ['w'], 'tmux-menu-selector', ['tmux.menu']),
|
|
41
|
+
b('crtr.tmux.menu.fold-tools', 'Global tmux', 'Fold finished tool calls', 'Fold every finished tool call in the transcript to its single call line.', ['f'], 'tmux-menu-selector', ['tmux.menu.view-settings']),
|
|
40
42
|
b('crtr.tmux.menu.metadata', 'Global tmux', 'Show metadata', 'Show the focused node’s metadata dossier.', ['m'], 'tmux-menu-selector', ['tmux.menu.show']),
|
|
41
43
|
b('crtr.tmux.menu.context', 'Global tmux', 'Browse context', 'Browse the focused node context.', ['c'], 'tmux-menu-selector', ['tmux.menu.show']),
|
|
42
44
|
b('crtr.tmux.menu.providers', 'Global tmux', 'Open settings', 'Open the crouter settings panel.', ['p'], 'tmux-menu-selector', ['tmux.menu']),
|
|
@@ -118,8 +120,9 @@ export const BINDING_CATALOG = Object.freeze([
|
|
|
118
120
|
b('crtr.view.inspector.section-prev', 'Views', 'Previous Inspector section', 'Move to the previous Inspector section.', ['shift+tab'], 'terminal', ['view.inspector']),
|
|
119
121
|
b('crtr.view.inspector.page-down', 'Views', 'Page down Inspector', 'Scroll the Inspector detail body down.', ['ctrl+d', 'pagedown'], 'terminal', ['view.inspector']),
|
|
120
122
|
b('crtr.view.inspector.page-up', 'Views', 'Page up Inspector', 'Scroll the Inspector detail body up.', ['ctrl+u', 'pageup'], 'terminal', ['view.inspector']),
|
|
121
|
-
b('crtr.view.inspector.toggle-detail', 'Views', 'Toggle
|
|
122
|
-
b('crtr.view.inspector.cancel-item', 'Views', 'Cancel
|
|
123
|
+
b('crtr.view.inspector.toggle-detail', 'Views', 'Toggle item detail', 'Expand or collapse the selected cron or background job.', ['enter'], 'terminal', ['view.inspector']),
|
|
124
|
+
b('crtr.view.inspector.cancel-item', 'Views', 'Cancel selected item', 'Arm cancellation for the selected cron, or stopping for the selected background job.', ['x'], 'terminal', ['view.inspector']),
|
|
125
|
+
b('crtr.view.inspector.open-log', 'Views', 'Open job log', 'Follow the selected background job’s log in a new tmux window.', ['o'], 'terminal', ['view.inspector']),
|
|
123
126
|
b('crtr.view.inspector.confirm', 'Views', 'Confirm Inspector action', 'Confirm the armed Inspector action.', ['y'], 'terminal', ['view.inspector']),
|
|
124
127
|
b('crtr.view.inspector.dismiss', 'Views', 'Dismiss Inspector action', 'Dismiss an Inspector confirmation or banner.', ['escape'], 'terminal', ['view.inspector'], 'dismiss-modal'),
|
|
125
128
|
b('crtr.view.inspector.retarget', 'Views', 'Retarget Inspector', 'Inspect the selected cron anchor or creator node.', ['t'], 'terminal', ['view.inspector']),
|
|
@@ -9,6 +9,11 @@ export declare function suppressOutputForLeaf(helpName: string): boolean;
|
|
|
9
9
|
* abc`) don't prevent the match. */
|
|
10
10
|
export declare function suppressOutputForPath(tokens: readonly string[]): boolean;
|
|
11
11
|
export declare const HELP_ICON: string;
|
|
12
|
+
/** Glyphs for the plain agent tools the attach viewer re-skins (render/tool-calls.ts).
|
|
13
|
+
* Same registry as the crtr command icons so every Nerd Font codepoint the viewer
|
|
14
|
+
* paints lives in one file: terminal for `bash`, file-text for `read`, floppy for
|
|
15
|
+
* `write` (content committed to disk), pencil-square for `edit`. */
|
|
16
|
+
export declare const TOOL_ICON: Readonly<Record<'bash' | 'read' | 'write' | 'edit', string>>;
|
|
12
17
|
/** Resolve the Nerd Font glyph for a command's argv tokens: the longest
|
|
13
18
|
* matching LEAF_ICON_CP prefix, else the tokens[0] family glyph, else the
|
|
14
19
|
* generic ◆ fallback for an unmapped family. */
|
|
@@ -53,6 +53,16 @@ export function suppressOutputForPath(tokens) {
|
|
|
53
53
|
* regardless of which command's help was requested. */
|
|
54
54
|
const HELP_ICON_CP = 0xf059;
|
|
55
55
|
export const HELP_ICON = String.fromCodePoint(HELP_ICON_CP);
|
|
56
|
+
/** Glyphs for the plain agent tools the attach viewer re-skins (render/tool-calls.ts).
|
|
57
|
+
* Same registry as the crtr command icons so every Nerd Font codepoint the viewer
|
|
58
|
+
* paints lives in one file: terminal for `bash`, file-text for `read`, floppy for
|
|
59
|
+
* `write` (content committed to disk), pencil-square for `edit`. */
|
|
60
|
+
export const TOOL_ICON = {
|
|
61
|
+
bash: String.fromCodePoint(0xf120),
|
|
62
|
+
read: String.fromCodePoint(0xf15c),
|
|
63
|
+
write: String.fromCodePoint(0xf0c7),
|
|
64
|
+
edit: String.fromCodePoint(0xf044),
|
|
65
|
+
};
|
|
56
66
|
/** One glyph per root subtree (`crtr <family> ...`) — the fallback for any
|
|
57
67
|
* leaf not listed in LEAF_ICON_CP below. Codepoints are Nerd Font
|
|
58
68
|
* private-use-area icons chosen per family concept (see command-icons.md). */
|
|
@@ -7,6 +7,10 @@ export declare const CANVAS_CONTEXT_INTRO_PATH: string;
|
|
|
7
7
|
export declare const CANVAS_DOC_SUBSTRATE_PATH: string;
|
|
8
8
|
export declare const CANVAS_STRUCTURED_OUTPUT_PATH: string;
|
|
9
9
|
export declare const CANVAS_BASH_VALVE_PATH: string;
|
|
10
|
+
/** NOT a canvas extension — loaded only by the headless namer subprocess
|
|
11
|
+
* (`runtime/naming.ts`) to give it a constrained-schema `name_session` tool.
|
|
12
|
+
* Deliberately absent from CANVAS_EXTENSIONS: a node must never carry it. */
|
|
13
|
+
export declare const NAMING_TOOL_PATH: string;
|
|
10
14
|
/** The canvas extensions every node loads, in order. The inbox watcher commits
|
|
11
15
|
* its cursor at agent_settled before the stophook checks it for idle release. */
|
|
12
16
|
export declare const CANVAS_EXTENSIONS: string[];
|
|
@@ -19,6 +19,10 @@ export const CANVAS_CONTEXT_INTRO_PATH = resolveExtension('canvas-context-intro'
|
|
|
19
19
|
export const CANVAS_DOC_SUBSTRATE_PATH = resolveExtension('canvas-doc-substrate');
|
|
20
20
|
export const CANVAS_STRUCTURED_OUTPUT_PATH = resolveExtension('canvas-structured-output');
|
|
21
21
|
export const CANVAS_BASH_VALVE_PATH = resolveExtension('canvas-bash-valve');
|
|
22
|
+
/** NOT a canvas extension — loaded only by the headless namer subprocess
|
|
23
|
+
* (`runtime/naming.ts`) to give it a constrained-schema `name_session` tool.
|
|
24
|
+
* Deliberately absent from CANVAS_EXTENSIONS: a node must never carry it. */
|
|
25
|
+
export const NAMING_TOOL_PATH = resolveExtension('naming-tool');
|
|
22
26
|
/** The canvas extensions every node loads, in order. The inbox watcher commits
|
|
23
27
|
* its cursor at agent_settled before the stophook checks it for idle release. */
|
|
24
28
|
export const CANVAS_EXTENSIONS = [
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { NodeMeta } from '../canvas/index.js';
|
|
2
2
|
/** Asynchronously generate a name for `prompt` and persist it to the node's
|
|
3
|
-
* meta as `description` — only if the node has none yet (so a later
|
|
4
|
-
* never clobbers it). Non-blocking: safe to call from inside a live pi
|
|
5
|
-
* loop. Best-effort; swallows all errors.
|
|
3
|
+
* meta as `description` + `icon` — only if the node has none yet (so a later
|
|
4
|
+
* message never clobbers it). Non-blocking: safe to call from inside a live pi
|
|
5
|
+
* event loop. Best-effort; swallows all errors. The slug fallback carries no
|
|
6
|
+
* icon: a locally derived name has no judgment behind it to pick a glyph from.
|
|
6
7
|
*
|
|
7
8
|
* `onNamed` (optional) fires with the freshly-persisted meta the moment the
|
|
8
9
|
* name lands — the canvas-goal-capture naming hook passes a callback that calls
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
import { headlessName, sanitizeSessionName, slugFromPrompt } from './naming.js';
|
|
9
9
|
import { getNode, updateNode } from '../canvas/index.js';
|
|
10
10
|
/** Asynchronously generate a name for `prompt` and persist it to the node's
|
|
11
|
-
* meta as `description` — only if the node has none yet (so a later
|
|
12
|
-
* never clobbers it). Non-blocking: safe to call from inside a live pi
|
|
13
|
-
* loop. Best-effort; swallows all errors.
|
|
11
|
+
* meta as `description` + `icon` — only if the node has none yet (so a later
|
|
12
|
+
* message never clobbers it). Non-blocking: safe to call from inside a live pi
|
|
13
|
+
* event loop. Best-effort; swallows all errors. The slug fallback carries no
|
|
14
|
+
* icon: a locally derived name has no judgment behind it to pick a glyph from.
|
|
14
15
|
*
|
|
15
16
|
* `onNamed` (optional) fires with the freshly-persisted meta the moment the
|
|
16
17
|
* name lands — the canvas-goal-capture naming hook passes a callback that calls
|
|
@@ -20,22 +21,22 @@ export function generateAndPersistName(nodeId, prompt, onNamed) {
|
|
|
20
21
|
const body = (prompt ?? '').trim();
|
|
21
22
|
if (body === '')
|
|
22
23
|
return;
|
|
23
|
-
const persist = (
|
|
24
|
+
const persist = (generated) => {
|
|
24
25
|
try {
|
|
25
26
|
const meta = getNode(nodeId);
|
|
26
27
|
if (meta === null)
|
|
27
28
|
return;
|
|
28
29
|
if ((meta.description ?? '').trim() !== '')
|
|
29
30
|
return; // already named
|
|
30
|
-
const clean = sanitizeSessionName(name);
|
|
31
|
-
const
|
|
31
|
+
const clean = sanitizeSessionName(generated.name);
|
|
32
|
+
const description = clean !== '' ? clean : slugFromPrompt(body);
|
|
33
|
+
const icon = generated.icon.trim();
|
|
34
|
+
const updated = updateNode(nodeId, { description, ...(icon !== '' ? { icon } : {}) });
|
|
32
35
|
onNamed?.(updated);
|
|
33
36
|
}
|
|
34
37
|
catch {
|
|
35
38
|
// best-effort
|
|
36
39
|
}
|
|
37
40
|
};
|
|
38
|
-
void headlessName(body).then(
|
|
39
|
-
persist(name !== '' ? name : slugFromPrompt(body));
|
|
40
|
-
});
|
|
41
|
+
void headlessName(body).then(persist);
|
|
41
42
|
}
|
|
@@ -5,18 +5,38 @@ export declare function sanitizeSessionName(raw: string): string;
|
|
|
5
5
|
/** Local fallback: derive a name straight from the prompt (no pi call). Drops
|
|
6
6
|
* stop-words, takes the first few content words. */
|
|
7
7
|
export declare function slugFromPrompt(prompt: string): string;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
/** A generated session name: the kebab-case handle plus the Nerd Font glyph the
|
|
9
|
+
* namer chose for it. `icon` is '' when the model returned nothing usable —
|
|
10
|
+
* every surface renders the name alone in that case. */
|
|
11
|
+
export interface SessionName {
|
|
12
|
+
name: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
}
|
|
15
|
+
/** Normalize a model-supplied icon to a single renderable glyph, or '' when
|
|
16
|
+
* nothing usable came back.
|
|
17
|
+
*
|
|
18
|
+
* The model is asked for a `U+XXXX` codepoint rather than the literal
|
|
19
|
+
* character: Nerd Font glyphs sit in the private-use areas, which models
|
|
20
|
+
* reproduce unreliably as literal text (they tend to substitute an emoji), but
|
|
21
|
+
* name accurately as codepoints. A literal glyph is still accepted — including
|
|
22
|
+
* an emoji, which renders fine even if it is not the house style — so a model
|
|
23
|
+
* that ignores the format still contributes. Rejects a spelled-out
|
|
24
|
+
* `nf-fa-bug`, a bare ASCII letter, and anything multi-glyph, all of which
|
|
25
|
+
* would render as noise or tofu in a label. */
|
|
26
|
+
export declare function sanitizeIcon(raw: string): string;
|
|
27
|
+
/** Ask pi headlessly for a structured {name, icon} for `body`, async. Resolves
|
|
28
|
+
* to a sanitized SessionName, or `{name:'',icon:''}` on any failure (non-zero
|
|
29
|
+
* exit, timeout, no tool call, garbled emission) so the caller can fall back to
|
|
30
|
+
* a local slug. Owns the subprocess mechanics — crucially it hands pi an
|
|
31
|
+
* immediate stdin EOF: `pi -p` reads stdin, and execFile's default stdin is an
|
|
32
|
+
* OPEN pipe that never closes, so without this pi blocks waiting for EOF and
|
|
33
|
+
* the call exits non-zero (the regression that silently lost every LLM name to
|
|
34
|
+
* the slug fallback).
|
|
15
35
|
*
|
|
16
36
|
* Exported (not just for tests): the canvas-coupled persistence wrapper
|
|
17
37
|
* generateAndPersistName lives in naming-persist.ts to keep this module
|
|
18
38
|
* canvas-free, and imports this pure helper. */
|
|
19
|
-
export declare function headlessName(body: string): Promise<
|
|
39
|
+
export declare function headlessName(body: string): Promise<SessionName>;
|
|
20
40
|
/** A filesystem-safe slug for the `.todos/<slug>.md` fallback path: lowercase,
|
|
21
41
|
* [a-z0-9] kept, everything else → single hyphen, clamped to 8 words. */
|
|
22
42
|
export declare function titleSlug(title: string): string;
|