@north-light/crouter 0.3.282 → 0.3.284

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 (160) hide show
  1. package/dist/api/client.d.ts +22 -4
  2. package/dist/api/client.js +34 -0
  3. package/dist/api/dto/broker-ops.d.ts +11 -0
  4. package/dist/api/dto/broker.d.ts +3 -8
  5. package/dist/api/dto/common.d.ts +1 -1
  6. package/dist/api/dto/messages.d.ts +2 -2
  7. package/dist/api/dto/node-outcomes.d.ts +80 -0
  8. package/dist/api/dto/node-outcomes.js +2 -0
  9. package/dist/api/dto/nodes.d.ts +9 -0
  10. package/dist/api/dto/profiles.d.ts +5 -0
  11. package/dist/api/dto/reports.d.ts +45 -0
  12. package/dist/api/index.d.ts +1 -0
  13. package/dist/api/index.js +1 -0
  14. package/dist/api/routes.d.ts +7 -0
  15. package/dist/api/routes.js +7 -0
  16. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +24 -3
  17. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +31 -4
  18. package/dist/clients/attach/overlays/graph.d.ts +5 -0
  19. package/dist/clients/attach/overlays/graph.js +65 -47
  20. package/dist/clients/attach/overlays/pickers.js +8 -9
  21. package/dist/clients/attach/render/card-presentation.js +1 -1
  22. package/dist/clients/attach/viewer.js +1286 -1260
  23. package/dist/commands/api-client.js +22 -23
  24. package/dist/commands/node/create.js +38 -3
  25. package/dist/commands/node/inspect.js +3 -7
  26. package/dist/commands/node/message.js +3 -3
  27. package/dist/commands/node/outcome.d.ts +2 -0
  28. package/dist/commands/node/outcome.js +134 -0
  29. package/dist/commands/node.js +2 -1
  30. package/dist/commands/profile/pause.js +17 -14
  31. package/dist/commands/push.js +102 -1
  32. package/dist/commands/sys/__tests__/setup-core.test.js +4 -1
  33. package/dist/commands/sys/panels/broker-limits-panel.js +7 -1
  34. package/dist/commands/sys/panels/models-panel.js +2 -2
  35. package/dist/commands/sys/settings-shell.d.ts +1 -1
  36. package/dist/commands/sys/settings-shell.js +6 -0
  37. package/dist/commands/sys/settings.js +3 -3
  38. package/dist/core/__tests__/fixtures/fake-engine.d.ts +2 -0
  39. package/dist/core/__tests__/fixtures/fake-engine.js +42 -4
  40. package/dist/core/__tests__/helpers/harness.d.ts +1 -0
  41. package/dist/core/__tests__/helpers/harness.js +9 -0
  42. package/dist/core/__tests__/integration/profile-pause.test.d.ts +1 -0
  43. package/dist/core/__tests__/integration/profile-pause.test.js +115 -0
  44. package/dist/core/__tests__/node-outcome.test.d.ts +1 -0
  45. package/dist/core/__tests__/node-outcome.test.js +184 -0
  46. package/dist/core/__tests__/revive-parked-fresh.test.js +13 -20
  47. package/dist/core/__tests__/seam/broker-provider-retry.test.js +6 -2
  48. package/dist/core/__tests__/seam/dormancy-release.test.js +3 -3
  49. package/dist/core/__tests__/seam/node-outcome-delivery.test.d.ts +1 -0
  50. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +153 -0
  51. package/dist/core/bash-jobs.d.ts +6 -0
  52. package/dist/core/bash-jobs.js +22 -0
  53. package/dist/core/canvas/canvas.d.ts +41 -3
  54. package/dist/core/canvas/canvas.js +153 -39
  55. package/dist/core/canvas/crons.js +2 -1
  56. package/dist/core/canvas/index.d.ts +1 -0
  57. package/dist/core/canvas/index.js +1 -0
  58. package/dist/core/canvas/migrations.js +47 -0
  59. package/dist/core/canvas/node-outcome-deliveries.d.ts +80 -0
  60. package/dist/core/canvas/node-outcome-deliveries.js +163 -0
  61. package/dist/core/canvas/pid.d.ts +7 -0
  62. package/dist/core/canvas/pid.js +17 -0
  63. package/dist/core/canvas/render-source.js +2 -2
  64. package/dist/core/canvas/types.d.ts +42 -1
  65. package/dist/core/canvas/types.js +2 -1
  66. package/dist/core/config.d.ts +4 -1
  67. package/dist/core/config.js +25 -1
  68. package/dist/core/feed/feed.d.ts +8 -0
  69. package/dist/core/feed/feed.js +25 -4
  70. package/dist/core/feed/inbox.d.ts +5 -0
  71. package/dist/core/feed/inbox.js +13 -0
  72. package/dist/core/keybindings/catalog.d.ts +1 -1
  73. package/dist/core/keybindings/catalog.js +3 -0
  74. package/dist/core/profiles/manifest.d.ts +3 -1
  75. package/dist/core/profiles/manifest.js +6 -1
  76. package/dist/core/runtime/broker/daemon-ops.d.ts +3 -1
  77. package/dist/core/runtime/broker/daemon-ops.js +6 -0
  78. package/dist/core/runtime/broker/engine-drive.d.ts +2 -3
  79. package/dist/core/runtime/broker/engine-drive.js +74 -27
  80. package/dist/core/runtime/broker/frame-dispatch.js +1 -0
  81. package/dist/core/runtime/broker/read-ops.js +14 -0
  82. package/dist/core/runtime/broker/rebind.js +0 -7
  83. package/dist/core/runtime/broker-protocol.d.ts +1 -6
  84. package/dist/core/runtime/fleet.d.ts +7 -0
  85. package/dist/core/runtime/headless-pi.d.ts +13 -0
  86. package/dist/core/runtime/headless-pi.js +10 -2
  87. package/dist/core/runtime/lifecycle.d.ts +6 -1
  88. package/dist/core/runtime/lifecycle.js +50 -1
  89. package/dist/core/runtime/nodes.d.ts +5 -1
  90. package/dist/core/runtime/nodes.js +2 -1
  91. package/dist/core/runtime/outcome-document.d.ts +70 -0
  92. package/dist/core/runtime/outcome-document.js +97 -0
  93. package/dist/core/runtime/revive.js +16 -21
  94. package/dist/core/runtime/spawn.d.ts +5 -1
  95. package/dist/core/runtime/spawn.js +18 -7
  96. package/dist/core/runtime/stamp/channel.d.ts +3 -5
  97. package/dist/core/runtime/stamp/channel.js +3 -10
  98. package/dist/core/runtime/stop-guard.js +2 -2
  99. package/dist/core/runtime/structured-output.d.ts +24 -3
  100. package/dist/core/runtime/structured-output.js +42 -3
  101. package/dist/core/runtime/tmux-bindings.js +4 -0
  102. package/dist/core/runtime/warm-pool.d.ts +5 -2
  103. package/dist/core/runtime/warm-pool.js +5 -5
  104. package/dist/core/subscription-state.js +7 -5
  105. package/dist/core/substrate/render.js +10 -10
  106. package/dist/core/user-settings.d.ts +18 -1
  107. package/dist/core/user-settings.js +37 -0
  108. package/dist/daemon/__tests__/node-deadline-lane.test.d.ts +1 -0
  109. package/dist/daemon/__tests__/node-deadline-lane.test.js +76 -0
  110. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.d.ts +1 -0
  111. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +122 -0
  112. package/dist/daemon/__tests__/node-outcome-delivery.test.d.ts +1 -0
  113. package/dist/daemon/__tests__/node-outcome-delivery.test.js +86 -0
  114. package/dist/daemon/api/__tests__/broker-settle-park.test.js +86 -18
  115. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +10 -1
  116. package/dist/daemon/api/__tests__/seam/node-outcome-api.test.d.ts +1 -0
  117. package/dist/daemon/api/__tests__/seam/node-outcome-api.test.js +159 -0
  118. package/dist/daemon/api/__tests__/submit-result.test.d.ts +1 -0
  119. package/dist/daemon/api/__tests__/submit-result.test.js +214 -0
  120. package/dist/daemon/api/handlers/broker-ops.js +53 -24
  121. package/dist/daemon/api/handlers/canvas.js +2 -2
  122. package/dist/daemon/api/handlers/messages.js +12 -2
  123. package/dist/daemon/api/handlers/node-outcomes.d.ts +2 -0
  124. package/dist/daemon/api/handlers/node-outcomes.js +136 -0
  125. package/dist/daemon/api/handlers/nodes.js +67 -1
  126. package/dist/daemon/api/handlers/profiles.js +53 -1
  127. package/dist/daemon/api/handlers/reports.js +197 -33
  128. package/dist/daemon/api/map.d.ts +7 -2
  129. package/dist/daemon/api/map.js +78 -4
  130. package/dist/daemon/api/server.js +74 -7
  131. package/dist/daemon/crtrd.js +12 -0
  132. package/dist/daemon/fleet.d.ts +4 -8
  133. package/dist/daemon/fleet.js +48 -9
  134. package/dist/daemon/messaging/node-message.js +2 -1
  135. package/dist/daemon/node-outcome/deliver-outcome.d.ts +14 -0
  136. package/dist/daemon/node-outcome/deliver-outcome.js +155 -0
  137. package/dist/daemon/park-activity.d.ts +9 -0
  138. package/dist/daemon/park-activity.js +30 -0
  139. package/dist/daemon/park-pending.d.ts +10 -5
  140. package/dist/daemon/park-pending.js +18 -8
  141. package/dist/daemon/reconcilers/bash-deadline.js +6 -0
  142. package/dist/daemon/reconcilers/broker-supervision.d.ts +3 -7
  143. package/dist/daemon/reconcilers/broker-supervision.js +29 -33
  144. package/dist/daemon/reconcilers/node-deadline.d.ts +5 -0
  145. package/dist/daemon/reconcilers/node-deadline.js +82 -0
  146. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +9 -1
  147. package/dist/daemon/reconcilers/node-lifecycle/tick.js +12 -3
  148. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +10 -0
  149. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +41 -0
  150. package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +66 -66
  151. package/dist/pi-extensions/canvas-structured-output.d.ts +9 -5
  152. package/dist/pi-extensions/canvas-structured-output.js +23 -297
  153. package/dist/shared/env.d.ts +8 -0
  154. package/dist/shared/env.js +14 -0
  155. package/dist/shared/generated-context.d.ts +3 -9
  156. package/dist/shared/generated-context.js +8 -16
  157. package/dist/types.d.ts +12 -0
  158. package/dist/types.js +1 -0
  159. package/package.json +9 -8
  160. package/runtime.lock.json +227 -383
@@ -205,24 +205,15 @@ export class GraphOverlay {
205
205
  }
206
206
  async buildSnapshot() {
207
207
  beginFrameTelem();
208
- const nodes = new Map();
208
+ const [listed, focused] = await Promise.all([
209
+ this.source.listNodes().catch(() => []),
210
+ this.fetchFocused(),
211
+ ]);
212
+ const nodes = new Map(listed.map((node) => [node.node_id, node]));
209
213
  const childIds = new Map();
210
214
  const sortedChildIds = new Map();
211
215
  const managerOf = new Map();
212
216
  const activeBelow = new Map();
213
- const node = async (id) => {
214
- if (nodes.has(id))
215
- return nodes.get(id) ?? null;
216
- let v;
217
- try {
218
- v = await this.source.getNode(id);
219
- }
220
- catch {
221
- v = null;
222
- }
223
- nodes.set(id, v);
224
- return v;
225
- };
226
217
  const children = async (id) => {
227
218
  const hit = childIds.get(id);
228
219
  if (hit !== undefined)
@@ -234,11 +225,9 @@ export class GraphOverlay {
234
225
  catch {
235
226
  refs = [];
236
227
  }
237
- const out = [];
238
- for (const ref of refs) {
239
- if ((await node(ref.node_id))?.kind !== 'human')
240
- out.push(ref.node_id);
241
- }
228
+ const out = refs
229
+ .map((ref) => ref.node_id)
230
+ .filter((childId) => nodes.get(childId)?.kind !== 'human');
242
231
  childIds.set(id, out);
243
232
  return out;
244
233
  };
@@ -255,8 +244,8 @@ export class GraphOverlay {
255
244
  managerOf.set(id, mgr);
256
245
  return mgr;
257
246
  };
258
- const climbRoot = async (self) => {
259
- let cur = self;
247
+ const climbRoot = async () => {
248
+ let cur = this.self;
260
249
  const seen = new Set([cur]);
261
250
  for (;;) {
262
251
  const mgr = await manager(cur);
@@ -267,60 +256,89 @@ export class GraphOverlay {
267
256
  }
268
257
  return cur;
269
258
  };
270
- const rank = async (id) => statusRank((await node(id))?.status);
271
259
  const sortedChildren = async (id) => {
272
260
  const cached = sortedChildIds.get(id);
273
261
  if (cached !== undefined)
274
262
  return cached;
275
263
  const ids = [...await children(id)];
276
- const ranks = new Map();
277
- await Promise.all(ids.map(async (cid) => { ranks.set(cid, await rank(cid)); }));
278
- ids.sort((a, b) => (ranks.get(a) ?? 99) - (ranks.get(b) ?? 99));
264
+ ids.sort((a, b) => statusRank(nodes.get(a)?.status) - statusRank(nodes.get(b)?.status));
279
265
  sortedChildIds.set(id, ids);
280
266
  return ids;
281
267
  };
282
- const expand = new Set();
268
+ const autoExpanded = new Set();
283
269
  const seenActivity = new Set();
284
270
  const visitActivity = async (id) => {
285
- const selfActive = (await node(id))?.status === 'active';
271
+ const selfActive = nodes.get(id)?.status === 'active';
286
272
  if (seenActivity.has(id))
287
273
  return { active: selfActive ? 1 : 0, reveal: selfActive || id === this.self };
288
274
  seenActivity.add(id);
289
275
  let below = 0;
290
276
  let childReveal = false;
291
- for (const c of await children(id)) {
292
- const r = await visitActivity(c);
293
- below += r.active;
294
- if (r.reveal)
277
+ for (const childId of await children(id)) {
278
+ const result = await visitActivity(childId);
279
+ below += result.active;
280
+ if (result.reveal)
295
281
  childReveal = true;
296
282
  }
297
283
  activeBelow.set(id, below);
298
284
  if (childReveal)
299
- expand.add(id);
285
+ autoExpanded.add(id);
300
286
  return { active: below + (selfActive ? 1 : 0), reveal: childReveal || selfActive || id === this.self };
301
287
  };
302
- await visitActivity(await climbRoot(this.self));
288
+ const root = await climbRoot();
289
+ await visitActivity(root);
290
+ await Promise.all([...childIds.keys()].map((id) => sortedChildren(id)));
291
+ const snapshot = {
292
+ root,
293
+ rows: [],
294
+ autoExpanded,
295
+ activeBelow,
296
+ nodes,
297
+ childIds,
298
+ sortedChildIds,
299
+ managerOf,
300
+ focused,
301
+ };
302
+ snapshot.rows = this.projectRows(snapshot);
303
+ return snapshot;
304
+ }
305
+ /** Fold state is presentation-only. Reproject the visible DFS from the fully
306
+ * fetched topology so h/l never cross the daemon boundary. The explicit stack
307
+ * also keeps a deep graph from consuming the JavaScript call stack. */
308
+ projectRows(snapshot) {
303
309
  const rows = [];
304
310
  const visited = new Set();
305
- const walk = async (id, prefix, isRoot, isLast) => {
311
+ const stack = [
312
+ { id: snapshot.root, prefix: '', isRoot: true, isLast: true },
313
+ ];
314
+ while (stack.length > 0) {
315
+ const { id, prefix, isRoot, isLast } = stack.pop();
316
+ const connector = isRoot ? '' : isLast ? '└─ ' : '├─ ';
306
317
  if (visited.has(id)) {
307
- const connector = isRoot ? '' : isLast ? '└─ ' : '├─ ';
308
318
  rows.push({ id, hasKids: false, isSelf: id === this.self, branch: prefix + connector, cycle: true, collapsed: false });
309
- return;
319
+ continue;
310
320
  }
311
321
  visited.add(id);
312
- const kids = await sortedChildren(id);
313
- const folded = this.folds.userExpanded.has(id) ? false : this.folds.userCollapsed.has(id) ? true : !expand.has(id);
314
- const connector = isRoot ? '' : isLast ? '└─ ' : '├─ ';
322
+ const kids = snapshot.sortedChildIds.get(id) ?? [];
323
+ const folded = this.folds.userExpanded.has(id)
324
+ ? false
325
+ : this.folds.userCollapsed.has(id)
326
+ ? true
327
+ : !snapshot.autoExpanded.has(id);
315
328
  rows.push({ id, hasKids: kids.length > 0, isSelf: id === this.self, branch: prefix + connector, cycle: false, collapsed: folded });
316
329
  if (folded)
317
- return;
330
+ continue;
318
331
  const childPrefix = isRoot ? '' : prefix + (isLast ? ' ' : '│ ');
319
- for (let i = 0; i < kids.length; i++)
320
- await walk(kids[i], childPrefix, false, i === kids.length - 1);
321
- };
322
- await walk(await climbRoot(this.self), '', true, true);
323
- return { rows, activeBelow, nodes, childIds, sortedChildIds, managerOf, focused: await this.fetchFocused() };
332
+ for (let i = kids.length - 1; i >= 0; i--) {
333
+ stack.push({ id: kids[i], prefix: childPrefix, isRoot: false, isLast: i === kids.length - 1 });
334
+ }
335
+ }
336
+ return rows;
337
+ }
338
+ repaintFolds() {
339
+ if (this.snapshot !== undefined)
340
+ this.snapshot.rows = this.projectRows(this.snapshot);
341
+ this.tui.requestRender();
324
342
  }
325
343
  renderSnapshotRow(snapshot, r, isCursor, asks) {
326
344
  const wrap = (line, attached) => isCursor ? fillBar(line, fillWidth(), REVERSE)
@@ -523,7 +541,7 @@ export class GraphOverlay {
523
541
  if (cur !== undefined && cur.hasKids && !cur.collapsed) {
524
542
  this.userCollapsed.add(cur.id);
525
543
  this.userExpanded.delete(cur.id);
526
- this.refresh();
544
+ this.repaintFolds();
527
545
  }
528
546
  else {
529
547
  const p = snapshot?.managerOf.get(this.cursorId ?? this.self);
@@ -537,7 +555,7 @@ export class GraphOverlay {
537
555
  if (cur !== undefined && cur.collapsed && cur.hasKids) {
538
556
  this.userExpanded.add(cur.id);
539
557
  this.userCollapsed.delete(cur.id);
540
- this.refresh();
558
+ this.repaintFolds();
541
559
  }
542
560
  else if (cur !== undefined && cur.hasKids) {
543
561
  const c = snapshot?.sortedChildIds.get(cur.id)?.[0];
@@ -14,20 +14,19 @@
14
14
  //
15
15
  // R1 (contract): the tree/fork/settings payloads are PURE DATA — their selectors
16
16
  // build verbatim, no reconstruction. The MODEL picker's `ModelSelectorComponent`
17
- // needs a live `ModelRuntime`/`SettingsManager`: we feed the REAL component a
18
- // minimal in-memory `SettingsManager` plus a tiny `ModelRuntime` adapter (the
19
- // component calls only getAvailableSnapshot/getModel/getError/refresh — verified
20
- // against model-selector.js), preserving its full search + scope-toggle UI without
21
- // crossing engine state over the socket. The SESSION picker reconstructs
17
+ // needs a live `ModelRuntime`: we feed the REAL component a tiny `ModelRuntime`
18
+ // adapter (the component calls only getAvailableSnapshot/getModel/getError —
19
+ // verified against model-selector.js), preserving its full search + scope-toggle
20
+ // UI without crossing engine state over the socket. The SESSION picker reconstructs
22
21
  // faithfully from async loaders (no shim). The SCOPED-MODELS component is NOT
23
22
  // re-exported by pi (through 0.79.1) AND has no mutation frame in the contract,
24
23
  // so it renders read-only via a pi-tui SelectList.
25
24
  //
26
- // The duck-typed runtime adapter relies on the component's current 4-method
27
- // ModelRuntime surface — a future pi adding a runtime call there would surface at
25
+ // The duck-typed runtime adapter relies on the component's current ModelRuntime
26
+ // surface — a future pi adding a runtime call there would surface at
28
27
  // runtime (caught by live verification).
29
28
  import { Container, SelectList, SettingsList, } from '@earendil-works/pi-tui';
30
- import { DynamicBorder, getSelectListTheme, getSettingsListTheme, ModelSelectorComponent, SessionSelectorComponent, TreeSelectorComponent, UserMessageSelectorComponent, SettingsManager, } from '@earendil-works/pi-coding-agent';
29
+ import { DynamicBorder, getSelectListTheme, getSettingsListTheme, ModelSelectorComponent, SessionSelectorComponent, TreeSelectorComponent, UserMessageSelectorComponent, } from '@earendil-works/pi-coding-agent';
31
30
  /** A minimal `ModelRuntime` for `ModelSelectorComponent`: the component calls
32
31
  * only `getAvailableSnapshot()`, `getModel()`, `getError()`, and `refresh()`
33
32
  * (verified against pi `model-selector.js`). We satisfy exactly those from the
@@ -62,7 +61,7 @@ export function buildModelPicker(tui, data, send, close) {
62
61
  const current = data.current
63
62
  ? all.find((m) => m.provider === data.current.provider && m.id === data.current.id)
64
63
  : undefined;
65
- const component = new ModelSelectorComponent(tui, current, SettingsManager.inMemory(), modelRuntimeAdapter(all, available), data.scopedModels, (model) => {
64
+ const component = new ModelSelectorComponent(tui, current, modelRuntimeAdapter(all, available), data.scopedModels, (model) => {
66
65
  send({ type: 'set_model', model: `${model.provider}/${model.id}` });
67
66
  close();
68
67
  }, () => close());
@@ -102,7 +102,7 @@ function reviewCommentSummary(card) {
102
102
  }
103
103
  /** Both structured-output reprompts open this way (core/runtime/stop-guard.ts);
104
104
  * the stall reprompt does not. */
105
- const STRUCTURED_OUTPUT_REPROMPT = /^(?:You must call the `submit` tool|Structured-output request file is invalid)/;
105
+ const STRUCTURED_OUTPUT_REPROMPT = /^(?:You must submit a result|Structured-output request file is invalid)/;
106
106
  function stopGuardSummary(card) {
107
107
  return STRUCTURED_OUTPUT_REPROMPT.test(card.body) ? 'structured output required' : 'completion required';
108
108
  }