@crouton-kit/crouter 0.3.17 → 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/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/design/orchestrator.md +1 -1
- package/dist/builtin-personas/developer/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/developer/orchestrator.md +1 -1
- package/dist/builtin-personas/explore/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/general/{base.md → PERSONA.md} +4 -0
- 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/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/plan/orchestrator.md +1 -1
- package/dist/builtin-personas/plan/reviewers/architecture-fit/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/code-smells/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/pattern-consistency/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/requirements-coverage/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/security/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/review/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/runtime-base.md +6 -3
- package/dist/builtin-personas/spec/{base.md → PERSONA.md} +4 -0
- 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/SKILL.md +24 -14
- package/dist/builtin-skills/skills/crouter-development/personas/base-prompt/SKILL.md +4 -4
- 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 +4 -3
- package/dist/commands/human/prompts.js +4 -10
- package/dist/commands/human/queue.js +43 -8
- package/dist/commands/human/shared.d.ts +28 -1
- package/dist/commands/human/shared.js +48 -10
- 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 +660 -65
- 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__/human-surface-target.test.d.ts +1 -0
- package/dist/core/__tests__/human-surface-target.test.js +98 -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__/persona-subkind.test.js +18 -15
- 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/paths.d.ts +4 -1
- package/dist/core/canvas/paths.js +10 -4
- 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/types.js +2 -2
- 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/help.d.ts +6 -0
- package/dist/core/help.js +7 -0
- package/dist/core/memory-resolver.d.ts +49 -0
- package/dist/core/memory-resolver.js +141 -0
- package/dist/core/personas/index.d.ts +4 -3
- package/dist/core/personas/index.js +3 -2
- package/dist/core/personas/loader.d.ts +41 -16
- package/dist/core/personas/loader.js +133 -29
- package/dist/core/personas/resolve.d.ts +4 -4
- package/dist/core/personas/resolve.js +28 -16
- 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 +42 -14
- package/dist/core/runtime/placement.js +228 -38
- 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 +25 -1
- package/dist/core/spawn.js +72 -7
- 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 +145 -34
- 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,9 +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
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
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.
|
|
32
|
+
//
|
|
33
|
+
// Folding is auto by default: a branch stays COLLAPSED unless its subtree holds
|
|
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.
|
|
24
37
|
//
|
|
25
38
|
// ⚑K pending-asks is PER-NODE, inline on each waiting node's own row (manager,
|
|
26
39
|
// reports, tree rows; self shows a trailing ⚑ line in BASE). ⤳M direct-children
|
|
@@ -33,7 +46,7 @@
|
|
|
33
46
|
import { execFile, execFileSync } from 'node:child_process';
|
|
34
47
|
import { existsSync, readFileSync } from 'node:fs';
|
|
35
48
|
import { join } from 'node:path';
|
|
36
|
-
import { getNode, subscribersOf, subscriptionsOf, jobDir, fullName } from '../core/canvas/index.js';
|
|
49
|
+
import { getNode, subscribersOf, subscriptionsOf, jobDir, fullName, listFocuses } from '../core/canvas/index.js';
|
|
37
50
|
import { readConfig } from '../core/config.js';
|
|
38
51
|
// ---------------------------------------------------------------------------
|
|
39
52
|
// Module-level state — persists across /reload so guards don't stack and fold
|
|
@@ -45,10 +58,13 @@ let liveTimer;
|
|
|
45
58
|
* exactly one key tap exists (mirrors the liveTimer double-guard). */
|
|
46
59
|
let liveUnsub;
|
|
47
60
|
let view = 'base';
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
61
|
+
/** Manual fold OVERRIDES in GRAPH, keyed by id (so a topology change can't
|
|
62
|
+
* corrupt them; stale ids are ignored). They override the default policy —
|
|
63
|
+
* collapsed UNLESS the subtree holds a running ('active') agent or self (see
|
|
64
|
+
* computeDefaultExpanded). `h` collapses → userCollapsed; `l` expands →
|
|
65
|
+
* userExpanded. Both survive renders AND BASE↔GRAPH toggles. */
|
|
66
|
+
const userCollapsed = new Set();
|
|
67
|
+
const userExpanded = new Set();
|
|
52
68
|
/** GRAPH cursor (a node id, not an index — indices shift as topology changes). */
|
|
53
69
|
let cursorId;
|
|
54
70
|
/** GRAPH viewport scroll offset (row index of the top visible row). */
|
|
@@ -69,16 +85,21 @@ const PI_MAX_WIDGET_LINES = 10;
|
|
|
69
85
|
const VIEWPORT_FALLBACK_ROWS = 30;
|
|
70
86
|
// ---------------------------------------------------------------------------
|
|
71
87
|
// ANSI styling. pi renders embedded escapes in widget lines and measures width
|
|
72
|
-
// ANSI-aware, so raw escapes are safe and need no pi-tui dependency.
|
|
73
|
-
// uses theme-agnostic
|
|
74
|
-
//
|
|
75
|
-
//
|
|
88
|
+
// ANSI-aware, so raw escapes are safe and need no pi-tui dependency. The cursor
|
|
89
|
+
// (selected row) uses a theme-agnostic ATTRIBUTE (reverse), so it reads under
|
|
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.
|
|
76
93
|
// ---------------------------------------------------------------------------
|
|
77
94
|
const ESC = '\x1b[';
|
|
78
95
|
const RESET = `${ESC}0m`;
|
|
79
96
|
const BOLD = `${ESC}1m`;
|
|
80
97
|
const DIM = `${ESC}2m`;
|
|
81
98
|
const REVERSE = `${ESC}7m`;
|
|
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`;
|
|
82
103
|
const GREEN = `${ESC}32m`;
|
|
83
104
|
const RED = `${ESC}31m`;
|
|
84
105
|
const YELLOW = `${ESC}33m`;
|
|
@@ -137,15 +158,16 @@ function truncate(s, max = fillWidth()) {
|
|
|
137
158
|
function fillWidth() {
|
|
138
159
|
return Math.max(20, Math.min((process.stdout.columns ?? 80) - 2, 180));
|
|
139
160
|
}
|
|
140
|
-
/** Wrap `content` in a full-width
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* closes with a real
|
|
144
|
-
|
|
161
|
+
/** Wrap `content` in a full-width background bar opened by `open` (REVERSE for
|
|
162
|
+
* the cursor, BG_ATTACHED for a human-watched node). `open` is re-asserted after every
|
|
163
|
+
* embedded RESET so a coloured cell (the status dot) can't punch a hole in the
|
|
164
|
+
* bar; the visible width is padded out to `width`; the line closes with a real
|
|
165
|
+
* RESET so the style never bleeds into the editor below. */
|
|
166
|
+
function fillBar(content, width, open) {
|
|
145
167
|
const clipped = truncate(content, width);
|
|
146
|
-
const reasserted = clipped.replace(/\x1b\[0m/g, `${RESET}${
|
|
168
|
+
const reasserted = clipped.replace(/\x1b\[0m/g, `${RESET}${open}`);
|
|
147
169
|
const pad = Math.max(0, width - visibleWidth(clipped));
|
|
148
|
-
return `${
|
|
170
|
+
return `${open}${reasserted}${' '.repeat(pad)}${RESET}`;
|
|
149
171
|
}
|
|
150
172
|
function readTelemetry(nodeId) {
|
|
151
173
|
try {
|
|
@@ -168,6 +190,42 @@ function shortId(id) {
|
|
|
168
190
|
return id.slice(0, 8);
|
|
169
191
|
}
|
|
170
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
|
+
// ---------------------------------------------------------------------------
|
|
171
229
|
// Per-node ask counts — ONE shell-out per poll. `crtr canvas attention map`
|
|
172
230
|
// buckets a whole sub-DAG's pending asks by node in a single process, so the
|
|
173
231
|
// timer stays cheap (< 2 s) regardless of how many nodes are visible. --json
|
|
@@ -294,21 +352,48 @@ function statusRank(id) {
|
|
|
294
352
|
function sortedChildIds(id) {
|
|
295
353
|
return convoChildIds(id).sort((a, b) => statusRank(a) - statusRank(b));
|
|
296
354
|
}
|
|
355
|
+
/** Default fold policy: which nodes auto-EXPAND. A node expands only when one
|
|
356
|
+
* of its child subtrees holds a running ('active') agent or self — so the path
|
|
357
|
+
* to any live agent (and to you) is revealed while quiescent branches stay
|
|
358
|
+
* folded. One bottom-up O(N) pass from the ancestry root; cycle-guarded. */
|
|
359
|
+
function computeDefaultExpanded(root, self) {
|
|
360
|
+
const expand = new Set();
|
|
361
|
+
const seen = new Set();
|
|
362
|
+
// Returns whether subtree(id), INCLUDING id, holds an active node or self.
|
|
363
|
+
const visit = (id) => {
|
|
364
|
+
if (seen.has(id))
|
|
365
|
+
return id === self || getNode(id)?.status === 'active';
|
|
366
|
+
seen.add(id);
|
|
367
|
+
let childRevealing = false;
|
|
368
|
+
for (const c of convoChildIds(id))
|
|
369
|
+
if (visit(c))
|
|
370
|
+
childRevealing = true;
|
|
371
|
+
if (childRevealing)
|
|
372
|
+
expand.add(id); // a descendant is worth revealing → unfold id
|
|
373
|
+
return childRevealing || id === self || getNode(id)?.status === 'active';
|
|
374
|
+
};
|
|
375
|
+
visit(root);
|
|
376
|
+
return expand;
|
|
377
|
+
}
|
|
297
378
|
function buildGraphModel(self) {
|
|
298
379
|
const rootId = climbRoot(self);
|
|
380
|
+
const defaultExpanded = computeDefaultExpanded(rootId, self);
|
|
381
|
+
// userExpanded / userCollapsed override the auto policy; absent → policy decides.
|
|
382
|
+
const isFolded = (id) => userExpanded.has(id) ? false : userCollapsed.has(id) ? true : !defaultExpanded.has(id);
|
|
299
383
|
const rows = [];
|
|
300
384
|
const visited = new Set();
|
|
301
385
|
const walk = (id, prefix, isRoot, isLast) => {
|
|
302
386
|
if (visited.has(id)) {
|
|
303
387
|
const connector = isRoot ? '' : isLast ? '└─ ' : '├─ ';
|
|
304
|
-
rows.push({ id, hasKids: false, isSelf: id === self, branch: prefix + connector, cycle: true });
|
|
388
|
+
rows.push({ id, hasKids: false, isSelf: id === self, branch: prefix + connector, cycle: true, collapsed: false });
|
|
305
389
|
return;
|
|
306
390
|
}
|
|
307
391
|
visited.add(id);
|
|
308
392
|
const kids = sortedChildIds(id);
|
|
393
|
+
const folded = isFolded(id);
|
|
309
394
|
const connector = isRoot ? '' : isLast ? '└─ ' : '├─ ';
|
|
310
|
-
rows.push({ id, hasKids: kids.length > 0, isSelf: id === self, branch: prefix + connector, cycle: false });
|
|
311
|
-
if (
|
|
395
|
+
rows.push({ id, hasKids: kids.length > 0, isSelf: id === self, branch: prefix + connector, cycle: false, collapsed: folded });
|
|
396
|
+
if (folded)
|
|
312
397
|
return; // folded — don't descend
|
|
313
398
|
const childPrefix = isRoot ? '' : prefix + (isLast ? ' ' : '│ ');
|
|
314
399
|
for (let i = 0; i < kids.length; i++)
|
|
@@ -317,22 +402,32 @@ function buildGraphModel(self) {
|
|
|
317
402
|
walk(rootId, '', true, true);
|
|
318
403
|
return rows;
|
|
319
404
|
}
|
|
320
|
-
/** Render one GRAPH row.
|
|
321
|
-
|
|
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)
|
|
412
|
+
: truncate(line);
|
|
322
413
|
if (r.cycle) {
|
|
323
414
|
const line = `${r.branch} ${DIM}↺ ${shortId(r.id)}${RESET}`;
|
|
324
|
-
return
|
|
415
|
+
return wrap(line, false);
|
|
325
416
|
}
|
|
326
417
|
const node = getNode(r.id);
|
|
327
418
|
const dot = coloredGlyph(node);
|
|
328
419
|
const rawName = node !== null ? fullName(node) : shortId(r.id);
|
|
329
|
-
const name =
|
|
420
|
+
const name = r.isSelf ? `${BOLD}${rawName}${RESET}` : rawName;
|
|
330
421
|
const kind = `${DIM}${node?.kind ?? ''}${RESET}`;
|
|
331
422
|
const tokens = `${DIM}${tokensCell(r.id)}${RESET}`;
|
|
332
|
-
|
|
333
|
-
|
|
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}` : '';
|
|
334
429
|
const line = `${r.branch}${caret}${dot} ${name} ${kind} ${tokens}${childBadge(node)}${fold}${askBadge(r.id)}`;
|
|
335
|
-
return
|
|
430
|
+
return wrap(line, isAttached(r.id, node, focused));
|
|
336
431
|
}
|
|
337
432
|
/** Total lines the GRAPH widget may emit. pi hard-caps extension widgets at
|
|
338
433
|
* MAX_WIDGET_LINES — anything past that pi truncates itself, eating our own
|
|
@@ -436,6 +531,10 @@ export function registerCanvasNav(pi) {
|
|
|
436
531
|
// Captured from session_start; used in every subsequent render.
|
|
437
532
|
let ui;
|
|
438
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;
|
|
439
538
|
// Cache config once (binds rarely change within a session; readConfig is sync
|
|
440
539
|
// and never throws). prefixKey drives the non-tmux GRAPH toggle shortcut.
|
|
441
540
|
let navConfig;
|
|
@@ -531,10 +630,11 @@ export function registerCanvasNav(pi) {
|
|
|
531
630
|
}
|
|
532
631
|
const end = Math.min(rows.length, scrollTop + viewportH);
|
|
533
632
|
const lines = [];
|
|
633
|
+
const focused = focusedNodeIds(); // one sqlite read per render pass
|
|
534
634
|
if (scrollTop > 0)
|
|
535
635
|
lines.push(`${DIM} ↑ ${scrollTop} more${RESET}`);
|
|
536
636
|
for (let i = scrollTop; i < end; i++)
|
|
537
|
-
lines.push(renderGraphRow(rows[i], i === cursorIdx));
|
|
637
|
+
lines.push(renderGraphRow(rows[i], i === cursorIdx, focused));
|
|
538
638
|
if (end < rows.length)
|
|
539
639
|
lines.push(`${DIM} ↓ ${rows.length - end} more${RESET}`);
|
|
540
640
|
const hint = pendingConfirm !== undefined
|
|
@@ -677,8 +777,9 @@ export function registerCanvasNav(pi) {
|
|
|
677
777
|
return { consume: true };
|
|
678
778
|
}
|
|
679
779
|
if (isPlain(data, 'h')) {
|
|
680
|
-
if (cur !== undefined && cur.hasKids && !
|
|
681
|
-
|
|
780
|
+
if (cur !== undefined && cur.hasKids && !cur.collapsed) {
|
|
781
|
+
userCollapsed.add(cur.id);
|
|
782
|
+
userExpanded.delete(cur.id);
|
|
682
783
|
}
|
|
683
784
|
else {
|
|
684
785
|
const p = managerOf(cursorId ?? nodeId);
|
|
@@ -689,8 +790,9 @@ export function registerCanvasNav(pi) {
|
|
|
689
790
|
return { consume: true };
|
|
690
791
|
}
|
|
691
792
|
if (isPlain(data, 'l')) {
|
|
692
|
-
if (cur !== undefined && collapsed
|
|
693
|
-
|
|
793
|
+
if (cur !== undefined && cur.collapsed && cur.hasKids) {
|
|
794
|
+
userExpanded.add(cur.id);
|
|
795
|
+
userCollapsed.delete(cur.id);
|
|
694
796
|
}
|
|
695
797
|
else if (cur !== undefined && cur.hasKids) {
|
|
696
798
|
const c = sortedChildIds(cur.id)[0];
|
|
@@ -797,6 +899,12 @@ export function registerCanvasNav(pi) {
|
|
|
797
899
|
// Event handlers
|
|
798
900
|
// -------------------------------------------------------------------------
|
|
799
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;
|
|
800
908
|
ui = ctx.ui;
|
|
801
909
|
// Fresh session / hot-swap: start in BASE and clear any legacy or
|
|
802
910
|
// inactive-view widgets so nothing stale bleeds through.
|
|
@@ -840,6 +948,9 @@ export function registerCanvasNav(pi) {
|
|
|
840
948
|
if (liveTimer !== undefined)
|
|
841
949
|
clearInterval(liveTimer);
|
|
842
950
|
const timer = setInterval(() => {
|
|
951
|
+
// Inert in a headless ('print') broker — never shell out to `crtr` per tick.
|
|
952
|
+
if (liveMode !== 'tui')
|
|
953
|
+
return;
|
|
843
954
|
try {
|
|
844
955
|
const rootId = climbRoot(nodeId);
|
|
845
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
|