@crouton-kit/crouter 0.3.36 → 0.3.38

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 (177) hide show
  1. package/dist/build-root.js +3 -6
  2. package/dist/{builtin-personas/runtime-base.md → builtin-memory/00-runtime-base.md} +8 -1
  3. package/dist/{builtin-personas/spine/has-manager.md → builtin-memory/01-spine/00-has-manager.md} +8 -0
  4. package/dist/builtin-memory/01-spine/01-no-manager.md +10 -0
  5. package/dist/{builtin-personas/lifecycle/terminal.md → builtin-memory/02-lifecycle/00-terminal.md} +8 -0
  6. package/dist/{builtin-personas/lifecycle/resident.md → builtin-memory/02-lifecycle/01-resident.md} +8 -0
  7. package/dist/{builtin-personas/waiting.md → builtin-memory/03-waiting.md} +7 -0
  8. package/dist/{builtin-personas/orchestration-kernel.md → builtin-memory/04-orchestration-kernel.md} +8 -0
  9. package/dist/{builtin-personas/advisor/PERSONA.md → builtin-memory/05-kinds/advisor/00-base.md} +5 -2
  10. package/dist/{builtin-personas/design/PERSONA.md → builtin-memory/05-kinds/design/00-base.md} +5 -2
  11. package/dist/{builtin-personas/design/orchestrator.md → builtin-memory/05-kinds/design/01-orchestrator.md} +5 -4
  12. package/dist/{builtin-personas/developer/PERSONA.md → builtin-memory/05-kinds/developer/00-base.md} +5 -2
  13. package/dist/{builtin-personas/developer/orchestrator.md → builtin-memory/05-kinds/developer/01-orchestrator.md} +5 -4
  14. package/dist/{builtin-personas/explore/PERSONA.md → builtin-memory/05-kinds/explore/00-base.md} +5 -2
  15. package/dist/{builtin-personas/explore/orchestrator.md → builtin-memory/05-kinds/explore/01-orchestrator.md} +5 -3
  16. package/dist/{builtin-personas/general/PERSONA.md → builtin-memory/05-kinds/general/00-base.md} +5 -2
  17. package/dist/{builtin-personas/general/orchestrator.md → builtin-memory/05-kinds/general/01-orchestrator.md} +5 -3
  18. package/dist/{builtin-personas/plan/PERSONA.md → builtin-memory/05-kinds/plan/00-base.md} +5 -2
  19. package/dist/{builtin-personas/plan/orchestrator.md → builtin-memory/05-kinds/plan/01-orchestrator.md} +5 -4
  20. package/dist/{builtin-personas/plan/reviewers/architecture-fit/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/architecture-fit.md} +5 -2
  21. package/dist/{builtin-personas/plan/reviewers/code-smells/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/code-smells.md} +5 -2
  22. package/dist/{builtin-personas/plan/reviewers/pattern-consistency/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md} +5 -2
  23. package/dist/{builtin-personas/plan/reviewers/requirements-coverage/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md} +5 -2
  24. package/dist/{builtin-personas/plan/reviewers/security/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/security.md} +5 -2
  25. package/dist/{builtin-personas/product/PERSONA.md → builtin-memory/05-kinds/product/00-base.md} +5 -2
  26. package/dist/{builtin-personas/product/orchestrator.md → builtin-memory/05-kinds/product/01-orchestrator.md} +5 -4
  27. package/dist/{builtin-personas/product/teardown/PERSONA.md → builtin-memory/05-kinds/product/teardown.md} +5 -3
  28. package/dist/{builtin-personas/review/PERSONA.md → builtin-memory/05-kinds/review/00-base.md} +5 -2
  29. package/dist/{builtin-personas/review/orchestrator.md → builtin-memory/05-kinds/review/01-orchestrator.md} +5 -3
  30. package/dist/{builtin-personas/spec/PERSONA.md → builtin-memory/05-kinds/spec/00-base.md} +5 -2
  31. package/dist/{builtin-personas/spec/orchestrator.md → builtin-memory/05-kinds/spec/01-orchestrator.md} +5 -4
  32. package/dist/{builtin-personas/spec/requirements/PERSONA.md → builtin-memory/05-kinds/spec/requirements.md} +5 -2
  33. package/dist/builtin-memory/internal/INDEX.md +1 -1
  34. package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
  35. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  36. package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +4 -4
  37. package/dist/builtin-views/canvas/core.mjs +3 -2
  38. package/dist/builtin-views/prompt-review/core.mjs +6 -134
  39. package/dist/builtin-views/settings/core.mjs +26 -94
  40. package/dist/builtin-views/settings/text.mjs +0 -5
  41. package/dist/builtin-views/settings/tui.mjs +1 -7
  42. package/dist/builtin-views/settings/web.jsx +3 -49
  43. package/dist/clients/attach/__tests__/crtr-output-render.test.js +21 -205
  44. package/dist/clients/attach/attach-cmd.js +429 -432
  45. package/dist/clients/web/web-cmd.js +7 -7
  46. package/dist/commands/__tests__/human.test.js +1 -15
  47. package/dist/commands/attention.js +9 -6
  48. package/dist/commands/canvas-history/search.js +2 -2
  49. package/dist/commands/canvas-history/show.js +3 -3
  50. package/dist/commands/canvas-history.js +1 -1
  51. package/dist/commands/canvas-issue.js +1 -0
  52. package/dist/commands/canvas-snapshot.js +1 -0
  53. package/dist/commands/canvas.js +10 -11
  54. package/dist/commands/chord.js +1 -0
  55. package/dist/commands/human/prompts.js +0 -1
  56. package/dist/commands/human/queue.js +1 -0
  57. package/dist/commands/memory/read.js +3 -3
  58. package/dist/commands/memory/shared.d.ts +13 -8
  59. package/dist/commands/memory/shared.js +22 -8
  60. package/dist/commands/memory/write.js +5 -3
  61. package/dist/commands/node-snapshot.js +1 -0
  62. package/dist/commands/node.js +52 -22
  63. package/dist/commands/profile/add-project.d.ts +1 -0
  64. package/dist/commands/profile/add-project.js +42 -0
  65. package/dist/commands/profile/delete.d.ts +1 -0
  66. package/dist/commands/profile/delete.js +39 -0
  67. package/dist/commands/profile/list.d.ts +1 -0
  68. package/dist/commands/profile/list.js +35 -0
  69. package/dist/commands/profile/new.d.ts +1 -0
  70. package/dist/commands/profile/new.js +50 -0
  71. package/dist/commands/profile/remove-project.d.ts +1 -0
  72. package/dist/commands/profile/remove-project.js +42 -0
  73. package/dist/commands/profile/rename.d.ts +1 -0
  74. package/dist/commands/profile/rename.js +42 -0
  75. package/dist/commands/profile/show.d.ts +1 -0
  76. package/dist/commands/profile/show.js +50 -0
  77. package/dist/commands/profile.d.ts +2 -0
  78. package/dist/commands/profile.js +33 -0
  79. package/dist/commands/push.d.ts +0 -1
  80. package/dist/commands/push.js +2 -228
  81. package/dist/commands/revive.js +2 -2
  82. package/dist/commands/{canvas-tmux-spread.js → surface-tmux-spread.js} +9 -6
  83. package/dist/commands/surface.js +3 -2
  84. package/dist/commands/sys/config.js +6 -21
  85. package/dist/commands/sys/daemon.d.ts +2 -0
  86. package/dist/commands/{daemon.js → sys/daemon.js} +12 -12
  87. package/dist/commands/sys/doctor.js +1 -0
  88. package/dist/commands/sys/prompt-review.js +90 -17
  89. package/dist/commands/sys.js +4 -3
  90. package/dist/core/__tests__/daemon-boot.test.js +1 -1
  91. package/dist/core/__tests__/daemon-wedge.test.d.ts +1 -0
  92. package/dist/core/__tests__/daemon-wedge.test.js +87 -0
  93. package/dist/core/__tests__/hearth-bootstrap.test.js +2 -2
  94. package/dist/core/__tests__/history-inbox.test.d.ts +1 -0
  95. package/dist/core/__tests__/history-inbox.test.js +105 -0
  96. package/dist/core/__tests__/kickoff.test.js +3 -3
  97. package/dist/core/__tests__/revive.test.js +39 -1
  98. package/dist/core/canvas/canvas.js +10 -9
  99. package/dist/core/canvas/db.js +11 -0
  100. package/dist/core/canvas/history.d.ts +1 -1
  101. package/dist/core/canvas/history.js +91 -3
  102. package/dist/core/canvas/paths.d.ts +6 -0
  103. package/dist/core/canvas/paths.js +9 -0
  104. package/dist/core/canvas/status-glyph.js +1 -0
  105. package/dist/core/canvas/types.d.ts +10 -0
  106. package/dist/core/config.d.ts +44 -1
  107. package/dist/core/config.js +155 -12
  108. package/dist/core/fault-classifier.d.ts +2 -2
  109. package/dist/core/feed/inbox.d.ts +7 -12
  110. package/dist/core/feed/inbox.js +45 -29
  111. package/dist/core/hearth/providers/blaxel-bootstrap.js +1 -1
  112. package/dist/core/memory-resolver.d.ts +26 -15
  113. package/dist/core/memory-resolver.js +158 -40
  114. package/dist/core/preview-registry.js +14 -112
  115. package/dist/core/profiles/manifest.d.ts +33 -0
  116. package/dist/core/profiles/manifest.js +332 -0
  117. package/dist/core/profiles/select.d.ts +11 -0
  118. package/dist/core/profiles/select.js +115 -0
  119. package/dist/core/render.js +1 -1
  120. package/dist/core/runtime/bearings.d.ts +9 -0
  121. package/dist/core/runtime/bearings.js +31 -0
  122. package/dist/core/runtime/busy.d.ts +15 -0
  123. package/dist/core/runtime/busy.js +32 -1
  124. package/dist/core/runtime/close.d.ts +10 -0
  125. package/dist/core/runtime/close.js +18 -13
  126. package/dist/core/runtime/fault-recovery.js +4 -0
  127. package/dist/core/runtime/front-door.js +9 -2
  128. package/dist/core/runtime/kickoff.js +5 -7
  129. package/dist/core/runtime/launch.d.ts +25 -7
  130. package/dist/core/runtime/launch.js +42 -55
  131. package/dist/core/runtime/nodes.d.ts +7 -0
  132. package/dist/core/runtime/nodes.js +6 -0
  133. package/dist/core/runtime/persona.js +18 -32
  134. package/dist/core/runtime/placement.js +1 -1
  135. package/dist/core/runtime/revive.js +9 -1
  136. package/dist/core/runtime/spawn.d.ts +13 -0
  137. package/dist/core/runtime/spawn.js +25 -0
  138. package/dist/core/runtime/tmux.d.ts +2 -2
  139. package/dist/core/runtime/tmux.js +2 -2
  140. package/dist/core/scope.d.ts +14 -7
  141. package/dist/core/scope.js +76 -20
  142. package/dist/core/substrate/index.d.ts +3 -3
  143. package/dist/core/substrate/index.js +5 -3
  144. package/dist/core/substrate/on-read.js +3 -2
  145. package/dist/core/substrate/render.d.ts +16 -11
  146. package/dist/core/substrate/render.js +249 -62
  147. package/dist/core/substrate/schema.d.ts +11 -3
  148. package/dist/core/substrate/schema.js +25 -0
  149. package/dist/core/substrate/subject.d.ts +15 -2
  150. package/dist/core/substrate/subject.js +24 -2
  151. package/dist/daemon/crtrd-cli.js +1 -1
  152. package/dist/daemon/crtrd.d.ts +24 -0
  153. package/dist/daemon/crtrd.js +213 -5
  154. package/dist/daemon/manage.js +2 -2
  155. package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
  156. package/dist/pi-extensions/canvas-nav.js +2 -2
  157. package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
  158. package/dist/pi-extensions/canvas-stophook.js +59 -2
  159. package/dist/types.d.ts +57 -1
  160. package/dist/types.js +83 -1
  161. package/dist/web-client/assets/{index-IAJVtuVe.js → index-CbO8L0mN.js} +4 -4
  162. package/dist/web-client/assets/index-DwO46Cs5.css +2 -0
  163. package/dist/web-client/index.html +2 -2
  164. package/package.json +2 -2
  165. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +0 -56
  166. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +0 -57
  167. package/dist/builtin-memory/crouter-development/personas.md +0 -112
  168. package/dist/builtin-personas/spine/no-manager.md +0 -2
  169. package/dist/commands/daemon.d.ts +0 -2
  170. package/dist/core/personas/index.d.ts +0 -13
  171. package/dist/core/personas/index.js +0 -11
  172. package/dist/core/personas/loader.d.ts +0 -159
  173. package/dist/core/personas/loader.js +0 -327
  174. package/dist/core/personas/resolve.d.ts +0 -59
  175. package/dist/core/personas/resolve.js +0 -376
  176. package/dist/web-client/assets/index-DUThOUzU.css +0 -2
  177. /package/dist/commands/{canvas-tmux-spread.d.ts → surface-tmux-spread.d.ts} +0 -0
@@ -19,7 +19,7 @@ function stripAnsi(text) {
19
19
  test('detects crtr in bash command position, not heredoc body prose', () => {
20
20
  assert.equal(isCrtrBashCommand('crtr node new -h'), true);
21
21
  assert.equal(isCrtrBashCommand('crtr node inspect snapshot --node abc'), true);
22
- assert.equal(isCrtrBashCommand('crtr canvas daemon status'), true);
22
+ assert.equal(isCrtrBashCommand('crtr sys daemon status'), true);
23
23
  assert.equal(isCrtrBashCommand('npm test && /usr/local/bin/crouter surface view run inbox'), true);
24
24
  assert.equal(isCrtrBashCommand("cat <<'EOF'\nask about crtr node new\nEOF\necho done"), false);
25
25
  assert.equal(isCrtrBashCommand('echo crtr node new'), false);
@@ -161,14 +161,14 @@ test('a branch help preview with more subcommands than the line cap truncates wi
161
161
  // Contract: outer bash redirects are shell plumbing, not crtr argv, so the
162
162
  // displayed crtr path and help detection include only the command segment.
163
163
  test('a shell redirect on the outer bash call never leaks into the displayed crtr path or help detection', () => {
164
- const def = createCrtrBashToolDefinition({ command: 'crtr feed -h 2>&1' });
165
- const rendered = def.renderCall({ command: 'crtr feed -h 2>&1' }, theme).render(80).join('\n');
164
+ const def = createCrtrBashToolDefinition({ command: 'crtr push -h 2>&1' });
165
+ const rendered = def.renderCall({ command: 'crtr push -h 2>&1' }, theme).render(80).join('\n');
166
166
  assert.match(rendered, new RegExp(HELP_ICON));
167
167
  assert.match(rendered, /crtr help/);
168
- assert.match(rendered, /<b>feed<\/b>/);
168
+ assert.match(rendered, /<b>push<\/b>/);
169
169
  assert.doesNotMatch(rendered, /2>/);
170
170
  assert.doesNotMatch(rendered, />&1/);
171
- assert.equal(isCrtrHelpInvocation('crtr feed -h 2>&1'), true);
171
+ assert.equal(isCrtrHelpInvocation('crtr push -h 2>&1'), true);
172
172
  // Other redirect shapes on the outer call, and mid-argv redirects, must
173
173
  // never survive into the path either.
174
174
  const other = createCrtrBashToolDefinition({ command: 'crtr node new --name foo > /tmp/log 2>&1' });
@@ -177,9 +177,9 @@ test('a shell redirect on the outer bash call never leaks into the displayed crt
177
177
  assert.doesNotMatch(otherRendered, /tmp\/log/);
178
178
  // Redirect operators glued to their target with NO space (`2>/tmp/out`,
179
179
  // `>/tmp/log`) are still shell plumbing and never displayed as path text.
180
- const noSpace = createCrtrBashToolDefinition({ command: 'crtr feed -h 2>/tmp/out' });
181
- const noSpaceRendered = noSpace.renderCall({ command: 'crtr feed -h 2>/tmp/out' }, theme).render(80).join('\n');
182
- assert.match(noSpaceRendered, /<b>feed<\/b>/);
180
+ const noSpace = createCrtrBashToolDefinition({ command: 'crtr push -h 2>/tmp/out' });
181
+ const noSpaceRendered = noSpace.renderCall({ command: 'crtr push -h 2>/tmp/out' }, theme).render(80).join('\n');
182
+ assert.match(noSpaceRendered, /<b>push<\/b>/);
183
183
  assert.doesNotMatch(noSpaceRendered, /2>/);
184
184
  assert.doesNotMatch(noSpaceRendered, /tmp\/out/);
185
185
  const noSpaceMid = createCrtrBashToolDefinition({ command: 'crtr node new --name foo >/tmp/log' });
@@ -206,12 +206,12 @@ test('a collapsed help card never shows the help label twice (header + body)', (
206
206
  // (redirects and all) plus the exact, unsummarized output, for both help and
207
207
  // normal commands.
208
208
  test('expanded view shows the original raw command (redirects included) plus the raw output', () => {
209
- const def = createCrtrBashToolDefinition({ command: 'crtr feed -h 2>&1' });
209
+ const def = createCrtrBashToolDefinition({ command: 'crtr push -h 2>&1' });
210
210
  const expanded = def
211
211
  .renderResult({ content: [{ type: 'text', text: LEAF_SCHEMA }] }, { expanded: true }, theme, {})
212
212
  .render(80)
213
213
  .join('\n');
214
- assert.match(expanded, /\$ crtr feed -h 2>&1/);
214
+ assert.match(expanded, /\$ crtr push -h 2>&1/);
215
215
  assert.match(expanded, /render the canvas as an ASCII subscription/);
216
216
  assert.match(expanded, /Read-only: queries canvas\.db/);
217
217
  // Normal (non-help) command: expanded still carries the raw invocation.
@@ -236,15 +236,15 @@ test('a running or failed crtr -h invocation never gets the muted help status',
236
236
  // the command and the output is right there. Success (help or normal) carries
237
237
  // no body status; only running/failed do.
238
238
  test('a successful crtr call shows no "crtr done" body status line', () => {
239
- const def = createCrtrBashToolDefinition({ command: 'crtr feed' });
239
+ const def = createCrtrBashToolDefinition({ command: 'crtr push update' });
240
240
  const collapsed = def
241
- .renderResult({ content: [{ type: 'text', text: 'some feed output' }] }, { expanded: false }, theme, {})
241
+ .renderResult({ content: [{ type: 'text', text: 'some push output' }] }, { expanded: false }, theme, {})
242
242
  .render(80)
243
243
  .join('\n');
244
244
  assert.doesNotMatch(collapsed, /crtr done/);
245
- assert.match(collapsed, /some feed output/);
245
+ assert.match(collapsed, /some push output/);
246
246
  const expanded = def
247
- .renderResult({ content: [{ type: 'text', text: 'some feed output' }] }, { expanded: true }, theme, {})
247
+ .renderResult({ content: [{ type: 'text', text: 'some push output' }] }, { expanded: true }, theme, {})
248
248
  .render(80)
249
249
  .join('\n');
250
250
  assert.doesNotMatch(expanded, /crtr done/);
@@ -428,7 +428,7 @@ test('renderCall uses a mapped Nerd Font glyph and one line for every mapped roo
428
428
  const cases = [
429
429
  { command: 'crtr memory lint', iconTokens: ['memory', 'lint'], path: 'memory lint' },
430
430
  { command: 'crtr canvas dashboard', iconTokens: ['canvas', 'dashboard'], path: 'canvas dashboard' },
431
- { command: 'crtr feed read', iconTokens: ['feed', 'read'], path: 'feed read' },
431
+ { command: 'crtr node yield', iconTokens: ['node', 'yield'], path: 'node yield' },
432
432
  { command: 'crtr human ask', iconTokens: ['human', 'ask'], path: 'human ask' },
433
433
  { command: 'crtr node config set foo bar', iconTokens: ['node', 'config'], path: 'node config set foo bar' },
434
434
  { command: 'crtr pkg plugin list', iconTokens: ['pkg', 'plugin', 'list'], path: 'pkg plugin list' },
@@ -583,7 +583,7 @@ test('icon lookup uses per-leaf glyphs before family glyphs, with help unchanged
583
583
  assert.equal(HELP_ICON, String.fromCodePoint(0xf059));
584
584
  });
585
585
  // ---------------------------------------------------------------------------
586
- // canvas/node/feed runtime cockpit summaries (first non-memory batch, Silas's
586
+ // canvas/node runtime cockpit summaries (first non-memory batch, Silas's
587
587
  // 2026-07-01 reframe: collapsed cards are computed status digests, not
588
588
  // decorated stdout). Fixtures below are literal renderResult() output shapes
589
589
  // (core/render.ts: a `- field: N` scalar bullet, an `N <label>:` count
@@ -715,7 +715,7 @@ test('node inspect show is command-owned suppressOutput, never on failure', () =
715
715
  assert.match(failed.render(80).join('\n'), /huge dump on failure too/);
716
716
  });
717
717
  // ---------------------------------------------------------------------------
718
- // Batch B: canvas/node/feed/push runtime cockpit summaries (Silas's
718
+ // Batch B: canvas/node/push runtime cockpit summaries (Silas's
719
719
  // 2026-07-01 reframe continued). Fixtures below are literal render() output
720
720
  // shapes copied from the real command source (see preview-registry.ts's
721
721
  // per-summarizer doc comments for the exact file:line), not the live command
@@ -961,8 +961,8 @@ test('a crtr canvas history show card collapses to a node line + type-count dige
961
961
  .join('\n');
962
962
  assert.match(emptyExpanded, /0 artifacts\./);
963
963
  });
964
- test('crtr canvas daemon start/status/stop cards collapse to a one-line pid status', () => {
965
- const start = createCrtrBashToolDefinition({ command: 'crtr canvas daemon start' });
964
+ test('crtr sys daemon start/status/stop cards collapse to a one-line pid status', () => {
965
+ const start = createCrtrBashToolDefinition({ command: 'crtr sys daemon start' });
966
966
  assert.match(start.renderResult({ content: [{ type: 'text', text: '- started: true\n- pid: 4242' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /<success>started · pid 4242<\/success>/);
967
967
  assert.match(start.renderResult({ content: [{ type: 'text', text: '- started: false\n- existing_pid: 99' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /<muted>already running · pid 99<\/muted>/);
968
968
  assert.match(start.renderResult({ content: [{ type: 'text', text: '- started: false\n- existing_pid: 99' }] }, { expanded: true }, theme, {}).render(120).join('\n'), /existing_pid: 99/);
@@ -972,7 +972,7 @@ test('crtr canvas daemon start/status/stop cards collapse to a one-line pid stat
972
972
  .join('\n');
973
973
  assert.match(startExpanded, /started: true/);
974
974
  assert.match(startExpanded, /pid: 4242/);
975
- const status = createCrtrBashToolDefinition({ command: 'crtr canvas daemon status' });
975
+ const status = createCrtrBashToolDefinition({ command: 'crtr sys daemon status' });
976
976
  assert.match(status.renderResult({ content: [{ type: 'text', text: '- running: true\n- pid: 4242' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /<success>running · pid 4242<\/success>/);
977
977
  assert.match(status.renderResult({ content: [{ type: 'text', text: '- running: false' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /<error>not running<\/error>/);
978
978
  assert.match(status.renderResult({ content: [{ type: 'text', text: '- running: false' }] }, { expanded: true }, theme, {}).render(120).join('\n'), /running: false/);
@@ -982,7 +982,7 @@ test('crtr canvas daemon start/status/stop cards collapse to a one-line pid stat
982
982
  .join('\n');
983
983
  assert.match(statusExpanded, /running: true/);
984
984
  assert.match(statusExpanded, /pid: 4242/);
985
- const stop = createCrtrBashToolDefinition({ command: 'crtr canvas daemon stop' });
985
+ const stop = createCrtrBashToolDefinition({ command: 'crtr sys daemon stop' });
986
986
  assert.match(stop.renderResult({ content: [{ type: 'text', text: '- stopped: true\n- pid: 4242' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /stopped · pid 4242/);
987
987
  assert.match(stop.renderResult({ content: [{ type: 'text', text: '- stopped: false' }] }, { expanded: false }, theme, {}).render(120).join('\n'), /<muted>was not running<\/muted>/);
988
988
  assert.match(stop.renderResult({ content: [{ type: 'text', text: '- stopped: false' }] }, { expanded: true }, theme, {}).render(120).join('\n'), /stopped: false/);
@@ -1274,190 +1274,6 @@ test('a crtr node triggers list card collapses to a pending-count + top rows, no
1274
1274
  .join('\n');
1275
1275
  assert.match(emptyExpanded, /No pending triggers in scope self\./);
1276
1276
  });
1277
- test('a crtr feed read card collapses to a drained-pointer digest, not the raw coalesced sections', () => {
1278
- const def = createCrtrBashToolDefinition({ command: 'crtr feed read' });
1279
- const drained = def
1280
- .renderResult({
1281
- content: [
1282
- {
1283
- type: 'text',
1284
- text: [
1285
- "3 unread pointers drained from mq123's inbox.",
1286
- '',
1287
- 'From worker-a — 2 updates:',
1288
- ' [push] did a thing (ref: worker-a:reports/x.md)',
1289
- ' [push] did another (ref: worker-a:reports/y.md)',
1290
- '',
1291
- 'From worker-b — 1 update:',
1292
- ' [push] finished (ref: worker-b:reports/z.md)',
1293
- ].join('\n'),
1294
- },
1295
- ],
1296
- }, { expanded: false }, theme, {})
1297
- .render(140)
1298
- .join('\n');
1299
- assert.match(drained, /3 pointers drained from 2 nodes/);
1300
- assert.match(drained, /<muted>worker-a, worker-b<\/muted>/);
1301
- assert.doesNotMatch(drained, /ref: worker-a/);
1302
- const drainedExpanded = def
1303
- .renderResult({
1304
- content: [
1305
- {
1306
- type: 'text',
1307
- text: [
1308
- "3 unread pointers drained from mq123's inbox.",
1309
- '',
1310
- 'From worker-a — 2 updates:',
1311
- ' [push] did a thing (ref: worker-a:reports/x.md)',
1312
- ' [push] did another (ref: worker-a:reports/y.md)',
1313
- '',
1314
- 'From worker-b — 1 update:',
1315
- ' [push] finished (ref: worker-b:reports/z.md)',
1316
- ].join('\n'),
1317
- },
1318
- ],
1319
- }, { expanded: true }, theme, {})
1320
- .render(140)
1321
- .join('\n');
1322
- assert.match(drainedExpanded, /ref: worker-a:reports\/x\.md/);
1323
- const empty = def
1324
- .renderResult({ content: [{ type: 'text', text: 'No unread pointers for mq123 (unread=0).\n\nYour inbox is empty — nothing has arrived yet.' }] }, { expanded: false }, theme, {})
1325
- .render(120)
1326
- .join('\n');
1327
- assert.match(empty, /<muted>nothing unread<\/muted>/);
1328
- const emptyExpanded = def
1329
- .renderResult({ content: [{ type: 'text', text: 'No unread pointers for mq123 (unread=0).\n\nYour inbox is empty — nothing has arrived yet.' }] }, { expanded: true }, theme, {})
1330
- .render(120)
1331
- .join('\n');
1332
- assert.match(emptyExpanded, /Your inbox is empty — nothing has arrived yet\./);
1333
- });
1334
- test('a crtr feed message card previews an identity line + body teaser, not the raw label', () => {
1335
- const def = createCrtrBashToolDefinition({ command: 'crtr feed message m1' });
1336
- const found = def
1337
- .renderResult({ content: [{ type: 'text', text: ['Full message m1 (from mq123):', '', 'Line one', 'Line two', 'Line three', 'Line four'].join('\n') }] }, { expanded: false }, theme, {})
1338
- .render(120)
1339
- .join('\n');
1340
- assert.match(found, /m1 · from mq123/);
1341
- assert.match(found, /Line one/);
1342
- assert.match(found, /…/);
1343
- assert.doesNotMatch(found, /Line four/);
1344
- const foundExpanded = def
1345
- .renderResult({ content: [{ type: 'text', text: ['Full message m1 (from mq123):', '', 'Line one', 'Line two', 'Line three', 'Line four'].join('\n') }] }, { expanded: true }, theme, {})
1346
- .render(120)
1347
- .join('\n');
1348
- assert.match(foundExpanded, /Line four/);
1349
- const notFound = def
1350
- .renderResult({ content: [{ type: 'text', text: "No inbox entry with id m1 in mq123's inbox. Re-read the digest with `crtr feed read --all`." }] }, { expanded: false }, theme, {})
1351
- .render(120)
1352
- .join('\n');
1353
- assert.match(notFound, /No inbox entry with id m1/);
1354
- const notFoundExpanded = def
1355
- .renderResult({ content: [{ type: 'text', text: "No inbox entry with id m1 in mq123's inbox. Re-read the digest with `crtr feed read --all`." }] }, { expanded: true }, theme, {})
1356
- .render(120)
1357
- .join('\n');
1358
- assert.match(notFoundExpanded, /Re-read the digest with `crtr feed read --all`\./);
1359
- });
1360
- test('a crtr feed peek card collapses to a verdict + working/done/dead counts, not the raw rows', () => {
1361
- const def = createCrtrBashToolDefinition({ command: 'crtr feed peek' });
1362
- const zeroClear = def
1363
- .renderResult({ content: [{ type: 'text', text: 'No nodes below you (0 subscriptions, 0 unread). Nothing will wake you.' }] }, { expanded: false }, theme, {})
1364
- .render(120)
1365
- .join('\n');
1366
- assert.match(zeroClear, /<success>PASS · nothing below<\/success>/);
1367
- const zeroClearExpanded = def
1368
- .renderResult({ content: [{ type: 'text', text: 'No nodes below you (0 subscriptions, 0 unread). Nothing will wake you.' }] }, { expanded: true }, theme, {})
1369
- .render(120)
1370
- .join('\n');
1371
- assert.match(zeroClearExpanded, /Nothing will wake you\./);
1372
- const zeroUnread = def
1373
- .renderResult({ content: [{ type: 'text', text: 'No nodes below you (0 subscriptions, 4 unread). 4 unread reports sit in your inbox.' }] }, { expanded: false }, theme, {})
1374
- .render(120)
1375
- .join('\n');
1376
- assert.match(zeroUnread, /<warning>0 below · 4 unread<\/warning>/);
1377
- const zeroUnreadExpanded = def
1378
- .renderResult({ content: [{ type: 'text', text: 'No nodes below you (0 subscriptions, 4 unread). 4 unread reports sit in your inbox.' }] }, { expanded: true }, theme, {})
1379
- .render(120)
1380
- .join('\n');
1381
- assert.match(zeroUnreadExpanded, /4 unread reports sit in your inbox\./);
1382
- const withDead = def
1383
- .renderResult({
1384
- content: [
1385
- {
1386
- type: 'text',
1387
- text: [
1388
- '⚠ 1 below you is dead and will NOT wake you.',
1389
- '',
1390
- '3 nodes below you — 1 working, 1 done, 1 dead, 2 unread:',
1391
- '- ● worker-a (mq1) · developer · active · spawned 5m ago · cyc 2 · pushed 1m ago [push]',
1392
- '- ✓ worker-b (mq2) · developer · done · spawned 10m ago · cyc 3 · pushed 2m ago [push]',
1393
- '- ✗ worker-c (mq3) · developer · dead · spawned 20m ago · cyc 1 · no push yet',
1394
- ].join('\n'),
1395
- },
1396
- ],
1397
- }, { expanded: false }, theme, {})
1398
- .render(140)
1399
- .join('\n');
1400
- assert.match(withDead, /1 working · 1 done · 1 dead/);
1401
- assert.match(withDead, /<warning>1 dead — will not wake you<\/warning>/);
1402
- assert.doesNotMatch(withDead, /pushed 1m ago/);
1403
- const withDeadExpanded = def
1404
- .renderResult({
1405
- content: [
1406
- {
1407
- type: 'text',
1408
- text: [
1409
- '⚠ 1 below you is dead and will NOT wake you.',
1410
- '',
1411
- '3 nodes below you — 1 working, 1 done, 1 dead, 2 unread:',
1412
- '- ● worker-a (mq1) · developer · active · spawned 5m ago · cyc 2 · pushed 1m ago [push]',
1413
- '- ✓ worker-b (mq2) · developer · done · spawned 10m ago · cyc 3 · pushed 2m ago [push]',
1414
- '- ✗ worker-c (mq3) · developer · dead · spawned 20m ago · cyc 1 · no push yet',
1415
- ].join('\n'),
1416
- },
1417
- ],
1418
- }, { expanded: true }, theme, {})
1419
- .render(140)
1420
- .join('\n');
1421
- assert.match(withDeadExpanded, /pushed 1m ago/);
1422
- const noDead = def
1423
- .renderResult({
1424
- content: [
1425
- {
1426
- type: 'text',
1427
- text: [
1428
- 'Safe to yield — 1 worker running async will wake you.',
1429
- '',
1430
- '2 nodes below you — 1 working, 1 done, 0 dead, 3 unread:',
1431
- '- ● worker-a (mq1) · developer · active · spawned 5m ago · cyc 2 · pushed 1m ago [push]',
1432
- '- ✓ worker-b (mq2) · developer · done · spawned 10m ago · cyc 3 · pushed 2m ago [push]',
1433
- ].join('\n'),
1434
- },
1435
- ],
1436
- }, { expanded: false }, theme, {})
1437
- .render(140)
1438
- .join('\n');
1439
- assert.match(noDead, /1 working · 1 done/);
1440
- assert.doesNotMatch(noDead, /0 dead/);
1441
- assert.match(noDead, /<warning>3 unread<\/warning>/);
1442
- const noDeadExpanded = def
1443
- .renderResult({
1444
- content: [
1445
- {
1446
- type: 'text',
1447
- text: [
1448
- 'Safe to yield — 1 worker running async will wake you.',
1449
- '',
1450
- '2 nodes below you — 1 working, 1 done, 0 dead, 3 unread:',
1451
- '- ● worker-a (mq1) · developer · active · spawned 5m ago · cyc 2 · pushed 1m ago [push]',
1452
- '- ✓ worker-b (mq2) · developer · done · spawned 10m ago · cyc 3 · pushed 2m ago [push]',
1453
- ].join('\n'),
1454
- },
1455
- ],
1456
- }, { expanded: true }, theme, {})
1457
- .render(140)
1458
- .join('\n');
1459
- assert.match(noDeadExpanded, /Safe to yield — 1 worker running async will wake you\./);
1460
- });
1461
1277
  test('crtr push urgent/final cards collapse to a one-line outcome + report basename', () => {
1462
1278
  const urgentDef = createCrtrBashToolDefinition({ command: 'crtr push urgent' });
1463
1279
  const urgent = urgentDef