@north-light/crouter 0.3.158 → 0.3.159
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/builtin-memory/internal/storage-tiers.md +2 -0
- package/dist/clients/attach/chrome/bash-jobs.d.ts +0 -5
- package/dist/clients/attach/chrome/bash-jobs.js +5 -24
- package/dist/clients/attach/chrome/roster.d.ts +3 -2
- package/dist/clients/attach/chrome/roster.js +11 -35
- package/dist/clients/attach/viewer.js +479 -481
- package/dist/commands/node.js +141 -3
- package/dist/commands/surface-inspect.js +4 -3
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +5 -3
- package/dist/core/bash-jobs.d.ts +11 -0
- package/dist/core/bash-jobs.js +41 -1
- 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 +1 -1
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +3 -2
- package/dist/core/tui/host.js +21 -6
- package/dist/pi-extensions/canvas-bash-valve.js +5 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
|
@@ -3,6 +3,8 @@ name: internal/storage-tiers
|
|
|
3
3
|
kind: knowledge
|
|
4
4
|
description: Where crouter state belongs
|
|
5
5
|
when-and-why-to-read: When locating crtr state or deciding where a new file belongs, this reference should be read so files are found or placed in the storage tier with the right ownership and durability.
|
|
6
|
+
system-prompt-visibility: name
|
|
7
|
+
file-read-visibility: none
|
|
6
8
|
short-form: The two crtr storage tiers — scope root for durable user/repo content and canvas home for node-graph runtime state, node artifacts, and human tickets.
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -2,8 +2,3 @@ import { type BashJobStatus } from '../../../core/bash-jobs.js';
|
|
|
2
2
|
/** Compact cockpit row: the running command (or job count) plus elapsed time.
|
|
3
3
|
* `undefined` for an empty list — the caller omits the row entirely. */
|
|
4
4
|
export declare function bashJobsWaitSummary(jobs: readonly BashJobStatus[], nowMs?: number): string | undefined;
|
|
5
|
-
/** Readable drill-in document for the tmux detail surface. Watch-only — no
|
|
6
|
-
* cancel line: the owning agent already received the exact `kill -- -<pgid>`
|
|
7
|
-
* in its handoff notice, and persisting pgid to add a human stop affordance is
|
|
8
|
-
* a separable future addition (measuring-stick restraint). */
|
|
9
|
-
export declare function renderBashJobsDetails(jobs: readonly BashJobStatus[], nowMs?: number): string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// chrome/bash-jobs.ts — the attach-side formatter
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// chrome/bash-jobs.ts — the attach-side formatter for live backgrounded bash jobs,
|
|
2
|
+
// mirroring chrome/cron-wait.ts: the compact one-row cockpit summary. Pure — takes
|
|
3
|
+
// the already-scanned job list, never touches disk itself (that's
|
|
4
|
+
// activeBackgroundBashJobs' job, in core/bash-jobs.ts). Enter on that row opens
|
|
5
|
+
// the Inspector's `jobs` section, which owns the drill-in rendering.
|
|
6
6
|
import { formatBashElapsed } from '../../../core/bash-jobs.js';
|
|
7
7
|
const CMD_CELL_CAP = 26;
|
|
8
8
|
/** First line of `command`, whitespace-collapsed and capped to ~26 chars. */
|
|
@@ -22,22 +22,3 @@ export function bashJobsWaitSummary(jobs, nowMs = Date.now()) {
|
|
|
22
22
|
const oldest = jobs[0]; // activeBackgroundBashJobs returns oldest-first
|
|
23
23
|
return `${jobs.length} bash jobs · oldest ${formatBashElapsed(nowMs - oldest.startedAtMs)}`;
|
|
24
24
|
}
|
|
25
|
-
/** Readable drill-in document for the tmux detail surface. Watch-only — no
|
|
26
|
-
* cancel line: the owning agent already received the exact `kill -- -<pgid>`
|
|
27
|
-
* in its handoff notice, and persisting pgid to add a human stop affordance is
|
|
28
|
-
* a separable future addition (measuring-stick restraint). */
|
|
29
|
-
export function renderBashJobsDetails(jobs, nowMs = Date.now()) {
|
|
30
|
-
const lines = [
|
|
31
|
-
'# Background bash jobs',
|
|
32
|
-
'',
|
|
33
|
-
`${jobs.length} bash job${jobs.length === 1 ? '' : 's'} running in the background.`,
|
|
34
|
-
];
|
|
35
|
-
for (const job of jobs) {
|
|
36
|
-
lines.push('', `## ⚙ ${cmdCell(job.command)}`, '');
|
|
37
|
-
lines.push(`- **Elapsed:** ${formatBashElapsed(nowMs - job.startedAtMs)} · started ${new Date(job.startedAtMs).toISOString()}`);
|
|
38
|
-
lines.push(`- **Log:** \`${job.logPath}\``);
|
|
39
|
-
lines.push(`- **Watch:** \`tail -f ${job.logPath}\``);
|
|
40
|
-
lines.push('', '### Command', '', '```bash', job.command, '```');
|
|
41
|
-
}
|
|
42
|
-
return `${lines.join('\n')}\n`;
|
|
43
|
-
}
|
|
@@ -11,8 +11,9 @@ export interface RosterHooks {
|
|
|
11
11
|
* on close so a wait row that resolved while the popup was open disappears. */
|
|
12
12
|
requestChromeRefresh: () => void;
|
|
13
13
|
/** Open the viewer-owned Inspector popup (`surface inspect`) on a section —
|
|
14
|
-
* the cron wait row routes to `schedule
|
|
15
|
-
|
|
14
|
+
* the cron wait row routes to `schedule` and the bash row to `jobs`; the
|
|
15
|
+
* native Inspector owns details for both. */
|
|
16
|
+
openInspector: (section: 'overview' | 'schedule' | 'jobs') => void;
|
|
16
17
|
}
|
|
17
18
|
export interface AttachRoster {
|
|
18
19
|
/** Rebuild the rows from the canvas source, reconcile the selection, repaint. */
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
// editor's visual bottom drops the cursor into the list; within it ↑/↓ move the
|
|
5
5
|
// highlight, ↑ off the TOP row returns to the editor, ↓ CLAMPS at the bottom,
|
|
6
6
|
// Enter opens the row (SWAPS this pane in place onto a node, or opens the wait
|
|
7
|
-
// detail surface for a human/cron/bash row
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// detail surface for a human/cron/bash row: a human row opens the inbox, a cron
|
|
8
|
+
// row the Inspector's schedule section, a bash row the Inspector's jobs section),
|
|
9
|
+
// Esc / any typed key returns to the editor. Disabled entirely for a REMOTE
|
|
10
|
+
// attach: a remote graph id has no local pane to swap into and no local
|
|
11
|
+
// jobs/crons to inspect.
|
|
10
12
|
//
|
|
11
13
|
// TWO EDITOR COUPLINGS ARE OWNED HERE, deliberately and exclusively:
|
|
12
14
|
// • `editor.onCursorDownAtBottom` — the boundary handoff. The editor owns
|
|
@@ -23,18 +25,12 @@
|
|
|
23
25
|
// graph, so `refresh()` rebuilds the cached rows asynchronously while arrow
|
|
24
26
|
// movement only reverses the selected cached row and renders immediately.
|
|
25
27
|
import { execFile, execFileSync } from 'node:child_process';
|
|
26
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
27
|
-
import { tmpdir } from 'node:os';
|
|
28
|
-
import { join } from 'node:path';
|
|
29
28
|
import { Text, matchesKey } from '@earendil-works/pi-tui';
|
|
30
29
|
import { cliClient } from '../../../commands/api-client.js';
|
|
31
30
|
import { activeBackgroundBashJobs } from '../../../core/bash-jobs.js';
|
|
32
31
|
import { contextDir } from '../../../core/canvas/paths.js';
|
|
33
32
|
import { fillBar, fillWidth, REVERSE } from '../../../core/canvas/nav-render.js';
|
|
34
|
-
import { inTmux, shellQuote } from '../../../core/runtime/placement-tmux.js';
|
|
35
|
-
import { surfaceTmuxStyleArgs } from '../../../core/runtime/surface-bg.js';
|
|
36
33
|
import { buildCanvasPanelLines } from './canvas-panels.js';
|
|
37
|
-
import { renderBashJobsDetails } from './bash-jobs.js';
|
|
38
34
|
/** Seed pane focus from the pane's REAL active state, not an unconditional
|
|
39
35
|
* `true`. tmux only emits DECSET 1004 focus events on a TRANSITION, so a viewer
|
|
40
36
|
* spawned into a non-active pane (a `split -d` beside another node — the
|
|
@@ -114,31 +110,6 @@ export function createRoster(s, hooks) {
|
|
|
114
110
|
selKey = items[0].key;
|
|
115
111
|
paint();
|
|
116
112
|
};
|
|
117
|
-
/** Open a read-only markdown detail popup in nvim, deleting the temp file when
|
|
118
|
-
* the popup closes and re-running the chrome refresh (background-bash wait row). */
|
|
119
|
-
const openDetailsPopup = (prefix, file, title, missingNvim, body) => {
|
|
120
|
-
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
121
|
-
const path = join(dir, file);
|
|
122
|
-
writeFileSync(path, body, 'utf8');
|
|
123
|
-
const cmd = `if command -v nvim >/dev/null 2>&1; then exec nvim -R -c 'setlocal filetype=markdown' -- ${shellQuote(path)}; else printf '${missingNvim}\\n'; printf 'Press Enter to close.'; read _; fi`;
|
|
124
|
-
execFile('tmux', ['display-popup', '-E', '-T', title, '-w', '90%', '-h', '85%', ...surfaceTmuxStyleArgs(), cmd], () => {
|
|
125
|
-
rmSync(dir, { recursive: true, force: true });
|
|
126
|
-
hooks.requestChromeRefresh();
|
|
127
|
-
});
|
|
128
|
-
};
|
|
129
|
-
const openBashJobsDetails = () => {
|
|
130
|
-
const current = activeBackgroundBashJobs(contextDir(nodeId));
|
|
131
|
-
if (current.length === 0) {
|
|
132
|
-
hooks.setNotice('Background job already finished');
|
|
133
|
-
hooks.requestChromeRefresh();
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (!inTmux()) {
|
|
137
|
-
hooks.setNotice('Background job details require tmux');
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
openDetailsPopup('crtr-bash-jobs-', 'background-bash-jobs.md', ' background bash jobs ', 'nvim is required to inspect background bash jobs. Install Neovim and retry.', renderBashJobsDetails(current));
|
|
141
|
-
};
|
|
142
113
|
const openSelected = () => {
|
|
143
114
|
const item = items.find((candidate) => candidate.key === selKey);
|
|
144
115
|
if (item === undefined || remote)
|
|
@@ -158,8 +129,13 @@ export function createRoster(s, hooks) {
|
|
|
158
129
|
return;
|
|
159
130
|
}
|
|
160
131
|
if (item.kind === 'bash') {
|
|
132
|
+
if (activeBackgroundBashJobs(contextDir(nodeId)).length === 0) {
|
|
133
|
+
hooks.setNotice('Background job already finished');
|
|
134
|
+
hooks.requestChromeRefresh();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
161
137
|
exit();
|
|
162
|
-
|
|
138
|
+
hooks.openInspector('jobs');
|
|
163
139
|
return;
|
|
164
140
|
}
|
|
165
141
|
const id = item.nodeId;
|