@north-light/crouter 0.3.231 → 0.3.233

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 (187) hide show
  1. package/dist/api/client.d.ts +3 -1
  2. package/dist/api/client.js +4 -0
  3. package/dist/api/dto/canvas.d.ts +10 -0
  4. package/dist/api/dto/common.d.ts +1 -1
  5. package/dist/api/dto/health.d.ts +2 -1
  6. package/dist/api/dto/lifecycle.d.ts +3 -4
  7. package/dist/api/dto/messages.d.ts +5 -4
  8. package/dist/api/dto/nodes.d.ts +2 -0
  9. package/dist/api/dto/profiles.d.ts +5 -0
  10. package/dist/api/routes.d.ts +1 -0
  11. package/dist/api/routes.js +1 -0
  12. package/dist/builtin-memory/00-runtime-base/00-authoring.md +8 -0
  13. package/dist/builtin-memory/00-runtime-base/01-escalation.md +1 -1
  14. package/dist/builtin-memory/01-spine/00-has-manager.md +1 -1
  15. package/dist/builtin-memory/02-turn-lifecycle/00-ending-a-turn.md +5 -0
  16. package/dist/builtin-memory/02-turn-lifecycle/02-resident.md +5 -3
  17. package/dist/builtin-memory/04-orchestration-kernel.md +2 -2
  18. package/dist/builtin-memory/insights/capture.md +3 -2
  19. package/dist/builtin-memory/internal/memory-loading.md +4 -3
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +6 -1
  21. package/dist/clients/attach/render/diagram.js +13 -5
  22. package/dist/clients/attach/render/page-block.d.ts +0 -1
  23. package/dist/clients/attach/render/page-block.js +4 -57
  24. package/dist/clients/attach/viewer.js +570 -563
  25. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +9 -0
  26. package/dist/clients/inbox/__tests__/integration/mount-panel.test.js +62 -1
  27. package/dist/clients/inbox/controller.d.ts +10 -0
  28. package/dist/clients/inbox/controller.js +56 -12
  29. package/dist/clients/inbox/tui/input.js +38 -10
  30. package/dist/clients/inbox/tui/page-body.d.ts +10 -0
  31. package/dist/clients/inbox/tui/page-body.js +66 -0
  32. package/dist/clients/inbox/tui/panel.js +6 -4
  33. package/dist/clients/inbox/tui/render.js +89 -17
  34. package/dist/clients/inbox/tui/types.d.ts +4 -4
  35. package/dist/commands/__tests__/human.test.js +18 -3
  36. package/dist/commands/__tests__/node-message.test.js +3 -3
  37. package/dist/commands/api-client.js +1 -7
  38. package/dist/commands/canvas-config.js +6 -14
  39. package/dist/commands/canvas-use.js +4 -6
  40. package/dist/commands/cron.js +16 -22
  41. package/dist/commands/human/prompts.d.ts +1 -1
  42. package/dist/commands/human/prompts.js +118 -112
  43. package/dist/commands/human/request.js +13 -14
  44. package/dist/commands/human/review.js +3 -4
  45. package/dist/commands/human/shared.d.ts +6 -0
  46. package/dist/commands/human/shared.js +43 -5
  47. package/dist/commands/human.js +1 -1
  48. package/dist/commands/memory/delete.js +4 -6
  49. package/dist/commands/memory/edit.js +0 -4
  50. package/dist/commands/memory/move.js +3 -5
  51. package/dist/commands/memory/shared.d.ts +1 -1
  52. package/dist/commands/memory/shared.js +11 -7
  53. package/dist/commands/memory/write.js +60 -29
  54. package/dist/commands/memory.js +1 -1
  55. package/dist/commands/node/bash.js +6 -9
  56. package/dist/commands/node/create.js +89 -22
  57. package/dist/commands/node/inspect.js +3 -3
  58. package/dist/commands/node/lifecycle.js +30 -27
  59. package/dist/commands/node/message.js +24 -45
  60. package/dist/commands/node/subscription.js +6 -15
  61. package/dist/commands/node/wait.js +2 -3
  62. package/dist/commands/node-lifecycle-revive.js +1 -12
  63. package/dist/commands/pkg/browse/actions.js +2 -3
  64. package/dist/commands/pkg/market-manage.js +2 -5
  65. package/dist/commands/pkg/plugin-manage.js +7 -8
  66. package/dist/commands/profile/default.js +5 -5
  67. package/dist/commands/profile/delete.js +1 -1
  68. package/dist/commands/profile/env.js +9 -15
  69. package/dist/commands/profile/kind.js +3 -7
  70. package/dist/commands/profile/meta.js +3 -5
  71. package/dist/commands/profile/new.js +0 -6
  72. package/dist/commands/profile/pause.js +4 -8
  73. package/dist/commands/profile/project.js +5 -9
  74. package/dist/commands/profile/rename.js +3 -7
  75. package/dist/commands/profile/show.js +3 -3
  76. package/dist/commands/profile.js +4 -3
  77. package/dist/commands/surface-tmux-spread.js +1 -3
  78. package/dist/commands/sys/config.js +3 -4
  79. package/dist/commands/sys/support/prepare.js +8 -4
  80. package/dist/commands/sys/support/submit.js +2 -3
  81. package/dist/commands/sys/sync-deps.js +1 -9
  82. package/dist/commands/sys/sync-project-guidance.js +1 -7
  83. package/dist/commands/sys/sync-skills.js +1 -11
  84. package/dist/core/__tests__/cron-node-sink-parked-root.test.d.ts +1 -0
  85. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +147 -0
  86. package/dist/core/__tests__/history-inbox.test.js +11 -1
  87. package/dist/core/__tests__/human-deliver.test.js +2 -1
  88. package/dist/core/__tests__/integration/command-plugins.test.js +0 -1
  89. package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -1
  90. package/dist/core/__tests__/lifecycle.test.js +30 -2
  91. package/dist/core/__tests__/revive-parked-fresh.test.d.ts +1 -0
  92. package/dist/core/__tests__/revive-parked-fresh.test.js +109 -0
  93. package/dist/core/__tests__/seam/dormancy-release.test.js +32 -5
  94. package/dist/core/canvas/attention.d.ts +2 -0
  95. package/dist/core/canvas/attention.js +25 -18
  96. package/dist/core/canvas/extensions.d.ts +1 -1
  97. package/dist/core/canvas/extensions.js +7 -1
  98. package/dist/core/canvas/history.js +20 -2
  99. package/dist/core/canvas/types.d.ts +1 -1
  100. package/dist/core/command.js +33 -8
  101. package/dist/core/help.d.ts +28 -2
  102. package/dist/core/help.js +46 -10
  103. package/dist/core/human/__tests__/page-html-markdown.test.d.ts +1 -0
  104. package/dist/core/human/__tests__/page-html-markdown.test.js +48 -0
  105. package/dist/core/human/component-docs.js +4 -4
  106. package/dist/core/human/page-html-markdown.d.ts +8 -0
  107. package/dist/core/human/page-html-markdown.js +260 -0
  108. package/dist/core/memory/lint.d.ts +15 -0
  109. package/dist/core/memory/lint.js +150 -90
  110. package/dist/core/profiles/__tests__/fuzzy-match.test.d.ts +1 -0
  111. package/dist/core/profiles/__tests__/fuzzy-match.test.js +51 -0
  112. package/dist/core/profiles/fuzzy-match.d.ts +19 -0
  113. package/dist/core/profiles/fuzzy-match.js +92 -0
  114. package/dist/core/profiles/manifest.d.ts +14 -7
  115. package/dist/core/profiles/manifest.js +62 -12
  116. package/dist/core/profiles/select.d.ts +3 -1
  117. package/dist/core/profiles/select.js +5 -3
  118. package/dist/core/profiles/state-block.js +4 -3
  119. package/dist/core/runtime/boot-root.d.ts +3 -2
  120. package/dist/core/runtime/canvas-extensions.d.ts +7 -1
  121. package/dist/core/runtime/canvas-extensions.js +8 -1
  122. package/dist/core/runtime/lifecycle.d.ts +11 -2
  123. package/dist/core/runtime/lifecycle.js +15 -2
  124. package/dist/core/runtime/model-selection.d.ts +4 -0
  125. package/dist/core/runtime/model-selection.js +5 -0
  126. package/dist/core/runtime/nodes.js +5 -0
  127. package/dist/core/runtime/reopen.d.ts +6 -0
  128. package/dist/core/runtime/reopen.js +12 -1
  129. package/dist/core/runtime/revive.d.ts +6 -0
  130. package/dist/core/runtime/revive.js +22 -2
  131. package/dist/core/runtime/spawn.d.ts +5 -2
  132. package/dist/core/runtime/spawn.js +18 -32
  133. package/dist/core/runtime/structured-output.d.ts +6 -0
  134. package/dist/core/runtime/structured-output.js +6 -0
  135. package/dist/core/substrate/__tests__/surface-match-command.test.d.ts +1 -0
  136. package/dist/core/substrate/__tests__/surface-match-command.test.js +89 -0
  137. package/dist/core/substrate/__tests__/surface-match-pre-command.test.d.ts +1 -0
  138. package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +92 -0
  139. package/dist/core/substrate/frontmatter-validation.js +1 -1
  140. package/dist/core/substrate/injected-store.d.ts +6 -0
  141. package/dist/core/substrate/injected-store.js +24 -0
  142. package/dist/core/substrate/on-read.d.ts +17 -1
  143. package/dist/core/substrate/on-read.js +38 -3
  144. package/dist/core/substrate/schema.d.ts +3 -3
  145. package/dist/core/substrate/schema.js +4 -4
  146. package/dist/core/substrate/surface-match.d.ts +19 -0
  147. package/dist/core/substrate/surface-match.js +224 -12
  148. package/dist/core/termrender/version.d.ts +1 -1
  149. package/dist/core/termrender/version.js +1 -1
  150. package/dist/core/user-settings.js +1 -1
  151. package/dist/daemon/api/__tests__/broker-settle-park.test.d.ts +1 -0
  152. package/dist/daemon/api/__tests__/broker-settle-park.test.js +102 -0
  153. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.d.ts +1 -0
  154. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +188 -0
  155. package/dist/daemon/api/__tests__/node-create-description.test.d.ts +1 -0
  156. package/dist/daemon/api/__tests__/node-create-description.test.js +83 -0
  157. package/dist/daemon/api/__tests__/profile-metadata-route.test.d.ts +1 -0
  158. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +92 -0
  159. package/dist/daemon/api/__tests__/reopen-delivery.test.d.ts +1 -0
  160. package/dist/daemon/api/__tests__/reopen-delivery.test.js +173 -0
  161. package/dist/daemon/api/handlers/broker-ops.js +21 -0
  162. package/dist/daemon/api/handlers/canvas.js +10 -0
  163. package/dist/daemon/api/handlers/messages.js +25 -16
  164. package/dist/daemon/api/handlers/nodes.js +5 -0
  165. package/dist/daemon/api/handlers/profiles.js +22 -1
  166. package/dist/daemon/cron-run.js +19 -1
  167. package/dist/daemon/manage.d.ts +16 -1
  168. package/dist/daemon/manage.js +20 -1
  169. package/dist/daemon/park-pending.d.ts +13 -0
  170. package/dist/daemon/park-pending.js +42 -0
  171. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -0
  172. package/dist/daemon/reconcilers/broker-supervision.js +139 -21
  173. package/dist/daemon/reconcilers/live-obligation.d.ts +10 -4
  174. package/dist/daemon/reconcilers/live-obligation.js +7 -3
  175. package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -4
  176. package/dist/daemon/reconcilers/storage-maintenance.js +1 -33
  177. package/dist/pi-extensions/__tests__/pre-command-gate.test.d.ts +1 -0
  178. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +220 -0
  179. package/dist/pi-extensions/canvas-doc-substrate.d.ts +14 -0
  180. package/dist/pi-extensions/canvas-doc-substrate.js +75 -2
  181. package/dist/pi-extensions/canvas-prompt-scrub.d.ts +13 -0
  182. package/dist/pi-extensions/canvas-prompt-scrub.js +53 -0
  183. package/dist/shared/generated-context.d.ts +7 -0
  184. package/dist/shared/generated-context.js +11 -0
  185. package/package.json +4 -4
  186. package/runtime.lock.json +2 -2
  187. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/strip-skills-docs.ts +0 -47
@@ -29,9 +29,23 @@ interface ToolResultCtxLike {
29
29
  type ToolResultResultLike = {
30
30
  content: ContentBlockLike[];
31
31
  } | void;
32
+ /** tool_call: fired BEFORE the tool runs. Returning `{block: true, reason}`
33
+ * stops it — nothing executes, no `tool_result` fires, and `reason` becomes the
34
+ * call's synthesized error result, carrying arbitrary-length text. */
35
+ interface ToolCallEventLike {
36
+ toolName: string;
37
+ input?: unknown;
38
+ }
39
+ type ToolCallResultLike = {
40
+ block: true;
41
+ reason: string;
42
+ } | void;
32
43
  interface PiLike {
33
44
  on(event: 'before_agent_start', handler: (event: BeforeAgentStartEventLike) => BeforeAgentStartResultLike | void | Promise<BeforeAgentStartResultLike | void>): void;
34
45
  on(event: 'session_start', handler: (event: unknown, ctx: unknown) => void | Promise<void>): void;
46
+ on(event: 'session_compact', handler: (event: unknown, ctx: unknown) => void | Promise<void>): void;
47
+ on(event: 'turn_end', handler: (event: unknown, ctx: unknown) => void | Promise<void>): void;
48
+ on(event: 'tool_call', handler: (event: ToolCallEventLike, ctx: unknown) => ToolCallResultLike | Promise<ToolCallResultLike>): void;
35
49
  on(event: 'tool_result', handler: (event: ToolResultEventLike, ctx: ToolResultCtxLike) => ToolResultResultLike | Promise<ToolResultResultLike>): void;
36
50
  }
37
51
  export declare function registerCanvasDocSubstrate(pi: PiLike): void;
@@ -7,7 +7,9 @@
7
7
  //
8
8
  // before_agent_start splices the context's frozen preference snapshot after the
9
9
  // native tool list. Successful read/bash results append matching memory through
10
- // the shared context exposure state. Pure rendering lives in core/substrate/.
10
+ // the shared context exposure state. A bash call matching a `pre-command` doc is
11
+ // BLOCKED before it runs and the doc comes back as its synthesized error result.
12
+ // Pure rendering lives in core/substrate/.
11
13
  //
12
14
  // Plain TS-with-types — NO imports from @earendil-works/* (a local structural
13
15
  // PiLike interface stands in), so it compiles inside crouter's own tsc build
@@ -16,7 +18,7 @@ import { homedir } from 'node:os';
16
18
  import { join, resolve } from 'node:path';
17
19
  import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
18
20
  import { renderPreferencesFromState } from '../core/runtime/broker-extension-render.js';
19
- import { renderOnCommandDocsForSubject, renderOnReadDocsForSubject } from '../core/substrate/on-read.js';
21
+ import { corpusHasPreCommandSurfaces, demotePreCommandExposures, renderOnCommandDocsForSubject, renderOnReadDocsForSubject, renderPreCommandDocsForSubject, } from '../core/substrate/on-read.js';
20
22
  import { clearSessionCache } from '../core/substrate/session-cache.js';
21
23
  import { cloneContextExposureState, exposureTarget, freezePreferenceSnapshot, loadContextExposureState, mergeContextExposureState, replaceContextExposureState, saveContextExposureState, sharedContextExposureState, } from '../core/substrate/injected-store.js';
22
24
  import { autoLoadedContextInner, mergeAutoLoadedContext } from './envelope-merge.js';
@@ -28,6 +30,38 @@ import { autoLoadedContextInner, mergeAutoLoadedContext } from './envelope-merge
28
30
  * to reach for while reading the tools, so memory docs/preferences must sit
29
31
  * there, not far below. Falls back to appending if absent. */
30
32
  const TOOLS_ANCHOR = '\n\nGuidelines:';
33
+ /** The bash command string a tool call carries, or `null` when there is none. */
34
+ function bashCommandOf(input) {
35
+ const command = input?.command;
36
+ return typeof command === 'string' && command.trim() !== '' ? command : null;
37
+ }
38
+ /** The blocked call's synthesized error result. A blocked command is discarded
39
+ * IN FULL — pi executes none of it — so the copy must steer a re-issue of the
40
+ * WHOLE command, never of one clause: when the same command also built its own
41
+ * input (a heredoc, a `>` redirect, a `$(…)`), that setup did not run either,
42
+ * and re-issuing only the tail would act on stale or missing data. */
43
+ function heldReason(rendered) {
44
+ return [
45
+ 'HELD — nothing ran.',
46
+ '',
47
+ 'Your bash command was NOT executed. It matched memory you had not yet read, and that memory is below.',
48
+ '',
49
+ 'Read it, then re-issue your WHOLE command unchanged — every clause of it, including any heredoc, redirect, or `$(…)` that built its input, because none of that ran either. The re-issue executes: this memory is now in your transcript, so there is nothing left to deliver and nothing left to hold.',
50
+ '',
51
+ rendered,
52
+ ].join('\n');
53
+ }
54
+ /** The follow-on notice for a SIBLING command in the same assistant message.
55
+ * pi preflights siblings sequentially and then executes them concurrently, so
56
+ * without one flag per turn the second sibling would find the doc already
57
+ * exposed and slip past the hold its sibling just raised. */
58
+ const HELD_SIBLING_REASON = [
59
+ 'HELD — nothing ran.',
60
+ '',
61
+ 'Your bash command was NOT executed. Another command in this same message was held against memory you had not read, and that memory was returned with it.',
62
+ '',
63
+ 'Read it, then re-issue your WHOLE command unchanged. The re-issue executes.',
64
+ ].join('\n');
31
65
  export function registerCanvasDocSubstrate(pi) {
32
66
  const nodeId = process.env['CRTR_NODE_ID'];
33
67
  if (nodeId === undefined || nodeId.trim() === '')
@@ -57,6 +91,45 @@ export function registerCanvasDocSubstrate(pi) {
57
91
  systemPrompt: `${event.systemPrompt.slice(0, idx)}\n\n${block}${event.systemPrompt.slice(idx)}`,
58
92
  };
59
93
  });
94
+ // One flag per assistant turn: the first hold covers every matching command
95
+ // in the same message.
96
+ let blockedThisTurn = false;
97
+ pi.on('turn_end', () => {
98
+ blockedThisTurn = false;
99
+ });
100
+ // Compaction drops delivered guidance out of the transcript while the ledger
101
+ // still records it as delivered. Forget those deliveries so the holds re-arm.
102
+ pi.on('session_compact', () => {
103
+ mergeContextExposureState(contextExposure, loadContextExposureState(nodeId));
104
+ demotePreCommandExposures(contextExposure);
105
+ saveContextExposureState(nodeId, contextExposure);
106
+ blockedThisTurn = false;
107
+ });
108
+ pi.on('tool_call', async (event) => {
109
+ if (event.toolName !== 'bash')
110
+ return;
111
+ const command = bashCommandOf(event.input);
112
+ if (command === null)
113
+ return;
114
+ // The common case is a corpus with no pre-command doc at all, and it must
115
+ // cost nothing — short-circuit before the daemon round-trip below.
116
+ if (!corpusHasPreCommandSurfaces())
117
+ return;
118
+ if (blockedThisTurn)
119
+ return { block: true, reason: HELD_SIBLING_REASON };
120
+ const state = await brokerExtensionState(nodeId);
121
+ mergeContextExposureState(contextExposure, loadContextExposureState(nodeId));
122
+ const next = cloneContextExposureState(contextExposure);
123
+ const rendered = renderPreCommandDocsForSubject(state.subject, command, exposureTarget(next, 'transcript'));
124
+ // Everything this command matches is already in the transcript: the hold is
125
+ // released and the command runs.
126
+ if (rendered === '')
127
+ return;
128
+ blockedThisTurn = true;
129
+ saveContextExposureState(nodeId, next);
130
+ replaceContextExposureState(contextExposure, next);
131
+ return { block: true, reason: heldReason(rendered) };
132
+ });
60
133
  pi.on('tool_result', async (event, ctx) => {
61
134
  if (event.isError === true)
62
135
  return;
@@ -0,0 +1,13 @@
1
+ /** Strip pi's self-references from an assembled system prompt. */
2
+ export declare function scrubPromptSelfReference(systemPrompt: string): string;
3
+ interface BeforeAgentStartEventLike {
4
+ systemPrompt: string;
5
+ }
6
+ interface PiLike {
7
+ on(event: 'before_agent_start', handler: (event: BeforeAgentStartEventLike) => {
8
+ systemPrompt: string;
9
+ } | void): void;
10
+ }
11
+ /** Register the system-prompt scrub for a canvas node. */
12
+ export declare function registerCanvasPromptScrub(pi: PiLike): void;
13
+ export default registerCanvasPromptScrub;
@@ -0,0 +1,53 @@
1
+ // canvas-prompt-scrub.ts — removes pi's self-referential prompt text before any
2
+ // other consumer reads the system prompt.
3
+ //
4
+ // pi's prompt builder hardcodes two things a canvas node should not carry:
5
+ //
6
+ // 1. An opening sentence naming pi as the harness. A node's identity is the
7
+ // canvas persona crouter appends, not the engine it happens to run on.
8
+ // 2. A "Pi documentation (read only ...):" block — a marker line plus bullets
9
+ // pointing at pi's README / docs / examples under node_modules. It maps
10
+ // topics to doc files, which makes the agent extrapolate a
11
+ // topic -> docs/<topic>.md pattern and surface pi's internals unprompted.
12
+ //
13
+ // ORDER IS THE POINT. This must be a canvas extension, not a package one:
14
+ // crouter's canvas extensions load ahead of installed pi packages, and the
15
+ // Claude subscription adapter is a package. That adapter also wants the docs
16
+ // block gone (it is a third-party tell that costs a Claude subscription its
17
+ // plan rate), but it removes the block by cutting from the marker to the next
18
+ // boundary marker it knows — and a canvas prompt has none, so the cut runs to
19
+ // the end of the prompt and takes crouter's appended canvas persona with it.
20
+ // Scrubbing here leaves the adapter nothing to find, so the persona survives.
21
+ // The companion guard is CRTR env that disables the adapter's re-injection;
22
+ // without it the adapter rebuilds the block from its own fallback copy.
23
+ //
24
+ // Every rule below is anchored to pi's exact wording and degrades to a no-op if
25
+ // pi rewords, so a pi upgrade can never break a turn here.
26
+ const PI_IDENTITY = 'You are an expert coding assistant operating inside pi, a coding agent harness.';
27
+ const NEUTRAL_IDENTITY = 'You are an expert coding assistant.';
28
+ const PI_DOCS_MARKER = 'Pi documentation (read only';
29
+ // The marker line plus its trailing "- ..." bullets, and any leading blank
30
+ // lines so the surrounding prompt closes up cleanly.
31
+ const PI_DOCS_BLOCK = /\n*^Pi documentation \(read only[^\n]*:(?:\n[ \t]*-[^\n]*)*/m;
32
+ /** Strip pi's self-references from an assembled system prompt. */
33
+ export function scrubPromptSelfReference(systemPrompt) {
34
+ let prompt = systemPrompt;
35
+ if (prompt.includes(PI_IDENTITY))
36
+ prompt = prompt.replace(PI_IDENTITY, NEUTRAL_IDENTITY);
37
+ if (prompt.includes(PI_DOCS_MARKER))
38
+ prompt = `${prompt.replace(PI_DOCS_BLOCK, '').trimEnd()}\n`;
39
+ return prompt;
40
+ }
41
+ /** Register the system-prompt scrub for a canvas node. */
42
+ export function registerCanvasPromptScrub(pi) {
43
+ const nodeId = process.env['CRTR_NODE_ID'];
44
+ if (nodeId === undefined || nodeId.trim() === '')
45
+ return;
46
+ pi.on('before_agent_start', (event) => {
47
+ const scrubbed = scrubPromptSelfReference(event.systemPrompt);
48
+ if (scrubbed === event.systemPrompt)
49
+ return;
50
+ return { systemPrompt: scrubbed };
51
+ });
52
+ }
53
+ export default registerCanvasPromptScrub;
@@ -8,6 +8,13 @@ export declare const CONTEXT_NUDGE_CUSTOM_TYPE = "crtr-context-nudge";
8
8
  export declare const REVIEW_BOUNDARY_CUSTOM_TYPE = "crtr-review-boundary";
9
9
  /** Generic completion mandate issued by the terminal-node stop guard. */
10
10
  export declare const STALL_REPROMPT: string;
11
+ /** The daemon's parking mandate: the last turn of a conversation the unattended
12
+ * clock is concluding. Delivered live, wrapped in a `park` runtime card. It
13
+ * shares a CONTRACT with `node yield`'s pre-invocation guide (roadmap current,
14
+ * short and shrinking; context dir for in-progress material; memory only for
15
+ * gated permanent lessons) but not a string: yield is read by an agent choosing
16
+ * to refresh, this by an agent being told to conclude. */
17
+ export declare const PARK_SUMMARY_PROMPT: string;
11
18
  /** Static recovery prompts shared by the broker producer and display classifier. */
12
19
  export declare const AUTH_FAULT_RECOVERY_BODY = "Provider credentials were just updated (a new login landed). Your previous turn stopped on a provider authentication failure. Continue from where you left off and retry the work that failed.";
13
20
  export declare const CONNECTION_FAULT_RECOVERY_BODY = "The network connection is back online. Your previous turn stopped on a connection error (the network was down). Continue from where you left off and retry the work that failed.";
@@ -13,6 +13,17 @@ export const REVIEW_BOUNDARY_CUSTOM_TYPE = 'crtr-review-boundary';
13
13
  /** Generic completion mandate issued by the terminal-node stop guard. */
14
14
  export const STALL_REPROMPT = "You've stopped but you're not waiting on anyone and haven't finished. " +
15
15
  "Pipe the result to `crtr push final` through a single-quoted heredoc if the work is done, or use `crtr human send` if you are blocked or need the user.";
16
+ /** The daemon's parking mandate: the last turn of a conversation the unattended
17
+ * clock is concluding. Delivered live, wrapped in a `park` runtime card. It
18
+ * shares a CONTRACT with `node yield`'s pre-invocation guide (roadmap current,
19
+ * short and shrinking; context dir for in-progress material; memory only for
20
+ * gated permanent lessons) but not a string: yield is read by an agent choosing
21
+ * to refresh, this by an agent being told to conclude. */
22
+ export const PARK_SUMMARY_PROMPT = 'This conversation has been idle with nothing waiting on it, so it is being concluded. This is your last turn — do these four things now, then stop.\n\n'
23
+ + '1. Bring your roadmap current. It lives at `$CRTR_CONTEXT_DIR/roadmap.md`, and it is the document a fresh cycle reads to know where things stand: what was done, what is still open, and what someone picking this up needs. Write one now if you never had one. Keep it short and shrinking — strategy and present state only, deleting completed items rather than marking them done.\n\n'
24
+ + '2. Save anything else worth keeping. In-progress task material — what has happened, identifiers, in-flight state — goes to one or more files in your context directory. A permanent lesson worth remembering indefinitely goes to node memory (`crtr memory write -h`), gated deliberately: transcript state does not belong in memory.\n\n'
25
+ + '3. Push one regular report to your subscribers summarizing where things stand: `crtr push update`. NOT `crtr push final` — this concludes the conversation, it does not finish a mandate.\n\n'
26
+ + '4. Stop. A later message reopens you on a fresh context window grounded in your goal and that roadmap, so what you leave behind now is what you get back.';
16
27
  /** Static recovery prompts shared by the broker producer and display classifier. */
17
28
  export const AUTH_FAULT_RECOVERY_BODY = 'Provider credentials were just updated (a new login landed). Your previous turn stopped on a provider authentication failure. Continue from where you left off and retry the work that failed.';
18
29
  export const CONNECTION_FAULT_RECOVERY_BODY = 'The network connection is back online. Your previous turn stopped on a connection error (the network was down). Continue from where you left off and retry the work that failed.';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.231",
3
+ "version": "0.3.233",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -81,10 +81,10 @@
81
81
  "dev": "tsx --conditions=crtr-src src/cli.ts",
82
82
  "link": "npm link",
83
83
  "prepublishOnly": "npm run build",
84
- "test": "node --conditions=crtr-src --import tsx/esm --test --test-force-exit --test-concurrency=$(node -p 'Math.max(4, require(`node:os`).availableParallelism() - 1)') --test-timeout=10000 'src/**/__tests__/*.test.ts'",
85
- "test:integration": "node --conditions=crtr-src --import tsx/esm --test --test-concurrency=$(node -p 'Math.min(8, Math.max(2, require(`node:os`).availableParallelism() - 1))') --test-timeout=60000 'src/**/__tests__/integration/*.test.ts'",
84
+ "test": "CRTR_NO_DAEMON_AUTOSTART=1 node --conditions=crtr-src --import tsx/esm --test --test-force-exit --test-concurrency=$(node -p 'Math.max(4, require(`node:os`).availableParallelism() - 1)') --test-timeout=10000 'src/**/__tests__/*.test.ts'",
85
+ "test:integration": "CRTR_NO_DAEMON_AUTOSTART=1 node --conditions=crtr-src --import tsx/esm --test --test-concurrency=$(node -p 'Math.min(8, Math.max(2, require(`node:os`).availableParallelism() - 1))') --test-timeout=60000 'src/**/__tests__/integration/*.test.ts'",
86
86
  "test:seam": "npm run build && npm run test:seam:built",
87
- "test:seam:built": "node --test --test-concurrency=4 --test-timeout=180000 'dist/**/__tests__/seam/*.test.js'",
87
+ "test:seam:built": "CRTR_NO_DAEMON_AUTOSTART=1 node --test --test-concurrency=4 --test-timeout=180000 'dist/**/__tests__/seam/*.test.js'",
88
88
  "test:all": "npm test && npm run test:integration && npm run test:seam"
89
89
  },
90
90
  "overrides": {
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.231",
3
+ "version": "0.3.233",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.231",
9
+ "version": "0.3.233",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -1,47 +0,0 @@
1
- /**
2
- * Strip pi's "Pi documentation" block from the system prompt.
3
- *
4
- * Pi core hardcodes a "Pi documentation (read only when the user asks about pi
5
- * itself, its SDK, extensions, themes, skills, or TUI):" block — a marker line
6
- * plus a bullet list pointing at pi's README / docs / examples under
7
- * node_modules. It causes two problems we fix by removing the whole block:
8
- *
9
- * 1. It maps topics to doc files (`skills (docs/skills.md)`, etc.), which makes
10
- * the agent extrapolate a topic -> docs/<topic>.md pattern and surface pi's
11
- * internal skill system when we don't want it referenced.
12
- * 2. It is a THIRD-PARTY TELL. When authenticating a Claude subscription over
13
- * OAuth, Anthropic inspects the request and — if it doesn't look like genuine
14
- * Claude Code — routes it to "extra usage" instead of the plan, returning
15
- * HTTP 400 ("Third-party apps now draw from your extra usage..."). The
16
- * companion `pi-claude-oauth-adapter` normally strips this block for exactly
17
- * that reason, but it matches the marker string INCLUDING the word "skills,"
18
- * — and the earlier version of THIS extension mangled that marker (it removed
19
- * just the "skills" word), so the adapter's match failed and the block leaked
20
- * to the wire → every subscription turn 400'd. Removing the entire block here
21
- * is self-contained: it fixes the leak regardless of the adapter's marker,
22
- * load order, or presence, and subsumes the old skill-reference removal.
23
- *
24
- * Runs in `before_agent_start` so it survives `pi update` / `brew upgrade`
25
- * (which would overwrite any edit to the installed dist), and degrades to a
26
- * no-op if pi changes the wording.
27
- */
28
-
29
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
30
-
31
- // Matches the whole block: the "Pi documentation (read only ...):" marker line
32
- // (with or without the "skills," enumeration) plus its trailing "- ..." bullets,
33
- // and any leading blank lines so the surrounding prompt closes up cleanly.
34
- const PI_DOCS_BLOCK = /\n*^Pi documentation \(read only[^\n]*:(?:\n[ \t]*-[^\n]*)*/m;
35
-
36
- function stripPiDocsBlock(prompt: string): string {
37
- if (!prompt.includes("Pi documentation (read only")) return prompt; // no-op / wording changed
38
- return prompt.replace(PI_DOCS_BLOCK, "").trimEnd() + "\n";
39
- }
40
-
41
- export default function stripSkillsDocs(pi: ExtensionAPI) {
42
- pi.on("before_agent_start", async (event) => {
43
- const stripped = stripPiDocsBlock(event.systemPrompt);
44
- if (stripped === event.systemPrompt) return;
45
- return { systemPrompt: stripped };
46
- });
47
- }