@crouton-kit/crouter 0.3.18 → 0.3.19
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/build-root.js +6 -0
- package/dist/builtin-memory/crouter-development/marketplaces.md +164 -0
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +58 -0
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +60 -0
- package/dist/builtin-memory/crouter-development/personas.md +117 -0
- package/dist/builtin-memory/crouter-development/plugins.md +163 -0
- package/dist/builtin-memory/design.md +60 -0
- package/dist/builtin-memory/development.md +116 -0
- package/dist/builtin-memory/planning.md +66 -0
- package/dist/builtin-memory/spec.md +99 -0
- package/dist/builtin-personas/design/orchestrator.md +1 -1
- package/dist/builtin-personas/developer/orchestrator.md +1 -1
- package/dist/builtin-personas/lifecycle/resident.md +1 -1
- package/dist/builtin-personas/lifecycle/terminal.md +5 -2
- package/dist/builtin-personas/orchestration-kernel.md +15 -24
- package/dist/builtin-personas/plan/orchestrator.md +1 -1
- package/dist/builtin-personas/runtime-base.md +6 -3
- package/dist/builtin-personas/spec/orchestrator.md +1 -1
- package/dist/builtin-personas/waiting.md +8 -0
- package/dist/builtin-skills/skills/crouter-development/personas/orchestrator-prompt/SKILL.md +1 -1
- package/dist/builtin-skills/skills/crouter-development/plugins/SKILL.md +2 -2
- package/dist/builtin-views/_lib/states.mjs +161 -0
- package/dist/builtin-views/canvas/client.mjs +303 -0
- package/dist/builtin-views/canvas/view.mjs +576 -0
- package/dist/builtin-views/git-pr/client.mjs +440 -0
- package/dist/builtin-views/git-pr/view.mjs +675 -0
- package/dist/builtin-views/inbox/_lib/render.mjs +177 -0
- package/dist/builtin-views/inbox/sources/gmail.mjs +965 -0
- package/dist/builtin-views/inbox/sources/linkedin.mjs +427 -0
- package/dist/builtin-views/inbox/view.mjs +889 -0
- package/dist/builtin-views/linkedin/client.mjs +610 -0
- package/dist/builtin-views/linkedin/view.mjs +1171 -0
- package/dist/clients/attach/attach-cmd.d.ts +2 -0
- package/dist/clients/attach/attach-cmd.js +354 -0
- package/dist/clients/attach/chat-view.d.ts +77 -0
- package/dist/clients/attach/chat-view.js +450 -0
- package/dist/clients/attach/clipboard-image.d.ts +16 -0
- package/dist/clients/attach/clipboard-image.js +113 -0
- package/dist/clients/attach/config-load.d.ts +31 -0
- package/dist/clients/attach/config-load.js +113 -0
- package/dist/clients/attach/extension-dialogs.d.ts +29 -0
- package/dist/clients/attach/extension-dialogs.js +101 -0
- package/dist/clients/attach/input-controller.d.ts +54 -0
- package/dist/clients/attach/input-controller.js +204 -0
- package/dist/clients/attach/slash-commands.d.ts +36 -0
- package/dist/clients/attach/slash-commands.js +200 -0
- package/dist/clients/attach/view-socket.d.ts +48 -0
- package/dist/clients/attach/view-socket.js +126 -0
- package/dist/commands/attention.js +3 -3
- package/dist/commands/canvas-prune.js +1 -1
- package/dist/commands/daemon.js +3 -2
- package/dist/commands/human/prompts.js +1 -1
- package/dist/commands/human/queue.js +43 -8
- package/dist/commands/human/shared.d.ts +2 -0
- package/dist/commands/memory/find.d.ts +1 -0
- package/dist/commands/memory/find.js +180 -0
- package/dist/commands/memory/lint.d.ts +1 -0
- package/dist/commands/memory/lint.js +140 -0
- package/dist/commands/memory/list.d.ts +1 -0
- package/dist/commands/memory/list.js +79 -0
- package/dist/commands/memory/read.js +103 -0
- package/dist/commands/memory/shared.d.ts +30 -0
- package/dist/commands/memory/shared.js +122 -0
- package/dist/commands/memory/write.d.ts +1 -0
- package/dist/commands/memory/write.js +85 -0
- package/dist/commands/memory.d.ts +2 -0
- package/dist/commands/memory.js +27 -0
- package/dist/commands/node.d.ts +3 -2
- package/dist/commands/node.js +607 -61
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/push.js +6 -6
- package/dist/commands/revive.js +1 -1
- package/dist/commands/skill/author.js +1 -1
- package/dist/commands/skill/shared.d.ts +1 -8
- package/dist/commands/skill/shared.js +2 -55
- package/dist/commands/skill.js +9 -14
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/update.js +1 -1
- package/dist/commands/view-cycle.d.ts +2 -0
- package/dist/commands/view-cycle.js +125 -0
- package/dist/commands/view-list.d.ts +2 -0
- package/dist/commands/view-list.js +66 -0
- package/dist/commands/view-new.d.ts +2 -0
- package/dist/commands/view-new.js +70 -0
- package/dist/commands/view-pick.d.ts +2 -0
- package/dist/commands/view-pick.js +119 -0
- package/dist/commands/view-run.d.ts +2 -0
- package/dist/commands/view-run.js +191 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +29 -0
- package/dist/core/__tests__/broker-lifecycle.test.d.ts +1 -0
- package/dist/core/__tests__/broker-lifecycle.test.js +677 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.d.ts +1 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +166 -0
- package/dist/core/__tests__/cascade-close.test.js +12 -2
- package/dist/core/__tests__/child-death-wake.test.d.ts +1 -0
- package/dist/core/__tests__/child-death-wake.test.js +245 -0
- package/dist/core/__tests__/context-intro.test.js +76 -62
- package/dist/core/__tests__/daemon-boot.test.js +14 -5
- package/dist/core/__tests__/daemon-liveness.test.js +34 -9
- package/dist/core/__tests__/detach-focus.test.d.ts +1 -0
- package/dist/core/__tests__/detach-focus.test.js +206 -0
- package/dist/core/__tests__/draw-style.test.d.ts +1 -0
- package/dist/core/__tests__/draw-style.test.js +258 -0
- package/dist/core/__tests__/fixtures/c3-custom-provider-ext.d.ts +2 -0
- package/dist/core/__tests__/fixtures/c3-custom-provider-ext.js +18 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +138 -0
- package/dist/core/__tests__/fixtures/fake-engine.js +614 -0
- package/dist/core/__tests__/fixtures/fake-pi-host.js +1 -0
- package/dist/core/__tests__/flagship-lifecycle.test.js +7 -1
- package/dist/core/__tests__/frame-decoder-perf.test.d.ts +1 -0
- package/dist/core/__tests__/frame-decoder-perf.test.js +198 -0
- package/dist/core/__tests__/helpers/harness.d.ts +9 -0
- package/dist/core/__tests__/helpers/harness.js +111 -1
- package/dist/core/__tests__/home-session.test.js +41 -8
- package/dist/core/__tests__/human-new-window-regression.test.d.ts +1 -0
- package/dist/core/__tests__/human-new-window-regression.test.js +101 -0
- package/dist/core/__tests__/kickoff.test.js +37 -3
- package/dist/core/__tests__/live-mutation.test.js +50 -33
- package/dist/core/__tests__/memory.test.js +23 -115
- package/dist/core/__tests__/placement-focus.test.js +5 -0
- package/dist/core/__tests__/placement-teardown.test.js +54 -11
- package/dist/core/__tests__/relaunch.test.js +4 -3
- package/dist/core/__tests__/review-render-pane-regression.test.d.ts +1 -0
- package/dist/core/__tests__/review-render-pane-regression.test.js +133 -0
- package/dist/core/__tests__/spawn-root.test.js +10 -0
- package/dist/core/__tests__/spike-harness.test.js +1 -0
- package/dist/core/__tests__/wake-bearings.test.d.ts +1 -0
- package/dist/core/__tests__/wake-bearings.test.js +156 -0
- package/dist/core/__tests__/wake-origin.test.d.ts +1 -0
- package/dist/core/__tests__/wake-origin.test.js +110 -0
- package/dist/core/bootstrap.js +1 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +1 -0
- package/dist/core/canvas/browse/app.js +24 -2
- package/dist/core/canvas/browse/model.d.ts +38 -2
- package/dist/core/canvas/browse/model.js +134 -10
- package/dist/core/canvas/browse/render.d.ts +6 -12
- package/dist/core/canvas/browse/render.js +72 -104
- package/dist/core/canvas/canvas.js +15 -22
- package/dist/core/canvas/db.js +46 -0
- package/dist/core/canvas/index.d.ts +1 -0
- package/dist/core/canvas/index.js +1 -0
- package/dist/core/canvas/pid.d.ts +4 -0
- package/dist/core/canvas/pid.js +23 -0
- package/dist/core/canvas/render.d.ts +11 -2
- package/dist/core/canvas/render.js +69 -0
- package/dist/core/canvas/types.d.ts +85 -3
- package/dist/core/canvas/wakeups.d.ts +76 -0
- package/dist/core/canvas/wakeups.js +185 -0
- package/dist/core/config.js +4 -1
- package/dist/core/frontmatter.js +37 -124
- package/dist/core/memory-resolver.d.ts +49 -0
- package/dist/core/memory-resolver.js +141 -0
- package/dist/core/personas/loader.d.ts +7 -0
- package/dist/core/personas/loader.js +36 -5
- package/dist/core/personas/resolve.js +13 -3
- package/dist/core/predicate.d.ts +63 -0
- package/dist/core/predicate.js +189 -0
- package/dist/core/resolver.js +26 -5
- package/dist/core/runtime/bearings.d.ts +53 -12
- package/dist/core/runtime/bearings.js +132 -59
- package/dist/core/runtime/broker-cli.d.ts +1 -0
- package/dist/core/runtime/broker-cli.js +46 -0
- package/dist/core/runtime/broker-protocol.d.ts +332 -0
- package/dist/core/runtime/broker-protocol.js +153 -0
- package/dist/core/runtime/broker-sdk.d.ts +48 -0
- package/dist/core/runtime/broker-sdk.js +72 -0
- package/dist/core/runtime/broker.d.ts +55 -0
- package/dist/core/runtime/broker.js +1128 -0
- package/dist/core/runtime/close.js +35 -6
- package/dist/core/runtime/host.d.ts +53 -0
- package/dist/core/runtime/host.js +186 -0
- package/dist/core/runtime/kickoff.d.ts +2 -1
- package/dist/core/runtime/kickoff.js +91 -5
- package/dist/core/runtime/launch.d.ts +45 -2
- package/dist/core/runtime/launch.js +65 -2
- package/dist/core/runtime/lifecycle.js +23 -6
- package/dist/core/runtime/memory.d.ts +2 -42
- package/dist/core/runtime/memory.js +11 -162
- package/dist/core/runtime/nodes.d.ts +33 -0
- package/dist/core/runtime/nodes.js +59 -1
- package/dist/core/runtime/persona.js +21 -11
- package/dist/core/runtime/pi-vendored.d.ts +18 -0
- package/dist/core/runtime/pi-vendored.js +49 -0
- package/dist/core/runtime/placement.d.ts +32 -14
- package/dist/core/runtime/placement.js +206 -52
- package/dist/core/runtime/promote.d.ts +0 -6
- package/dist/core/runtime/promote.js +1 -12
- package/dist/core/runtime/{demote.d.ts → recycle.d.ts} +5 -5
- package/dist/core/runtime/{demote.js → recycle.js} +27 -11
- package/dist/core/runtime/reset.js +8 -6
- package/dist/core/runtime/revive.d.ts +2 -0
- package/dist/core/runtime/revive.js +34 -34
- package/dist/core/runtime/spawn.d.ts +19 -0
- package/dist/core/runtime/spawn.js +75 -22
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +6 -1
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +1 -1
- package/dist/core/runtime/tmux.d.ts +28 -0
- package/dist/core/runtime/tmux.js +80 -6
- package/dist/core/scope.d.ts +11 -0
- package/dist/core/scope.js +39 -0
- package/dist/core/spawn.d.ts +5 -0
- package/dist/core/spawn.js +20 -2
- package/dist/core/substrate/gate.d.ts +13 -0
- package/dist/core/substrate/gate.js +21 -0
- package/dist/core/substrate/index.d.ts +7 -0
- package/dist/core/substrate/index.js +18 -0
- package/dist/core/substrate/on-read.d.ts +14 -0
- package/dist/core/substrate/on-read.js +292 -0
- package/dist/core/substrate/render.d.ts +25 -0
- package/dist/core/substrate/render.js +256 -0
- package/dist/core/substrate/schema.d.ts +76 -0
- package/dist/core/substrate/schema.js +124 -0
- package/dist/core/substrate/session-cache.d.ts +30 -0
- package/dist/core/substrate/session-cache.js +77 -0
- package/dist/core/substrate/subject.d.ts +41 -0
- package/dist/core/substrate/subject.js +54 -0
- package/dist/core/tui/contract.d.ts +83 -0
- package/dist/core/tui/contract.js +8 -0
- package/dist/core/tui/draw.d.ts +96 -0
- package/dist/core/tui/draw.js +339 -0
- package/dist/core/tui/host.d.ts +29 -0
- package/dist/core/tui/host.js +379 -0
- package/dist/core/tui/loader.d.ts +16 -0
- package/dist/core/tui/loader.js +94 -0
- package/dist/core/{canvas/browse → tui}/terminal.js +7 -6
- package/dist/core/wake.d.ts +86 -0
- package/dist/core/wake.js +308 -0
- package/dist/daemon/crtrd.d.ts +29 -4
- package/dist/daemon/crtrd.js +662 -46
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +171 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +19 -12
- package/dist/pi-extensions/canvas-commands.d.ts +3 -0
- package/dist/pi-extensions/canvas-commands.js +10 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +17 -0
- package/dist/pi-extensions/canvas-context-intro.js +55 -15
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +44 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +112 -0
- package/dist/pi-extensions/canvas-nav.d.ts +3 -0
- package/dist/pi-extensions/canvas-nav.js +87 -23
- package/dist/pi-extensions/canvas-stophook.js +17 -8
- package/dist/pi-extensions/canvas-view.d.ts +21 -0
- package/dist/pi-extensions/canvas-view.js +75 -0
- package/dist/prompts/skill.js +19 -26
- package/dist/prompts/view.d.ts +7 -0
- package/dist/prompts/view.js +101 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -0
- package/package.json +9 -4
- package/dist/commands/skill/find.d.ts +0 -4
- package/dist/commands/skill/find.js +0 -257
- package/dist/commands/skill/read.js +0 -91
- /package/dist/commands/{skill → memory}/read.d.ts +0 -0
- /package/dist/core/{canvas/browse → tui}/terminal.d.ts +0 -0
|
@@ -18,15 +18,22 @@
|
|
|
18
18
|
// alt+c is a tmux display-menu (not a pi key), so prefix chords (m/e/1-9/custom)
|
|
19
19
|
// are tmux menu items that route through `crtr canvas chord`.
|
|
20
20
|
//
|
|
21
|
-
// Selection /
|
|
22
|
-
// CURSOR (selected)
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
21
|
+
// Selection / attachment signals:
|
|
22
|
+
// CURSOR (selected) = reverse-video bar (ESC[7m), full width — an attribute,
|
|
23
|
+
// not a colour, so it reads under NO_COLOR.
|
|
24
|
+
// ATTACHED (watched) = a coloured background bar — a human is currently
|
|
25
|
+
// viewing the node: a `focuses` viewport points at it
|
|
26
|
+
// (tmux host) or ≥1 helloed viewer is connected to its
|
|
27
|
+
// broker (job/attach.json). Running is a separate axis,
|
|
28
|
+
// signaled by the dot glyph alone (● = engine active on
|
|
29
|
+
// its host — which may be an unwatched backstage pane
|
|
30
|
+
// or a paneless broker).
|
|
31
|
+
// SELF = bold name — a quiet "you are here" marker.
|
|
27
32
|
//
|
|
28
33
|
// Folding is auto by default: a branch stays COLLAPSED unless its subtree holds
|
|
29
34
|
// a running ('active') agent or self. h/l override that per-node and persist.
|
|
35
|
+
// A ▸ caret marks an expandable (collapsed-with-kids) row — but NOT the cursor
|
|
36
|
+
// row, whose reverse-video bar already sets it apart.
|
|
30
37
|
//
|
|
31
38
|
// ⚑K pending-asks is PER-NODE, inline on each waiting node's own row (manager,
|
|
32
39
|
// reports, tree rows; self shows a trailing ⚑ line in BASE). ⤳M direct-children
|
|
@@ -39,7 +46,7 @@
|
|
|
39
46
|
import { execFile, execFileSync } from 'node:child_process';
|
|
40
47
|
import { existsSync, readFileSync } from 'node:fs';
|
|
41
48
|
import { join } from 'node:path';
|
|
42
|
-
import { getNode, subscribersOf, subscriptionsOf, jobDir, fullName } from '../core/canvas/index.js';
|
|
49
|
+
import { getNode, subscribersOf, subscriptionsOf, jobDir, fullName, listFocuses } from '../core/canvas/index.js';
|
|
43
50
|
import { readConfig } from '../core/config.js';
|
|
44
51
|
// ---------------------------------------------------------------------------
|
|
45
52
|
// Module-level state — persists across /reload so guards don't stack and fold
|
|
@@ -80,17 +87,19 @@ const VIEWPORT_FALLBACK_ROWS = 30;
|
|
|
80
87
|
// ANSI styling. pi renders embedded escapes in widget lines and measures width
|
|
81
88
|
// ANSI-aware, so raw escapes are safe and need no pi-tui dependency. The cursor
|
|
82
89
|
// (selected row) uses a theme-agnostic ATTRIBUTE (reverse), so it reads under
|
|
83
|
-
// NO_COLOR; the
|
|
84
|
-
//
|
|
90
|
+
// NO_COLOR; the attached-row tint is a background COLOUR, while the dot glyph
|
|
91
|
+
// (●/○/✓/✗) carries the running signal independently, even where colour is
|
|
92
|
+
// stripped.
|
|
85
93
|
// ---------------------------------------------------------------------------
|
|
86
94
|
const ESC = '\x1b[';
|
|
87
95
|
const RESET = `${ESC}0m`;
|
|
88
96
|
const BOLD = `${ESC}1m`;
|
|
89
97
|
const DIM = `${ESC}2m`;
|
|
90
98
|
const REVERSE = `${ESC}7m`;
|
|
91
|
-
/** Dark-green background bar marking
|
|
92
|
-
* the cursor's reverse-video bar; chosen so
|
|
93
|
-
|
|
99
|
+
/** Dark-green background bar marking an ATTACHED node (a human is currently
|
|
100
|
+
* watching it) — distinct from the cursor's reverse-video bar; chosen so
|
|
101
|
+
* default-fg text stays readable. */
|
|
102
|
+
const BG_ATTACHED = `${ESC}48;5;22m`;
|
|
94
103
|
const GREEN = `${ESC}32m`;
|
|
95
104
|
const RED = `${ESC}31m`;
|
|
96
105
|
const YELLOW = `${ESC}33m`;
|
|
@@ -150,7 +159,7 @@ function fillWidth() {
|
|
|
150
159
|
return Math.max(20, Math.min((process.stdout.columns ?? 80) - 2, 180));
|
|
151
160
|
}
|
|
152
161
|
/** Wrap `content` in a full-width background bar opened by `open` (REVERSE for
|
|
153
|
-
* the cursor,
|
|
162
|
+
* the cursor, BG_ATTACHED for a human-watched node). `open` is re-asserted after every
|
|
154
163
|
* embedded RESET so a coloured cell (the status dot) can't punch a hole in the
|
|
155
164
|
* bar; the visible width is padded out to `width`; the line closes with a real
|
|
156
165
|
* RESET so the style never bleeds into the editor below. */
|
|
@@ -181,6 +190,42 @@ function shortId(id) {
|
|
|
181
190
|
return id.slice(0, 8);
|
|
182
191
|
}
|
|
183
192
|
// ---------------------------------------------------------------------------
|
|
193
|
+
// Attachment — is a human currently WATCHING a node? A separate axis from
|
|
194
|
+
// running (status 'active' = the engine is live on its host, which may be an
|
|
195
|
+
// unwatched backstage pane or a paneless broker). Two hosts, two signals:
|
|
196
|
+
// tmux — a `focuses` row points at the node (one cheap sqlite read per
|
|
197
|
+
// render pass; pane-existence alone is NOT the signal).
|
|
198
|
+
// broker — the broker persists its helloed-viewer count to job/attach.json
|
|
199
|
+
// on every viewer change (src/core/runtime/broker.ts). Trusted only
|
|
200
|
+
// while the node is 'active': a broker crash can leave a stale file.
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
/** Node ids currently shown in a tmux focus viewport. Built once per render. */
|
|
203
|
+
function focusedNodeIds() {
|
|
204
|
+
try {
|
|
205
|
+
return new Set(listFocuses().map((f) => f.node_id));
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return new Set();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** True when a human is watching `id` right now (tmux focus or broker viewer). */
|
|
212
|
+
function isAttached(id, node, focused) {
|
|
213
|
+
if (focused.has(id))
|
|
214
|
+
return true;
|
|
215
|
+
if (node?.status !== 'active')
|
|
216
|
+
return false; // stale attach.json from a crash
|
|
217
|
+
try {
|
|
218
|
+
const p = join(jobDir(id), 'attach.json');
|
|
219
|
+
if (!existsSync(p))
|
|
220
|
+
return false;
|
|
221
|
+
const rec = JSON.parse(readFileSync(p, 'utf8'));
|
|
222
|
+
return typeof rec.viewers === 'number' && rec.viewers > 0;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
184
229
|
// Per-node ask counts — ONE shell-out per poll. `crtr canvas attention map`
|
|
185
230
|
// buckets a whole sub-DAG's pending asks by node in a single process, so the
|
|
186
231
|
// timer stays cheap (< 2 s) regardless of how many nodes are visible. --json
|
|
@@ -357,12 +402,13 @@ function buildGraphModel(self) {
|
|
|
357
402
|
walk(rootId, '', true, true);
|
|
358
403
|
return rows;
|
|
359
404
|
}
|
|
360
|
-
/** Render one GRAPH row. CURSOR (selected) → reverse-video bar; an
|
|
361
|
-
* (
|
|
362
|
-
* outranks the
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
405
|
+
/** Render one GRAPH row. CURSOR (selected) → reverse-video bar; an ATTACHED
|
|
406
|
+
* (human-watched) node → a coloured background bar; SELF → bold name. The
|
|
407
|
+
* cursor outranks the attached tint when both land on the same row. Running
|
|
408
|
+
* is signaled by the dot glyph alone (● green = active engine). */
|
|
409
|
+
function renderGraphRow(r, isCursor, focused) {
|
|
410
|
+
const wrap = (line, attached) => isCursor ? fillBar(line, fillWidth(), REVERSE)
|
|
411
|
+
: attached ? fillBar(line, fillWidth(), BG_ATTACHED)
|
|
366
412
|
: truncate(line);
|
|
367
413
|
if (r.cycle) {
|
|
368
414
|
const line = `${r.branch} ${DIM}↺ ${shortId(r.id)}${RESET}`;
|
|
@@ -374,10 +420,14 @@ function renderGraphRow(r, isCursor) {
|
|
|
374
420
|
const name = r.isSelf ? `${BOLD}${rawName}${RESET}` : rawName;
|
|
375
421
|
const kind = `${DIM}${node?.kind ?? ''}${RESET}`;
|
|
376
422
|
const tokens = `${DIM}${tokensCell(r.id)}${RESET}`;
|
|
377
|
-
|
|
378
|
-
|
|
423
|
+
// ▸ marks an expandable (collapsed-with-kids) row. The cursor row gets no
|
|
424
|
+
// caret — its reverse-video bar already distinguishes it — so the triangle
|
|
425
|
+
// reads purely as "this unfolds".
|
|
426
|
+
const expandable = r.hasKids && r.collapsed;
|
|
427
|
+
const caret = !isCursor && expandable ? `${DIM}▸${RESET} ` : ' ';
|
|
428
|
+
const fold = expandable ? ` ${DIM}[+${childCount(r.id)}]${RESET}` : '';
|
|
379
429
|
const line = `${r.branch}${caret}${dot} ${name} ${kind} ${tokens}${childBadge(node)}${fold}${askBadge(r.id)}`;
|
|
380
|
-
return wrap(line, node
|
|
430
|
+
return wrap(line, isAttached(r.id, node, focused));
|
|
381
431
|
}
|
|
382
432
|
/** Total lines the GRAPH widget may emit. pi hard-caps extension widgets at
|
|
383
433
|
* MAX_WIDGET_LINES — anything past that pi truncates itself, eating our own
|
|
@@ -481,6 +531,10 @@ export function registerCanvasNav(pi) {
|
|
|
481
531
|
// Captured from session_start; used in every subsequent render.
|
|
482
532
|
let ui;
|
|
483
533
|
let renderScheduled = false;
|
|
534
|
+
// Run mode captured at session_start. The nav chrome + ask-poll timer are
|
|
535
|
+
// interactive-only; a headless ('print') broker leaves this non-'tui' so the
|
|
536
|
+
// timer no-ops (no per-tick `crtr` shell-out) and no chrome is rendered.
|
|
537
|
+
let liveMode;
|
|
484
538
|
// Cache config once (binds rarely change within a session; readConfig is sync
|
|
485
539
|
// and never throws). prefixKey drives the non-tmux GRAPH toggle shortcut.
|
|
486
540
|
let navConfig;
|
|
@@ -576,10 +630,11 @@ export function registerCanvasNav(pi) {
|
|
|
576
630
|
}
|
|
577
631
|
const end = Math.min(rows.length, scrollTop + viewportH);
|
|
578
632
|
const lines = [];
|
|
633
|
+
const focused = focusedNodeIds(); // one sqlite read per render pass
|
|
579
634
|
if (scrollTop > 0)
|
|
580
635
|
lines.push(`${DIM} ↑ ${scrollTop} more${RESET}`);
|
|
581
636
|
for (let i = scrollTop; i < end; i++)
|
|
582
|
-
lines.push(renderGraphRow(rows[i], i === cursorIdx));
|
|
637
|
+
lines.push(renderGraphRow(rows[i], i === cursorIdx, focused));
|
|
583
638
|
if (end < rows.length)
|
|
584
639
|
lines.push(`${DIM} ↓ ${rows.length - end} more${RESET}`);
|
|
585
640
|
const hint = pendingConfirm !== undefined
|
|
@@ -844,6 +899,12 @@ export function registerCanvasNav(pi) {
|
|
|
844
899
|
// Event handlers
|
|
845
900
|
// -------------------------------------------------------------------------
|
|
846
901
|
pi.on('session_start', (_event, ctx) => {
|
|
902
|
+
liveMode = ctx.mode;
|
|
903
|
+
// The nav chrome (widgets, key taps, the ask-poll timer) is interactive-only.
|
|
904
|
+
// A headless (print-mode) broker loads this extension but renders no chrome
|
|
905
|
+
// and must not poll. Under tmux ctx.mode is always 'tui' — byte-identical.
|
|
906
|
+
if (ctx.mode !== 'tui')
|
|
907
|
+
return;
|
|
847
908
|
ui = ctx.ui;
|
|
848
909
|
// Fresh session / hot-swap: start in BASE and clear any legacy or
|
|
849
910
|
// inactive-view widgets so nothing stale bleeds through.
|
|
@@ -887,6 +948,9 @@ export function registerCanvasNav(pi) {
|
|
|
887
948
|
if (liveTimer !== undefined)
|
|
888
949
|
clearInterval(liveTimer);
|
|
889
950
|
const timer = setInterval(() => {
|
|
951
|
+
// Inert in a headless ('print') broker — never shell out to `crtr` per tick.
|
|
952
|
+
if (liveMode !== 'tui')
|
|
953
|
+
return;
|
|
890
954
|
try {
|
|
891
955
|
const rootId = climbRoot(nodeId);
|
|
892
956
|
const fresh = fetchAsksMap(rootId);
|
|
@@ -500,14 +500,23 @@ export function registerCanvasStophook(pi) {
|
|
|
500
500
|
// down; the daemon watches its inbox and revives it (resume) the moment a
|
|
501
501
|
// subscribed worker delivers. An 'attended' root never releases: the human
|
|
502
502
|
// is its wake source, so we keep its window live and dormant.
|
|
503
|
-
if (decision.reason === 'awaiting') {
|
|
504
|
-
// AWAITING
|
|
505
|
-
//
|
|
506
|
-
//
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
503
|
+
if (decision.reason === 'awaiting' || decision.reason === 'scheduled') {
|
|
504
|
+
// AWAITING ≠ done (no manager-takeover). What happens next splits on
|
|
505
|
+
// whether the user is WATCHING this node:
|
|
506
|
+
// • FOCUSED → it holds the user's viewport, so keep pi LIVE and
|
|
507
|
+
// dormant (exactly like a resident root): do NOT release or shut
|
|
508
|
+
// down. The in-process inbox-watcher (still alive) wakes it the
|
|
509
|
+
// instant a worker pushes — no respawn, no frozen pane, the pane
|
|
510
|
+
// stays interactive. When the user later focuses AWAY, placement's
|
|
511
|
+
// retarget reclassifies it as a parked terminal viewer and releases
|
|
512
|
+
// it then (transition 'release' + pane reaped), so the kept-alive
|
|
513
|
+
// pi is reclaimed on focus-away, never held forever.
|
|
514
|
+
// • UNFOCUSED → no one is watching, so holding a live pi for a window
|
|
515
|
+
// is waste. Release it (idle + idle-release) and shut pi down; its
|
|
516
|
+
// backstage pane closes and the daemon revives it (resume) on the
|
|
517
|
+
// next unseen inbox entry.
|
|
518
|
+
if (focusOf(nodeId) !== null)
|
|
519
|
+
return; // focused → stay alive, dormant
|
|
511
520
|
transition(nodeId, 'release');
|
|
512
521
|
try {
|
|
513
522
|
ctx?.shutdown?.();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface CommandUI {
|
|
2
|
+
notify(message: string, type?: 'info' | 'warning' | 'error'): void;
|
|
3
|
+
}
|
|
4
|
+
interface CommandCtx {
|
|
5
|
+
mode: string;
|
|
6
|
+
ui: CommandUI;
|
|
7
|
+
}
|
|
8
|
+
interface PiLike {
|
|
9
|
+
registerCommand?(name: string, options: {
|
|
10
|
+
description?: string;
|
|
11
|
+
handler: (args: string, ctx: CommandCtx) => void | Promise<void>;
|
|
12
|
+
}): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Register the /view command on `pi`.
|
|
16
|
+
*
|
|
17
|
+
* Returns immediately when CRTR_NODE_ID is absent — the extension is fully
|
|
18
|
+
* inert in a non-canvas pi session.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerCanvasView(pi: PiLike): void;
|
|
21
|
+
export default registerCanvasView;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// canvas-view.ts — pi extension registering the /view canvas command.
|
|
2
|
+
//
|
|
3
|
+
// /view — open the view picker (`crtr view pick`) as a tmux popup:
|
|
4
|
+
// a raw-ANSI list of every available view; Enter hands off (one-way exec)
|
|
5
|
+
// to `crtr view run <id>`, which paints the full-screen view inside the
|
|
6
|
+
// same popup. Quitting the view closes the popup back to THIS pi pane.
|
|
7
|
+
// /view <name> — skip the picker and popup `crtr view run <name>` directly.
|
|
8
|
+
//
|
|
9
|
+
// Views are stateless render surfaces with NO pi session. Unlike /resume-node
|
|
10
|
+
// this command MUST NOT touch the node-focus / swap-pane / reviveNode path
|
|
11
|
+
// (spec Decision 8) — there is no pane to return to and no session to revive.
|
|
12
|
+
// The popup is fire-and-forget: it owns its own screen and closes itself when
|
|
13
|
+
// the view exits, dropping back to the pi pane on its own.
|
|
14
|
+
//
|
|
15
|
+
// crtr ONLY runs inside tmux (see crouter/CLAUDE.md) — there is no non-tmux
|
|
16
|
+
// fallback picker. Outside tmux the command notifies and no-ops.
|
|
17
|
+
//
|
|
18
|
+
// INERT when CRTR_NODE_ID is absent (a plain pi session, not a canvas node).
|
|
19
|
+
//
|
|
20
|
+
// Plain TS-with-types — no imports from @earendil-works/* so this compiles
|
|
21
|
+
// inside crouter's own tsc build without a dep on the pi packages (mirrors
|
|
22
|
+
// canvas-resume.ts / canvas-nav.ts / canvas-commands.ts).
|
|
23
|
+
import { execFile } from 'node:child_process';
|
|
24
|
+
/** Single-quote a string for safe interpolation into a `sh -c` command line —
|
|
25
|
+
* tmux runs the display-popup trailing string through the shell, so a view
|
|
26
|
+
* name with spaces or quotes must be escaped. */
|
|
27
|
+
function shellQuote(s) {
|
|
28
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Register the /view command on `pi`.
|
|
32
|
+
*
|
|
33
|
+
* Returns immediately when CRTR_NODE_ID is absent — the extension is fully
|
|
34
|
+
* inert in a non-canvas pi session.
|
|
35
|
+
*/
|
|
36
|
+
export function registerCanvasView(pi) {
|
|
37
|
+
const nodeId = process.env['CRTR_NODE_ID'];
|
|
38
|
+
if (nodeId === undefined || nodeId.trim() === '')
|
|
39
|
+
return; // not a canvas node
|
|
40
|
+
if (typeof pi.registerCommand !== 'function')
|
|
41
|
+
return;
|
|
42
|
+
pi.registerCommand('view', {
|
|
43
|
+
description: 'Open a view in a popup — bare for the picker, or /view <name> to open that view directly',
|
|
44
|
+
handler: async (args, ctx) => {
|
|
45
|
+
// The popup is terminal-only — guard the run mode before opening it.
|
|
46
|
+
if (ctx.mode !== 'tui') {
|
|
47
|
+
try {
|
|
48
|
+
ctx.ui.notify('/view needs the interactive TUI', 'warning');
|
|
49
|
+
}
|
|
50
|
+
catch { /* best-effort */ }
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// crtr only runs in tmux: open the view (picker, or a named view) as a
|
|
54
|
+
// popup. It owns the screen and closes itself when the view exits,
|
|
55
|
+
// dropping back to THIS pi pane — no node-focus, no return-pane.
|
|
56
|
+
// Fire-and-forget: tmux runs the trailing string through sh -c.
|
|
57
|
+
if (process.env['TMUX'] !== undefined) {
|
|
58
|
+
const name = args.trim();
|
|
59
|
+
// bare /view → the picker; /view <name> → that view directly.
|
|
60
|
+
const cmd = name === '' ? 'crtr view pick' : `crtr view run ${shellQuote(name)}`;
|
|
61
|
+
try {
|
|
62
|
+
execFile('tmux', ['display-popup', '-E', '-w', '90%', '-h', '85%', cmd], () => { });
|
|
63
|
+
}
|
|
64
|
+
catch { /* best-effort */ }
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Not in tmux → crtr is tmux-only, so there is nothing to fall back to.
|
|
68
|
+
try {
|
|
69
|
+
ctx.ui.notify('/view needs tmux', 'warning');
|
|
70
|
+
}
|
|
71
|
+
catch { /* best-effort */ }
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export default registerCanvasView;
|
package/dist/prompts/skill.js
CHANGED
|
@@ -108,7 +108,7 @@ ${topicLine(topic)}
|
|
|
108
108
|
- \`ls\` repo top level
|
|
109
109
|
- check stack manifests
|
|
110
110
|
- \`git log --oneline -15\` in this area
|
|
111
|
-
- \`crtr
|
|
111
|
+
- \`crtr memory find "<topic>"\` / \`crtr memory list\` — does a primer already exist?
|
|
112
112
|
|
|
113
113
|
If subsystem is small/self-evident, **stop**. Suggest a CLAUDE.md note. Primers
|
|
114
114
|
are for large, complicated, or unintuitive systems only.
|
|
@@ -116,7 +116,7 @@ are for large, complicated, or unintuitive systems only.
|
|
|
116
116
|
## 2. Scope + name
|
|
117
117
|
|
|
118
118
|
- **Scope**: \`project\` by default. \`user\` only if cross-repo.
|
|
119
|
-
- **Name**: kebab-case. Confirm no collision: \`crtr
|
|
119
|
+
- **Name**: kebab-case. Confirm no collision: \`crtr memory read <name>\` (returns \`.path\`, \`.scope\`).
|
|
120
120
|
|
|
121
121
|
## 3. Parallel exploration
|
|
122
122
|
|
|
@@ -182,9 +182,8 @@ Domain terms, invariants, non-obvious constraints.
|
|
|
182
182
|
Non-obvious coupling. Looks-broken-but-isn't. Past footguns.
|
|
183
183
|
\`\`\`
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
only for cross-plugin or distant refs.
|
|
185
|
+
Add a \`## Related\` section only for genuinely related skills — cross-plugin
|
|
186
|
+
or distant refs included; skip it when there is nothing worth pointing at.
|
|
188
187
|
|
|
189
188
|
**Density rules:**
|
|
190
189
|
- \`file:line\` over prose
|
|
@@ -200,9 +199,8 @@ only for cross-plugin or distant refs.
|
|
|
200
199
|
Output is JSON; \`.content\` has the body, \`.path\` has the location:
|
|
201
200
|
|
|
202
201
|
\`\`\`
|
|
203
|
-
crtr
|
|
204
|
-
crtr
|
|
205
|
-
crtr skill find search "<keyword>" # confirm description triggers discovery
|
|
202
|
+
crtr memory read <name>
|
|
203
|
+
crtr memory find "<keyword>" # confirm description triggers discovery
|
|
206
204
|
\`\`\`
|
|
207
205
|
|
|
208
206
|
Sharpen description if discovery misses. Cut body if bloated.
|
|
@@ -251,7 +249,7 @@ PR over many small ones for refactors here, because review churn dominates"*
|
|
|
251
249
|
|
|
252
250
|
- **Scope**: \`user\` for cross-project methodology. \`project\` for repo-specific.
|
|
253
251
|
- **Name**: kebab-case, verb-or-noun-phrase. Not "guide-to-X".
|
|
254
|
-
- Check \`crtr
|
|
252
|
+
- Check \`crtr memory read <name>\` (returns \`.path\`, \`.scope\`).
|
|
255
253
|
|
|
256
254
|
## 3. Scaffold
|
|
257
255
|
|
|
@@ -301,9 +299,8 @@ to read the whole thing for value, you've buried the judgment.
|
|
|
301
299
|
- **<name>**: what it looks like; how to avoid
|
|
302
300
|
\`\`\`
|
|
303
301
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
only for cross-plugin or distant refs.
|
|
302
|
+
Add a \`## Related\` section only for genuinely related skills — cross-plugin
|
|
303
|
+
or distant refs included; skip it when there is nothing worth pointing at.
|
|
307
304
|
|
|
308
305
|
## 6. Progressive disclosure
|
|
309
306
|
|
|
@@ -324,9 +321,8 @@ loads supporting files only when needed.
|
|
|
324
321
|
Output is JSON; \`.content\` has the body, \`.path\` has the location:
|
|
325
322
|
|
|
326
323
|
\`\`\`
|
|
327
|
-
crtr
|
|
328
|
-
crtr
|
|
329
|
-
crtr skill find search "<keyword>"
|
|
324
|
+
crtr memory read <name>
|
|
325
|
+
crtr memory find "<keyword>"
|
|
330
326
|
\`\`\`
|
|
331
327
|
|
|
332
328
|
## Constraints
|
|
@@ -415,9 +411,8 @@ Or invent your own. Stay tight — no padding.
|
|
|
415
411
|
Output is JSON; \`.content\` has the body, \`.path\` has the location:
|
|
416
412
|
|
|
417
413
|
\`\`\`
|
|
418
|
-
crtr
|
|
419
|
-
crtr
|
|
420
|
-
crtr skill find search "<keyword>"
|
|
414
|
+
crtr memory read <name>
|
|
415
|
+
crtr memory find "<keyword>"
|
|
421
416
|
\`\`\`
|
|
422
417
|
|
|
423
418
|
## Switch templates if needed
|
|
@@ -469,7 +464,7 @@ field/flag/code values** — pull verbatim from source.
|
|
|
469
464
|
|
|
470
465
|
- **Scope**: \`user\` for cross-project facts. \`project\` for repo-specific.
|
|
471
466
|
- **Name**: noun-phrase. \`http-status-codes\` not \`learn-http-status\`.
|
|
472
|
-
- Check \`crtr
|
|
467
|
+
- Check \`crtr memory read <name>\` (returns \`.path\`, \`.scope\`).
|
|
473
468
|
|
|
474
469
|
## 3. Scaffold
|
|
475
470
|
|
|
@@ -530,9 +525,8 @@ SKILL.md links to siblings (\`see [full-table.md](full-table.md)\`).
|
|
|
530
525
|
Output is JSON; \`.content\` has the body, \`.path\` has the location:
|
|
531
526
|
|
|
532
527
|
\`\`\`
|
|
533
|
-
crtr
|
|
534
|
-
crtr
|
|
535
|
-
crtr skill find search "<keyword>"
|
|
528
|
+
crtr memory read <name>
|
|
529
|
+
crtr memory find "<keyword>"
|
|
536
530
|
\`\`\`
|
|
537
531
|
|
|
538
532
|
Search must surface the skill on a typical lookup query. Sharpen the
|
|
@@ -582,7 +576,7 @@ push to \\\`main\\\`, wait for green CI, click promote"* is a runbook step.
|
|
|
582
576
|
|
|
583
577
|
- **Scope**: \`project\` for repo-specific procedures. \`user\` for cross-project.
|
|
584
578
|
- **Name**: verb-phrase. \`deploy-to-prod\` not \`production-deployment-guide\`.
|
|
585
|
-
- Check \`crtr
|
|
579
|
+
- Check \`crtr memory read <name>\` (returns \`.path\`, \`.scope\`).
|
|
586
580
|
|
|
587
581
|
## 3. Scaffold
|
|
588
582
|
|
|
@@ -637,9 +631,8 @@ crtr skill author scaffold <name> --type runbook --scope <user|project> --descri
|
|
|
637
631
|
Output is JSON; \`.content\` has the body, \`.path\` has the location:
|
|
638
632
|
|
|
639
633
|
\`\`\`
|
|
640
|
-
crtr
|
|
641
|
-
crtr
|
|
642
|
-
crtr skill find search "<keyword>"
|
|
634
|
+
crtr memory read <name>
|
|
635
|
+
crtr memory find "<keyword>"
|
|
643
636
|
\`\`\`
|
|
644
637
|
|
|
645
638
|
Walk through the runbook mentally. Each step verifiable? Each decision
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Scaffold stub for `crtr view new`. Returns the contents of a runnable
|
|
2
|
+
// `view.mjs` — a minimal, self-contained ViewModule that runs as-is via
|
|
3
|
+
// `crtr view run <name>` and prints a sane snapshot when piped (`| cat`).
|
|
4
|
+
//
|
|
5
|
+
// Authoring guidance lives INSIDE the stub (the comment block at the top of the
|
|
6
|
+
// generated file), so a view author reads the contract right where they edit.
|
|
7
|
+
/** Escape a value for embedding inside a single-quoted JS string literal. */
|
|
8
|
+
function jsStr(s) {
|
|
9
|
+
return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
10
|
+
}
|
|
11
|
+
/** Build the `view.mjs` source for a freshly scaffolded view. */
|
|
12
|
+
export function viewScaffold(v) {
|
|
13
|
+
const id = jsStr(v.id);
|
|
14
|
+
const title = jsStr(v.title);
|
|
15
|
+
const description = jsStr(v.description);
|
|
16
|
+
return `// ${v.title} — a crtr view.
|
|
17
|
+
//
|
|
18
|
+
// A view is a self-contained ESM module the \`crtr view\` host loads and runs.
|
|
19
|
+
// Run it: crtr view run ${v.id} (interactive, inside tmux)
|
|
20
|
+
// crtr view run ${v.id} | cat (static snapshot, exits 0)
|
|
21
|
+
//
|
|
22
|
+
// THE CONTRACT (the host injects everything — import NOTHING from crtr):
|
|
23
|
+
// manifest { id, title, description, refreshMs?, keymap? }
|
|
24
|
+
// id MUST equal this view's directory name.
|
|
25
|
+
// init(host) build initial state — keep it CHEAP and sync-ish;
|
|
26
|
+
// do NOT do slow fetches here (do them in refresh).
|
|
27
|
+
// refresh(state,host) async data load; the host runs it on launch, every
|
|
28
|
+
// manifest.refreshMs (if set), and whenever a key handler
|
|
29
|
+
// returns { type: 'refresh' }. Mutate state in place.
|
|
30
|
+
// render(state,draw,content) paint into the \`content\` Rect via draw.* —
|
|
31
|
+
// a pure read of state; NEVER write ANSI yourself.
|
|
32
|
+
// onKey(k,state,host) handle one keystroke; mutate state; return a ViewAction.
|
|
33
|
+
// dump(state) plain text for the piped / non-TTY path (exit 0).
|
|
34
|
+
//
|
|
35
|
+
// draw API (all absolute cells inside \`content\`):
|
|
36
|
+
// draw.text(row,col,text,style?) · draw.spans(row,col,spans,maxWidth?)
|
|
37
|
+
// draw.hline(row,fromCol?,toCol?) · draw.box(rect,title?)
|
|
38
|
+
// draw.columns(rect,[1,2]) -> Rect[] (proportional split)
|
|
39
|
+
// draw.list(rect,items,cursor,scroll) -> { scroll } (windows + cursor row)
|
|
40
|
+
// style: { fg, bg, bold, dim, reverse } (fg/bg honored only when color is on)
|
|
41
|
+
// host API:
|
|
42
|
+
// host.options CLI --flags, camelCased & stringified (e.g. options.port)
|
|
43
|
+
// host.setStatus(msg) transient footer-left status; null clears it
|
|
44
|
+
// host.setError(msg) sticky red banner above the footer; null clears it
|
|
45
|
+
// ViewAction: { type: 'render' | 'refresh' | 'quit' | 'none' }
|
|
46
|
+
|
|
47
|
+
/** @type {import('@crouton-kit/crouter/dist/core/tui/contract.js').ViewModule} */
|
|
48
|
+
const view = {
|
|
49
|
+
manifest: {
|
|
50
|
+
id: '${id}',
|
|
51
|
+
title: '${title}',
|
|
52
|
+
description: '${description}',
|
|
53
|
+
// refreshMs: 30000, // uncomment to auto-poll; omit ⇒ on-demand (g) only
|
|
54
|
+
keymap: [
|
|
55
|
+
{ keys: 'g', label: 'refresh' },
|
|
56
|
+
{ keys: 'q', label: 'quit' },
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
init(host) {
|
|
61
|
+
// Cheap, synchronous setup. Stash CLI flags off host.options here.
|
|
62
|
+
return { count: 0, port: host.options.port ?? null };
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
async refresh(state, host) {
|
|
66
|
+
// Load your data here (shell out, fetch, read files). Mutate \`state\`.
|
|
67
|
+
state.count += 1;
|
|
68
|
+
host.setStatus(\`refreshed \${state.count}×\`);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
render(state, draw, content) {
|
|
72
|
+
draw.text(content.row, content.col, '${title}', { bold: true });
|
|
73
|
+
draw.text(content.row + 2, content.col, \`refreshed \${state.count} time(s)\`);
|
|
74
|
+
draw.text(content.row + 3, content.col, \`port option: \${state.port ?? '(none)'}\`, { dim: true });
|
|
75
|
+
draw.text(
|
|
76
|
+
content.row + 5,
|
|
77
|
+
content.col,
|
|
78
|
+
'Edit view.mjs to build your view — g refreshes, q quits.',
|
|
79
|
+
{ dim: true },
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
onKey(k, state, host) {
|
|
84
|
+
if (k.input === 'q') return { type: 'quit' };
|
|
85
|
+
if (k.input === 'g') return { type: 'refresh' };
|
|
86
|
+
return { type: 'none' };
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
dump(state) {
|
|
90
|
+
return [
|
|
91
|
+
'${title}',
|
|
92
|
+
'',
|
|
93
|
+
\`refreshed \${state.count} time(s)\`,
|
|
94
|
+
\`port option: \${state.port ?? '(none)'}\`,
|
|
95
|
+
].join('\\n');
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default view;
|
|
100
|
+
`;
|
|
101
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -83,6 +83,10 @@ export interface ScopeConfig {
|
|
|
83
83
|
auto_update: AutoUpdateConfig;
|
|
84
84
|
max_panes_per_window: number;
|
|
85
85
|
canvasNav: CanvasNavConfig;
|
|
86
|
+
/** Default to spawning nodes on the headless broker host instead of a tmux
|
|
87
|
+
* pane. Off by default (tmux stays the default); `--headless` overrides it
|
|
88
|
+
* per-spawn. Read at spawn via `readConfig('user').headless`. */
|
|
89
|
+
headless?: boolean;
|
|
86
90
|
}
|
|
87
91
|
export interface ScopeState {
|
|
88
92
|
marketplaces: Record<string, {
|
package/dist/types.js
CHANGED
|
@@ -37,6 +37,7 @@ export function defaultScopeConfig() {
|
|
|
37
37
|
auto_update: { crtr: 'notify', content: 'notify', interval_hours: 24 },
|
|
38
38
|
max_panes_per_window: DEFAULT_MAX_PANES_PER_WINDOW,
|
|
39
39
|
canvasNav: defaultCanvasNavConfig(),
|
|
40
|
+
headless: false,
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
/** Built-in canvas-nav binds so an absent config still gives the intended UX.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crouton-kit/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.19",
|
|
4
4
|
"description": "crtr — fast access to skills, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"bin"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "rm -rf dist && tsc && cp -R src/builtin-skills dist/builtin-skills && cp -R src/builtin-personas dist/builtin-personas",
|
|
27
|
+
"build": "rm -rf dist && tsc && cp -R src/builtin-skills dist/builtin-skills && cp -R src/builtin-personas dist/builtin-personas && cp -R src/builtin-views dist/builtin-views && cp -R src/builtin-memory dist/builtin-memory",
|
|
28
28
|
"dev": "tsx src/cli.ts",
|
|
29
29
|
"link": "npm link",
|
|
30
30
|
"prepublishOnly": "npm run build",
|
|
@@ -36,8 +36,13 @@
|
|
|
36
36
|
},
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@crouton-kit/humanloop": "^0.3.
|
|
40
|
-
"
|
|
39
|
+
"@crouton-kit/humanloop": "^0.3.16",
|
|
40
|
+
"@earendil-works/pi-ai": "^0.79.0",
|
|
41
|
+
"@earendil-works/pi-coding-agent": "^0.79.0",
|
|
42
|
+
"@earendil-works/pi-tui": "^0.79.0",
|
|
43
|
+
"commander": "^13.0.0",
|
|
44
|
+
"cron-parser": "5.5.0",
|
|
45
|
+
"yaml": "^2.9.0"
|
|
41
46
|
},
|
|
42
47
|
"devDependencies": {
|
|
43
48
|
"@types/node": "^22.0.0",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare const findList: import("../../core/command.js").LeafDef;
|
|
2
|
-
export declare const findSearch: import("../../core/command.js").LeafDef;
|
|
3
|
-
export declare const findGrep: import("../../core/command.js").LeafDef;
|
|
4
|
-
export declare const findBranch: import("../../core/command.js").BranchDef;
|