@north-light/crouter 0.3.262 → 0.3.269

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 (150) hide show
  1. package/dist/api/client.d.ts +5 -1
  2. package/dist/api/client.js +6 -0
  3. package/dist/api/dto/canvas.d.ts +53 -2
  4. package/dist/api/dto/health.d.ts +2 -0
  5. package/dist/api/dto/nodes.d.ts +6 -2
  6. package/dist/api/routes.d.ts +1 -0
  7. package/dist/api/routes.js +1 -0
  8. package/dist/builtin-memory/05-kinds/advisor/advice-contract.md +2 -2
  9. package/dist/builtin-memory/internal/memory-loading.md +3 -3
  10. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +50 -0
  11. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +46 -6
  12. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +10 -5
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  14. package/dist/clients/attach/input/controller.d.ts +4 -0
  15. package/dist/clients/attach/input/controller.js +8 -0
  16. package/dist/clients/attach/session/bindings.d.ts +3 -0
  17. package/dist/clients/attach/session/bindings.js +7 -0
  18. package/dist/clients/attach/session/keys.d.ts +2 -0
  19. package/dist/clients/attach/session/keys.js +3 -3
  20. package/dist/clients/attach/session/whip-achievements.d.ts +4 -0
  21. package/dist/clients/attach/session/whip-achievements.js +145 -0
  22. package/dist/clients/attach/slash/dispatch.js +5 -3
  23. package/dist/clients/attach/viewer.js +668 -667
  24. package/dist/commands/canvas-history/grep.js +3 -22
  25. package/dist/commands/canvas-history/read.js +5 -3
  26. package/dist/commands/canvas-history/search.js +3 -22
  27. package/dist/commands/canvas-history/shared.d.ts +8 -0
  28. package/dist/commands/canvas-history/shared.js +64 -1
  29. package/dist/commands/canvas-history/stats.d.ts +1 -0
  30. package/dist/commands/canvas-history/stats.js +68 -0
  31. package/dist/commands/canvas-history.js +4 -3
  32. package/dist/commands/memory/read.js +15 -38
  33. package/dist/commands/memory/shared.d.ts +1 -1
  34. package/dist/commands/memory/shared.js +1 -1
  35. package/dist/commands/node/create.js +2 -2
  36. package/dist/commands/sys/config.js +19 -2
  37. package/dist/commands/sys/context/admin/docs-panel.d.ts +3 -3
  38. package/dist/commands/sys/context/admin/model.d.ts +7 -2
  39. package/dist/commands/sys/context/admin/model.js +7 -1
  40. package/dist/commands/sys/context/admin/read-view.d.ts +5 -5
  41. package/dist/commands/sys/context/admin/read-view.js +9 -4
  42. package/dist/commands/sys/context/resolve.d.ts +32 -3
  43. package/dist/commands/sys/context/resolve.js +74 -25
  44. package/dist/commands/sys/panels/models-panel.d.ts +28 -5
  45. package/dist/commands/sys/panels/models-panel.js +560 -75
  46. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +1 -1
  47. package/dist/core/__tests__/integration/revive.test.js +4 -2
  48. package/dist/core/__tests__/model-pin-durability.test.js +25 -1
  49. package/dist/core/__tests__/model-routes-config.test.d.ts +1 -0
  50. package/dist/core/__tests__/model-routes-config.test.js +142 -0
  51. package/dist/core/__tests__/on-read-nested-store.test.js +8 -0
  52. package/dist/core/__tests__/profile-project-memory-delivery.test.js +264 -1
  53. package/dist/core/__tests__/relaunch-root.test.js +17 -0
  54. package/dist/core/__tests__/seam/broker-provider-retry.test.js +21 -6
  55. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +19 -2
  56. package/dist/core/broker-client/__tests__/transport-relay.test.js +3 -1
  57. package/dist/core/broker-client/transport-relay.js +5 -1
  58. package/dist/core/canvas/__tests__/history-transcript.test.d.ts +1 -0
  59. package/dist/core/canvas/__tests__/history-transcript.test.js +102 -0
  60. package/dist/core/canvas/browse/app.d.ts +1 -1
  61. package/dist/core/canvas/browse/app.js +13 -10
  62. package/dist/core/canvas/browse/model.js +16 -1
  63. package/dist/core/canvas/browse/render.d.ts +23 -3
  64. package/dist/core/canvas/browse/render.js +429 -64
  65. package/dist/core/canvas/canvas.js +12 -8
  66. package/dist/core/canvas/extensions.d.ts +1 -1
  67. package/dist/core/canvas/extensions.js +7 -1
  68. package/dist/core/canvas/history.d.ts +36 -1
  69. package/dist/core/canvas/history.js +328 -7
  70. package/dist/core/canvas/labels.d.ts +2 -2
  71. package/dist/core/canvas/migrations.js +32 -0
  72. package/dist/core/canvas/node-recap.d.ts +23 -0
  73. package/dist/core/canvas/node-recap.js +67 -0
  74. package/dist/core/canvas/render-source.d.ts +34 -2
  75. package/dist/core/canvas/render-source.js +83 -24
  76. package/dist/core/canvas/types.d.ts +9 -0
  77. package/dist/core/config.d.ts +19 -2
  78. package/dist/core/config.js +174 -51
  79. package/dist/core/keybindings/catalog.d.ts +2 -2
  80. package/dist/core/keybindings/catalog.js +11 -8
  81. package/dist/core/model-routes.js +11 -4
  82. package/dist/core/runtime/broker/auth-reload.js +4 -1
  83. package/dist/core/runtime/broker/fault-retry.js +7 -2
  84. package/dist/core/runtime/broker/frame-client.js +4 -0
  85. package/dist/core/runtime/broker/frame-dispatch.js +7 -0
  86. package/dist/core/runtime/broker/inbox.d.ts +12 -2
  87. package/dist/core/runtime/broker/inbox.js +68 -38
  88. package/dist/core/runtime/broker-protocol.d.ts +6 -0
  89. package/dist/core/runtime/broker.js +14 -0
  90. package/dist/core/runtime/canvas-extensions.d.ts +1 -0
  91. package/dist/core/runtime/canvas-extensions.js +2 -0
  92. package/dist/core/runtime/interactive-deliver.d.ts +8 -2
  93. package/dist/core/runtime/interactive-deliver.js +12 -3
  94. package/dist/core/runtime/launch-target.js +1 -1
  95. package/dist/core/runtime/launch.d.ts +12 -6
  96. package/dist/core/runtime/launch.js +19 -17
  97. package/dist/core/runtime/model-swap.d.ts +5 -4
  98. package/dist/core/runtime/model-swap.js +7 -5
  99. package/dist/core/runtime/promote.js +2 -1
  100. package/dist/core/runtime/reset.js +4 -2
  101. package/dist/core/runtime/revive.js +22 -0
  102. package/dist/core/runtime/spawn.d.ts +3 -3
  103. package/dist/core/runtime/spawn.js +20 -3
  104. package/dist/core/runtime/stamp/channel.d.ts +18 -0
  105. package/dist/core/runtime/stamp/channel.js +74 -0
  106. package/dist/core/runtime/stamp/protocol.d.ts +86 -0
  107. package/dist/core/runtime/stamp/protocol.js +113 -0
  108. package/dist/core/runtime/tmux-driver.d.ts +11 -1
  109. package/dist/core/runtime/tmux-driver.js +27 -11
  110. package/dist/core/self-update.js +2 -5
  111. package/dist/core/substrate/listings.d.ts +1 -1
  112. package/dist/core/substrate/listings.js +6 -2
  113. package/dist/core/substrate/on-read.d.ts +61 -5
  114. package/dist/core/substrate/on-read.js +129 -22
  115. package/dist/core/substrate/render.d.ts +3 -2
  116. package/dist/core/substrate/render.js +133 -38
  117. package/dist/core/tui/draw.d.ts +1 -0
  118. package/dist/core/tui/draw.js +5 -1
  119. package/dist/core/tui/markdown.d.ts +17 -0
  120. package/dist/core/tui/markdown.js +407 -0
  121. package/dist/core/user-settings.d.ts +4 -0
  122. package/dist/core/user-settings.js +1 -0
  123. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -0
  124. package/dist/daemon/api/__tests__/seam/api-server.test.js +34 -0
  125. package/dist/daemon/api/bridge.d.ts +3 -2
  126. package/dist/daemon/api/bridge.js +34 -9
  127. package/dist/daemon/api/handlers/canvas.js +80 -18
  128. package/dist/daemon/api/handlers/health.js +17 -12
  129. package/dist/daemon/api/handlers/messages.js +12 -1
  130. package/dist/daemon/api/handlers/nodes.js +10 -3
  131. package/dist/daemon/api/map.js +2 -0
  132. package/dist/daemon/messaging/node-message.js +15 -1
  133. package/dist/daemon/reconcilers/broker-supervision.js +26 -9
  134. package/dist/daemon/reconcilers/live-obligation.d.ts +8 -1
  135. package/dist/daemon/reconcilers/live-obligation.js +17 -0
  136. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +2 -2
  137. package/dist/pi-extensions/canvas-inbox-watcher.js +27 -2
  138. package/dist/pi-extensions/canvas-recap.js +4 -0
  139. package/dist/pi-extensions/canvas-stamp.d.ts +14 -0
  140. package/dist/pi-extensions/canvas-stamp.js +77 -0
  141. package/dist/pi-extensions/canvas-stophook.js +3 -0
  142. package/dist/shared/__tests__/env-boundary.test.js +4 -2
  143. package/dist/shared/crtr-version.d.ts +2 -0
  144. package/dist/shared/crtr-version.js +18 -0
  145. package/dist/shared/env.d.ts +10 -0
  146. package/dist/shared/env.js +19 -4
  147. package/dist/types.d.ts +14 -2
  148. package/dist/types.js +4 -0
  149. package/package.json +1 -1
  150. package/runtime.lock.json +2 -2
@@ -0,0 +1,77 @@
1
+ // canvas-stamp.ts — the sole writer of `crtr-stamp` entries.
2
+ //
3
+ // Two records land in the session jsonl. A SESSION stamp names the node and the
4
+ // crtr release that own the file, appended at session start only when the
5
+ // latest one on disk disagrees — which covers a fresh session, a fork (whose
6
+ // copied history still carries the source node's stamp), a new cycle, and a
7
+ // runtime upgrade mid-node, without a rule per case. A MESSAGE stamp records
8
+ // where one user message came from, joined to it by the message's own
9
+ // timestamp.
10
+ //
11
+ // Every user message is stamped; an origin appears only when a delivery seam
12
+ // announced one (absence means unknown, never a guess). An assistant message is
13
+ // stamped only when an `ext` contribution is pending, so an ordinary turn costs
14
+ // no line.
15
+ //
16
+ // Ordering note: pi runs message_end handlers BEFORE it persists the finalized
17
+ // message, so the stamp is written as that message's structural parent. The
18
+ // join is by `msgTs`, so tree position carries no meaning here.
19
+ import { envNodeId } from '../shared/env.js';
20
+ import { crtrVersion } from '../shared/crtr-version.js';
21
+ import { claimMessageOrigin, drainStampExt, hasPendingStampExt, } from '../core/runtime/stamp/channel.js';
22
+ import { CRTR_STAMP_CUSTOM_TYPE, latestSessionStamp, STAMP_SCHEMA_VERSION, } from '../core/runtime/stamp/protocol.js';
23
+ /** Plain text of a message's content (string or content blocks). */
24
+ function messageText(content) {
25
+ if (typeof content === 'string')
26
+ return content;
27
+ if (Array.isArray(content)) {
28
+ return content
29
+ .filter((block) => typeof block === 'object' && block !== null && typeof block.text === 'string')
30
+ .map((block) => block.text)
31
+ .join('\n');
32
+ }
33
+ return '';
34
+ }
35
+ function envelope(kind, payload) {
36
+ const ext = drainStampExt();
37
+ return {
38
+ v: STAMP_SCHEMA_VERSION,
39
+ kind,
40
+ payload,
41
+ ...(ext === undefined ? {} : { ext }),
42
+ };
43
+ }
44
+ /** Register the stamp writer. */
45
+ export function registerCanvasStamp(pi) {
46
+ pi.on('session_start', (_event, ctx) => {
47
+ const node = envNodeId();
48
+ if (node === undefined || node.trim() === '')
49
+ return;
50
+ const crtr = crtrVersion();
51
+ const latest = latestSessionStamp(ctx.sessionManager.getEntries());
52
+ if (latest !== null && latest.payload.node === node && latest.payload.crtr === crtr)
53
+ return;
54
+ pi.appendEntry(CRTR_STAMP_CUSTOM_TYPE, envelope('session', { node, crtr }));
55
+ });
56
+ pi.on('message_end', (event) => {
57
+ const message = event?.message;
58
+ if (message === undefined || message === null)
59
+ return;
60
+ if (typeof message.timestamp !== 'number')
61
+ return;
62
+ const msgTs = message.timestamp;
63
+ if (message.role === 'user') {
64
+ const origin = claimMessageOrigin(messageText(message.content));
65
+ pi.appendEntry(CRTR_STAMP_CUSTOM_TYPE, envelope('message', {
66
+ msgTs,
67
+ ...(origin === null ? {} : { origin }),
68
+ }));
69
+ return;
70
+ }
71
+ // Any other message earns a line only for a pending contribution.
72
+ if (!hasPendingStampExt())
73
+ return;
74
+ pi.appendEntry(CRTR_STAMP_CUSTOM_TYPE, envelope('message', { msgTs }));
75
+ });
76
+ }
77
+ export default registerCanvasStamp;
@@ -33,6 +33,7 @@ import { activeBackgroundBashJobs } from '../core/bash-jobs.js';
33
33
  import { CONTEXT_NUDGE_CUSTOM_TYPE, formatCard } from '../shared/generated-context.js';
34
34
  import { isReviewBoundary } from '../core/runtime/session-visibility.js';
35
35
  import { runRefreshAbort } from '../core/runtime/broker/extension-abort.js';
36
+ import { announceMessageOrigin } from '../core/runtime/stamp/channel.js';
36
37
  /** Condense a tool call into one short line for the activity cue. Picks the most
37
38
  * identifying arg (command / path / pattern / description), collapses whitespace,
38
39
  * and hard-caps the length so a giant bash command can't bloat telemetry.json. */
@@ -271,6 +272,7 @@ export function registerCanvasStophook(pi) {
271
272
  };
272
273
  const enactSettleDirective = (directive, ctx) => {
273
274
  if (directive.action === 'reprompt') {
275
+ announceMessageOrigin(directive.prompt, { type: 'runtime', kind: 'stop-guard' });
274
276
  pi.sendUserMessage(directive.prompt, { deliverAs: 'followUp' });
275
277
  return;
276
278
  }
@@ -566,6 +568,7 @@ export function registerCanvasStophook(pi) {
566
568
  firedBands.add(at);
567
569
  const note = formatCard('context-nudge', {}, steerNote(at, node.lifecycle, node.mode));
568
570
  if (runContinues) {
571
+ announceMessageOrigin(note, { type: 'runtime', kind: 'context-nudge' });
569
572
  pi.sendUserMessage(note, { deliverAs: 'steer' });
570
573
  }
571
574
  else {
@@ -17,6 +17,7 @@ const MIGRATED_VARS = [
17
17
  'CRTR_PROFILE_ID',
18
18
  'CRTR_NODE_CWD',
19
19
  'CRTR_MODEL_INTENT',
20
+ 'CRTR_MODEL_EXACT',
20
21
  'CRTR_HOME',
21
22
  'CRTR_STREAM_WATCHDOG_MS',
22
23
  'CRTR_WATCHER_TICK_MS',
@@ -35,6 +36,7 @@ const MIGRATED_VARS = [
35
36
  'CRTR_WARN_LIVE_BROKERS',
36
37
  'CRTR_TEST_UNATTENDED_PARK_MS',
37
38
  'CRTR_TEST_PARK_SUMMARY_GRACE_MS',
39
+ 'CRTR_UNATTENDED_PARK_MS',
38
40
  ];
39
41
  // Matches `process.env['VAR']`, `process.env.VAR`, or `process.env[\`VAR\`]`
40
42
  // for exactly one of MIGRATED_VARS — not a longer name that merely starts
@@ -53,8 +55,8 @@ const EXEMPTIONS = new Map([
53
55
  ],
54
56
  [
55
57
  'core/runtime/broker.ts',
56
- "clears CRTR_MODEL_INTENT via `delete process.env[...]` — a mutation, " +
57
- 'not a read, so it stays here per shared/env.ts\'s header comment.',
58
+ "clears CRTR_MODEL_INTENT and sets CRTR_MODEL_EXACT via process.env — mutations, " +
59
+ 'not reads, so they stay here per shared/env.ts\'s header comment.',
58
60
  ],
59
61
  ]);
60
62
  function tsFilesUnder(dir) {
@@ -0,0 +1,2 @@
1
+ /** The running crouter package version (`package.json` `version`). */
2
+ export declare function crtrVersion(): string;
@@ -0,0 +1,18 @@
1
+ // The installed crtr release string, read once per process from the package
2
+ // manifest. Callers that record a version into durable state (the session
3
+ // stamp) and callers that compare against npm (self-update) read this one
4
+ // implementation.
5
+ import { readFileSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ let cached = null;
9
+ /** The running crouter package version (`package.json` `version`). */
10
+ export function crtrVersion() {
11
+ if (cached !== null)
12
+ return cached;
13
+ // src|dist/shared/crtr-version.ts → up to src|dist/ → up to pkg root
14
+ const root = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
15
+ const parsed = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
16
+ cached = parsed.version;
17
+ return cached;
18
+ }
@@ -8,6 +8,8 @@ export declare function envNodeCwd(): string | undefined;
8
8
  * undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
9
9
  * in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
10
10
  export declare function envModelIntent(): string | undefined;
11
+ /** Whether the launch recipe requires this broker to keep its exact provider/model. */
12
+ export declare function envModelExact(): boolean;
11
13
  /** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
12
14
  * (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
13
15
  * only when a caller needs the override itself — to check whether one is
@@ -67,6 +69,14 @@ export declare function envWarnLiveBrokers(): number | undefined;
67
69
  /** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
68
70
  * gated by `envNoDaemonAutostart()` at the call site; no production default. */
69
71
  export declare function envTestUnattendedParkMs(): number | undefined;
72
+ /** Production unattended-park interval override (`CRTR_UNATTENDED_PARK_MS`), in
73
+ * milliseconds; wins over the user-scope config value
74
+ * (`readConfig('user').lifecycle.unattendedParkMs`, itself defaulting to 15
75
+ * min) whenever set, autostart or not. Unlike `CRTR_TEST_UNATTENDED_PARK_MS`
76
+ * this is not gated on `envNoDaemonAutostart()`: it is the env escape hatch
77
+ * above the configured knob a deployment sets to tune how long an eligible
78
+ * resident idles before its parking turn. */
79
+ export declare function envUnattendedParkMs(): number | undefined;
70
80
  /** Test-only park-summary grace-period override
71
81
  * (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
72
82
  export declare function envTestParkSummaryGraceMs(): number | undefined;
@@ -40,6 +40,10 @@ export function envNodeCwd() {
40
40
  export function envModelIntent() {
41
41
  return process.env['CRTR_MODEL_INTENT'];
42
42
  }
43
+ /** Whether the launch recipe requires this broker to keep its exact provider/model. */
44
+ export function envModelExact() {
45
+ return process.env['CRTR_MODEL_EXACT'] === '1';
46
+ }
43
47
  /** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
44
48
  * (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
45
49
  * only when a caller needs the override itself — to check whether one is
@@ -140,10 +144,11 @@ export function envDebug() {
140
144
  return process.env['CRTR_DEBUG'] === '1';
141
145
  }
142
146
  // Precedence — broker-supervision.ts's threshold/interval overrides. Each
143
- // returns the raw parsed value with NO default: the caller (config for the
144
- // thresholds, a hardcoded production constant for the intervals) supplies
145
- // the default, and env wins over it when set. Undefined, unparseable, or
146
- // non-positive all mean "no override" — the caller's own default applies.
147
+ // returns the raw parsed value with NO default: the caller supplies the
148
+ // default (user config for the broker thresholds and the unattended-park
149
+ // interval, a hardcoded constant for the test-only park-summary grace), and
150
+ // env wins over it when set. Undefined, unparseable, or non-positive all mean
151
+ // "no override" — the caller's own default applies.
147
152
  function parsePositiveInteger(raw) {
148
153
  if (raw === undefined || raw === '')
149
154
  return undefined;
@@ -171,6 +176,16 @@ function parsePositiveMsNoDefault(raw) {
171
176
  export function envTestUnattendedParkMs() {
172
177
  return parsePositiveMsNoDefault(process.env['CRTR_TEST_UNATTENDED_PARK_MS']);
173
178
  }
179
+ /** Production unattended-park interval override (`CRTR_UNATTENDED_PARK_MS`), in
180
+ * milliseconds; wins over the user-scope config value
181
+ * (`readConfig('user').lifecycle.unattendedParkMs`, itself defaulting to 15
182
+ * min) whenever set, autostart or not. Unlike `CRTR_TEST_UNATTENDED_PARK_MS`
183
+ * this is not gated on `envNoDaemonAutostart()`: it is the env escape hatch
184
+ * above the configured knob a deployment sets to tune how long an eligible
185
+ * resident idles before its parking turn. */
186
+ export function envUnattendedParkMs() {
187
+ return parsePositiveMsNoDefault(process.env['CRTR_UNATTENDED_PARK_MS']);
188
+ }
174
189
  /** Test-only park-summary grace-period override
175
190
  * (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
176
191
  export function envTestParkSummaryGraceMs() {
package/dist/types.d.ts CHANGED
@@ -157,6 +157,14 @@ export interface BrokerThresholdsConfig {
157
157
  /** Defer daemon-initiated revives once the live broker census reaches this count. */
158
158
  automaticReviveCap: number;
159
159
  }
160
+ /** Host-wide node-lifecycle timing. Read only from user scope by crtrd, like
161
+ * `brokerThresholds`: project configuration must not change another user's
162
+ * daemon. */
163
+ export interface LifecycleConfig {
164
+ /** How long an eligible resident idles before its unattended-parking turn
165
+ * begins, in milliseconds. `CRTR_UNATTENDED_PARK_MS` overrides this. */
166
+ unattendedParkMs: number;
167
+ }
160
168
  export type KeybindingOverrides = Record<string, string[]>;
161
169
  /** Compile-time seam for runtime consumers migrating to semantic binding IDs. */
162
170
  export type CanvasAction = {
@@ -189,12 +197,14 @@ export interface ModelLaddersConfig {
189
197
  openai: Record<ModelStrength, string>;
190
198
  }
191
199
  /** A declared provider/model route. Route ids are the keys of `modelRoutes` so
192
- * scopes can override one route without restating the registry. */
200
+ * scopes can override one route without restating the registry. `credentialSource`
201
+ * orders otherwise-equivalent routes; credentials are selected by `providerId`.
202
+ * Effective routes always name every strength. */
193
203
  export interface ModelRouteConfig {
194
204
  family: string;
195
205
  credentialSource: string;
196
206
  providerId: string;
197
- models: Partial<Record<ModelStrength, string>>;
207
+ models: Record<ModelStrength, string>;
198
208
  }
199
209
  export interface ModelRoutingConfig {
200
210
  credentialSourceOrder?: string[];
@@ -249,6 +259,8 @@ export interface ScopeConfig {
249
259
  * Independent attended roots keep their normal viewer behavior. */
250
260
  auto_open_child_viewers: boolean;
251
261
  brokerThresholds: BrokerThresholdsConfig;
262
+ /** Host-wide node-lifecycle timing (user scope only). */
263
+ lifecycle: LifecycleConfig;
252
264
  /** Ring a short completion sound in the attach viewer when the node you are
253
265
  * watching finishes a turn and hands control back (the Claude-Code Stop-hook
254
266
  * ding). Only ever fires inside a live viewer pane — a headless/background
package/dist/types.js CHANGED
@@ -82,6 +82,10 @@ export function defaultScopeConfig() {
82
82
  // sized as a backstop that actually engages before the machine does.
83
83
  // Override per host with CRTR_MAX_LIVE_BROKERS / CRTR_WARN_LIVE_BROKERS.
84
84
  brokerThresholds: { warning: 16, automaticReviveCap: 32 },
85
+ // The unattended-park idle-eligibility delay: how long an eligible resident
86
+ // idles before its parking turn begins. Override per host with
87
+ // CRTR_UNATTENDED_PARK_MS.
88
+ lifecycle: { unattendedParkMs: 15 * 60_000 },
85
89
  completion_bell: true,
86
90
  working_gerunds: [...DEFAULT_WORKING_GERUNDS],
87
91
  whip_mode: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.262",
3
+ "version": "0.3.269",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.262",
3
+ "version": "0.3.269",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.262",
9
+ "version": "0.3.269",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {