@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.
Files changed (257) hide show
  1. package/dist/build-root.js +6 -0
  2. package/dist/builtin-memory/crouter-development/marketplaces.md +164 -0
  3. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +58 -0
  4. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +60 -0
  5. package/dist/builtin-memory/crouter-development/personas.md +117 -0
  6. package/dist/builtin-memory/crouter-development/plugins.md +163 -0
  7. package/dist/builtin-memory/design.md +60 -0
  8. package/dist/builtin-memory/development.md +116 -0
  9. package/dist/builtin-memory/planning.md +66 -0
  10. package/dist/builtin-memory/spec.md +99 -0
  11. package/dist/builtin-personas/design/orchestrator.md +1 -1
  12. package/dist/builtin-personas/developer/orchestrator.md +1 -1
  13. package/dist/builtin-personas/lifecycle/resident.md +1 -1
  14. package/dist/builtin-personas/lifecycle/terminal.md +5 -2
  15. package/dist/builtin-personas/orchestration-kernel.md +15 -24
  16. package/dist/builtin-personas/plan/orchestrator.md +1 -1
  17. package/dist/builtin-personas/runtime-base.md +6 -3
  18. package/dist/builtin-personas/spec/orchestrator.md +1 -1
  19. package/dist/builtin-personas/waiting.md +8 -0
  20. package/dist/builtin-skills/skills/crouter-development/personas/orchestrator-prompt/SKILL.md +1 -1
  21. package/dist/builtin-skills/skills/crouter-development/plugins/SKILL.md +2 -2
  22. package/dist/builtin-views/_lib/states.mjs +161 -0
  23. package/dist/builtin-views/canvas/client.mjs +303 -0
  24. package/dist/builtin-views/canvas/view.mjs +576 -0
  25. package/dist/builtin-views/git-pr/client.mjs +440 -0
  26. package/dist/builtin-views/git-pr/view.mjs +675 -0
  27. package/dist/builtin-views/inbox/_lib/render.mjs +177 -0
  28. package/dist/builtin-views/inbox/sources/gmail.mjs +965 -0
  29. package/dist/builtin-views/inbox/sources/linkedin.mjs +427 -0
  30. package/dist/builtin-views/inbox/view.mjs +889 -0
  31. package/dist/builtin-views/linkedin/client.mjs +610 -0
  32. package/dist/builtin-views/linkedin/view.mjs +1171 -0
  33. package/dist/clients/attach/attach-cmd.d.ts +2 -0
  34. package/dist/clients/attach/attach-cmd.js +354 -0
  35. package/dist/clients/attach/chat-view.d.ts +77 -0
  36. package/dist/clients/attach/chat-view.js +450 -0
  37. package/dist/clients/attach/clipboard-image.d.ts +16 -0
  38. package/dist/clients/attach/clipboard-image.js +113 -0
  39. package/dist/clients/attach/config-load.d.ts +31 -0
  40. package/dist/clients/attach/config-load.js +113 -0
  41. package/dist/clients/attach/extension-dialogs.d.ts +29 -0
  42. package/dist/clients/attach/extension-dialogs.js +101 -0
  43. package/dist/clients/attach/input-controller.d.ts +54 -0
  44. package/dist/clients/attach/input-controller.js +204 -0
  45. package/dist/clients/attach/slash-commands.d.ts +36 -0
  46. package/dist/clients/attach/slash-commands.js +200 -0
  47. package/dist/clients/attach/view-socket.d.ts +48 -0
  48. package/dist/clients/attach/view-socket.js +126 -0
  49. package/dist/commands/attention.js +3 -3
  50. package/dist/commands/canvas-prune.js +1 -1
  51. package/dist/commands/daemon.js +3 -2
  52. package/dist/commands/human/prompts.js +1 -1
  53. package/dist/commands/human/queue.js +43 -8
  54. package/dist/commands/human/shared.d.ts +2 -0
  55. package/dist/commands/memory/find.d.ts +1 -0
  56. package/dist/commands/memory/find.js +180 -0
  57. package/dist/commands/memory/lint.d.ts +1 -0
  58. package/dist/commands/memory/lint.js +140 -0
  59. package/dist/commands/memory/list.d.ts +1 -0
  60. package/dist/commands/memory/list.js +79 -0
  61. package/dist/commands/memory/read.js +103 -0
  62. package/dist/commands/memory/shared.d.ts +30 -0
  63. package/dist/commands/memory/shared.js +122 -0
  64. package/dist/commands/memory/write.d.ts +1 -0
  65. package/dist/commands/memory/write.js +85 -0
  66. package/dist/commands/memory.d.ts +2 -0
  67. package/dist/commands/memory.js +27 -0
  68. package/dist/commands/node.d.ts +3 -2
  69. package/dist/commands/node.js +607 -61
  70. package/dist/commands/pkg/market-manage.js +1 -1
  71. package/dist/commands/push.js +6 -6
  72. package/dist/commands/revive.js +1 -1
  73. package/dist/commands/skill/author.js +1 -1
  74. package/dist/commands/skill/shared.d.ts +1 -8
  75. package/dist/commands/skill/shared.js +2 -55
  76. package/dist/commands/skill.js +9 -14
  77. package/dist/commands/sys/doctor.js +1 -1
  78. package/dist/commands/sys/update.js +1 -1
  79. package/dist/commands/view-cycle.d.ts +2 -0
  80. package/dist/commands/view-cycle.js +125 -0
  81. package/dist/commands/view-list.d.ts +2 -0
  82. package/dist/commands/view-list.js +66 -0
  83. package/dist/commands/view-new.d.ts +2 -0
  84. package/dist/commands/view-new.js +70 -0
  85. package/dist/commands/view-pick.d.ts +2 -0
  86. package/dist/commands/view-pick.js +119 -0
  87. package/dist/commands/view-run.d.ts +2 -0
  88. package/dist/commands/view-run.js +191 -0
  89. package/dist/commands/view.d.ts +2 -0
  90. package/dist/commands/view.js +29 -0
  91. package/dist/core/__tests__/broker-lifecycle.test.d.ts +1 -0
  92. package/dist/core/__tests__/broker-lifecycle.test.js +677 -0
  93. package/dist/core/__tests__/broker-sdk-wiring.test.d.ts +1 -0
  94. package/dist/core/__tests__/broker-sdk-wiring.test.js +166 -0
  95. package/dist/core/__tests__/cascade-close.test.js +12 -2
  96. package/dist/core/__tests__/child-death-wake.test.d.ts +1 -0
  97. package/dist/core/__tests__/child-death-wake.test.js +245 -0
  98. package/dist/core/__tests__/context-intro.test.js +76 -62
  99. package/dist/core/__tests__/daemon-boot.test.js +14 -5
  100. package/dist/core/__tests__/daemon-liveness.test.js +34 -9
  101. package/dist/core/__tests__/detach-focus.test.d.ts +1 -0
  102. package/dist/core/__tests__/detach-focus.test.js +206 -0
  103. package/dist/core/__tests__/draw-style.test.d.ts +1 -0
  104. package/dist/core/__tests__/draw-style.test.js +258 -0
  105. package/dist/core/__tests__/fixtures/c3-custom-provider-ext.d.ts +2 -0
  106. package/dist/core/__tests__/fixtures/c3-custom-provider-ext.js +18 -0
  107. package/dist/core/__tests__/fixtures/fake-engine.d.ts +138 -0
  108. package/dist/core/__tests__/fixtures/fake-engine.js +614 -0
  109. package/dist/core/__tests__/fixtures/fake-pi-host.js +1 -0
  110. package/dist/core/__tests__/flagship-lifecycle.test.js +7 -1
  111. package/dist/core/__tests__/frame-decoder-perf.test.d.ts +1 -0
  112. package/dist/core/__tests__/frame-decoder-perf.test.js +198 -0
  113. package/dist/core/__tests__/helpers/harness.d.ts +9 -0
  114. package/dist/core/__tests__/helpers/harness.js +111 -1
  115. package/dist/core/__tests__/home-session.test.js +41 -8
  116. package/dist/core/__tests__/human-new-window-regression.test.d.ts +1 -0
  117. package/dist/core/__tests__/human-new-window-regression.test.js +101 -0
  118. package/dist/core/__tests__/kickoff.test.js +37 -3
  119. package/dist/core/__tests__/live-mutation.test.js +50 -33
  120. package/dist/core/__tests__/memory.test.js +23 -115
  121. package/dist/core/__tests__/placement-focus.test.js +5 -0
  122. package/dist/core/__tests__/placement-teardown.test.js +54 -11
  123. package/dist/core/__tests__/relaunch.test.js +4 -3
  124. package/dist/core/__tests__/review-render-pane-regression.test.d.ts +1 -0
  125. package/dist/core/__tests__/review-render-pane-regression.test.js +133 -0
  126. package/dist/core/__tests__/spawn-root.test.js +10 -0
  127. package/dist/core/__tests__/spike-harness.test.js +1 -0
  128. package/dist/core/__tests__/wake-bearings.test.d.ts +1 -0
  129. package/dist/core/__tests__/wake-bearings.test.js +156 -0
  130. package/dist/core/__tests__/wake-origin.test.d.ts +1 -0
  131. package/dist/core/__tests__/wake-origin.test.js +110 -0
  132. package/dist/core/bootstrap.js +1 -1
  133. package/dist/core/canvas/browse/__tests__/render.test.js +1 -0
  134. package/dist/core/canvas/browse/app.js +24 -2
  135. package/dist/core/canvas/browse/model.d.ts +38 -2
  136. package/dist/core/canvas/browse/model.js +134 -10
  137. package/dist/core/canvas/browse/render.d.ts +6 -12
  138. package/dist/core/canvas/browse/render.js +72 -104
  139. package/dist/core/canvas/canvas.js +15 -22
  140. package/dist/core/canvas/db.js +46 -0
  141. package/dist/core/canvas/index.d.ts +1 -0
  142. package/dist/core/canvas/index.js +1 -0
  143. package/dist/core/canvas/pid.d.ts +4 -0
  144. package/dist/core/canvas/pid.js +23 -0
  145. package/dist/core/canvas/render.d.ts +11 -2
  146. package/dist/core/canvas/render.js +69 -0
  147. package/dist/core/canvas/types.d.ts +85 -3
  148. package/dist/core/canvas/wakeups.d.ts +76 -0
  149. package/dist/core/canvas/wakeups.js +185 -0
  150. package/dist/core/config.js +4 -1
  151. package/dist/core/frontmatter.js +37 -124
  152. package/dist/core/memory-resolver.d.ts +49 -0
  153. package/dist/core/memory-resolver.js +141 -0
  154. package/dist/core/personas/loader.d.ts +7 -0
  155. package/dist/core/personas/loader.js +36 -5
  156. package/dist/core/personas/resolve.js +13 -3
  157. package/dist/core/predicate.d.ts +63 -0
  158. package/dist/core/predicate.js +189 -0
  159. package/dist/core/resolver.js +26 -5
  160. package/dist/core/runtime/bearings.d.ts +53 -12
  161. package/dist/core/runtime/bearings.js +132 -59
  162. package/dist/core/runtime/broker-cli.d.ts +1 -0
  163. package/dist/core/runtime/broker-cli.js +46 -0
  164. package/dist/core/runtime/broker-protocol.d.ts +332 -0
  165. package/dist/core/runtime/broker-protocol.js +153 -0
  166. package/dist/core/runtime/broker-sdk.d.ts +48 -0
  167. package/dist/core/runtime/broker-sdk.js +72 -0
  168. package/dist/core/runtime/broker.d.ts +55 -0
  169. package/dist/core/runtime/broker.js +1128 -0
  170. package/dist/core/runtime/close.js +35 -6
  171. package/dist/core/runtime/host.d.ts +53 -0
  172. package/dist/core/runtime/host.js +186 -0
  173. package/dist/core/runtime/kickoff.d.ts +2 -1
  174. package/dist/core/runtime/kickoff.js +91 -5
  175. package/dist/core/runtime/launch.d.ts +45 -2
  176. package/dist/core/runtime/launch.js +65 -2
  177. package/dist/core/runtime/lifecycle.js +23 -6
  178. package/dist/core/runtime/memory.d.ts +2 -42
  179. package/dist/core/runtime/memory.js +11 -162
  180. package/dist/core/runtime/nodes.d.ts +33 -0
  181. package/dist/core/runtime/nodes.js +59 -1
  182. package/dist/core/runtime/persona.js +21 -11
  183. package/dist/core/runtime/pi-vendored.d.ts +18 -0
  184. package/dist/core/runtime/pi-vendored.js +49 -0
  185. package/dist/core/runtime/placement.d.ts +32 -14
  186. package/dist/core/runtime/placement.js +206 -52
  187. package/dist/core/runtime/promote.d.ts +0 -6
  188. package/dist/core/runtime/promote.js +1 -12
  189. package/dist/core/runtime/{demote.d.ts → recycle.d.ts} +5 -5
  190. package/dist/core/runtime/{demote.js → recycle.js} +27 -11
  191. package/dist/core/runtime/reset.js +8 -6
  192. package/dist/core/runtime/revive.d.ts +2 -0
  193. package/dist/core/runtime/revive.js +34 -34
  194. package/dist/core/runtime/spawn.d.ts +19 -0
  195. package/dist/core/runtime/spawn.js +75 -22
  196. package/dist/core/runtime/stop-guard.d.ts +1 -1
  197. package/dist/core/runtime/stop-guard.js +6 -1
  198. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  199. package/dist/core/runtime/tmux-chrome.js +1 -1
  200. package/dist/core/runtime/tmux.d.ts +28 -0
  201. package/dist/core/runtime/tmux.js +80 -6
  202. package/dist/core/scope.d.ts +11 -0
  203. package/dist/core/scope.js +39 -0
  204. package/dist/core/spawn.d.ts +5 -0
  205. package/dist/core/spawn.js +20 -2
  206. package/dist/core/substrate/gate.d.ts +13 -0
  207. package/dist/core/substrate/gate.js +21 -0
  208. package/dist/core/substrate/index.d.ts +7 -0
  209. package/dist/core/substrate/index.js +18 -0
  210. package/dist/core/substrate/on-read.d.ts +14 -0
  211. package/dist/core/substrate/on-read.js +292 -0
  212. package/dist/core/substrate/render.d.ts +25 -0
  213. package/dist/core/substrate/render.js +256 -0
  214. package/dist/core/substrate/schema.d.ts +76 -0
  215. package/dist/core/substrate/schema.js +124 -0
  216. package/dist/core/substrate/session-cache.d.ts +30 -0
  217. package/dist/core/substrate/session-cache.js +77 -0
  218. package/dist/core/substrate/subject.d.ts +41 -0
  219. package/dist/core/substrate/subject.js +54 -0
  220. package/dist/core/tui/contract.d.ts +83 -0
  221. package/dist/core/tui/contract.js +8 -0
  222. package/dist/core/tui/draw.d.ts +96 -0
  223. package/dist/core/tui/draw.js +339 -0
  224. package/dist/core/tui/host.d.ts +29 -0
  225. package/dist/core/tui/host.js +379 -0
  226. package/dist/core/tui/loader.d.ts +16 -0
  227. package/dist/core/tui/loader.js +94 -0
  228. package/dist/core/{canvas/browse → tui}/terminal.js +7 -6
  229. package/dist/core/wake.d.ts +86 -0
  230. package/dist/core/wake.js +308 -0
  231. package/dist/daemon/crtrd.d.ts +29 -4
  232. package/dist/daemon/crtrd.js +662 -46
  233. package/dist/pi-extensions/__tests__/canvas-context-intro.test.d.ts +1 -0
  234. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +171 -0
  235. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +19 -12
  236. package/dist/pi-extensions/canvas-commands.d.ts +3 -0
  237. package/dist/pi-extensions/canvas-commands.js +10 -0
  238. package/dist/pi-extensions/canvas-context-intro.d.ts +17 -0
  239. package/dist/pi-extensions/canvas-context-intro.js +55 -15
  240. package/dist/pi-extensions/canvas-doc-substrate.d.ts +44 -0
  241. package/dist/pi-extensions/canvas-doc-substrate.js +112 -0
  242. package/dist/pi-extensions/canvas-nav.d.ts +3 -0
  243. package/dist/pi-extensions/canvas-nav.js +87 -23
  244. package/dist/pi-extensions/canvas-stophook.js +17 -8
  245. package/dist/pi-extensions/canvas-view.d.ts +21 -0
  246. package/dist/pi-extensions/canvas-view.js +75 -0
  247. package/dist/prompts/skill.js +19 -26
  248. package/dist/prompts/view.d.ts +7 -0
  249. package/dist/prompts/view.js +101 -0
  250. package/dist/types.d.ts +4 -0
  251. package/dist/types.js +1 -0
  252. package/package.json +9 -4
  253. package/dist/commands/skill/find.d.ts +0 -4
  254. package/dist/commands/skill/find.js +0 -257
  255. package/dist/commands/skill/read.js +0 -91
  256. /package/dist/commands/{skill → memory}/read.d.ts +0 -0
  257. /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 / liveness signals:
22
- // CURSOR (selected) = reverse-video bar (ESC[7m), full width — an attribute,
23
- // not a colour, so it reads under NO_COLOR. Plus a ▸ caret.
24
- // ACTIVE (running) = a coloured background bar (status 'active'); the dot
25
- // glyph still carries the signal where colour is stripped.
26
- // SELF = bold name a quiet "you are here" marker.
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 active-row tint is a background COLOUR, but the differing dot
84
- // glyph (●/○/✓/✗) keeps the running signal even where colour is stripped.
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 a running ('active') node distinct from
92
- * the cursor's reverse-video bar; chosen so default-fg text stays readable. */
93
- const BG_ACTIVE = `${ESC}48;5;22m`;
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, BG_ACTIVE for a running node). `open` is re-asserted after every
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 ACTIVE
361
- * (running) node → a coloured background bar; SELF → bold name. The cursor
362
- * outranks the active tint when both land on the same row. */
363
- function renderGraphRow(r, isCursor) {
364
- const wrap = (line, active) => isCursor ? fillBar(line, fillWidth(), REVERSE)
365
- : active ? fillBar(line, fillWidth(), BG_ACTIVE)
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
- const caret = isCursor ? `${BOLD}▸${RESET} ` : ' ';
378
- const fold = r.hasKids && r.collapsed ? ` ${DIM}[+${childCount(r.id)}]${RESET}` : '';
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?.status === 'active');
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 = F3. transition('release') marks it idle-released. If this
505
- // node is FOCUSED its pane FREEZES in place (remain-on-exit, armed at
506
- // focus time) so the daemon can respawn-pane -k it back into the SAME
507
- // focus pane when a worker pushes; if UNFOCUSED its backstage pane
508
- // closes (dormant) and the daemon revives it into the backstage on the
509
- // inbox. Both are the same release tmux's per-window remain-on-exit
510
- // decides freeze vs close. NO manager-takeover (awaiting ≠ done).
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;
@@ -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 skill find search "<topic>"\` / \`crtr skill find list\` — does a primer already exist?
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 skill read <name> --no-body\` (returns \`.path\`, \`.scope\`, \`.plugin\`).
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
- **No \`## Related\` for within-plugin siblings**the CLI auto-appends a
186
- \`## Neighbors\` section on \`crtr skill read <name>\`. Add a manual \`## Related\`
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 skill read <name> --no-body
204
- crtr skill read <name>
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 skill read <name> --no-body\` (returns \`.path\`, \`.scope\`, \`.plugin\`).
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
- **No \`## Related\` for within-plugin siblings**the CLI auto-appends a
305
- \`## Neighbors\` section on \`crtr skill read <name>\`. Add a manual \`## Related\`
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 skill read <name> --no-body
328
- crtr skill read <name>
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 skill read <name> --no-body
419
- crtr skill read <name>
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 skill read <name> --no-body\` (returns \`.path\`, \`.scope\`, \`.plugin\`).
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 skill read <name> --no-body
534
- crtr skill read <name>
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 skill read <name> --no-body\` (returns \`.path\`, \`.scope\`, \`.plugin\`).
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 skill read <name> --no-body
641
- crtr skill read <name>
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,7 @@
1
+ export interface ViewScaffoldVars {
2
+ id: string;
3
+ title: string;
4
+ description: string;
5
+ }
6
+ /** Build the `view.mjs` source for a freshly scaffolded view. */
7
+ export declare function viewScaffold(v: ViewScaffoldVars): string;
@@ -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.18",
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.15",
40
- "commander": "^13.0.0"
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;