@north-light/crouter 0.3.249 → 0.3.251

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 (175) hide show
  1. package/README.md +1 -1
  2. package/dist/api/__tests__/integration/client.test.js +28 -7
  3. package/dist/api/client.d.ts +1 -1
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/lifecycle.d.ts +3 -0
  6. package/dist/api/dto/messages.d.ts +4 -0
  7. package/dist/api/dto/nodes.d.ts +4 -0
  8. package/dist/api/dto/reports.d.ts +7 -2
  9. package/dist/builtin-memory/00-runtime-base/01-escalation.md +1 -1
  10. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +3 -0
  11. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  12. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +0 -1
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +4 -3
  14. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +4 -3
  15. package/dist/clients/attach/session/chrome-refresh.d.ts +3 -0
  16. package/dist/clients/attach/session/chrome-refresh.js +1 -0
  17. package/dist/clients/attach/viewer.js +532 -532
  18. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.d.ts +1 -0
  19. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +53 -0
  20. package/dist/clients/inbox/controller.js +32 -5
  21. package/dist/clients/inbox/tui/ansi.d.ts +3 -1
  22. package/dist/clients/inbox/tui/ansi.js +14 -10
  23. package/dist/commands/__tests__/api-client-cold-start-diagnostic.test.js +7 -7
  24. package/dist/commands/api-client.d.ts +2 -2
  25. package/dist/commands/api-client.js +5 -5
  26. package/dist/commands/canvas-browse.js +1 -1
  27. package/dist/commands/node/create.js +3 -1
  28. package/dist/commands/node/inspect.js +1 -0
  29. package/dist/commands/node/lifecycle.js +1 -1
  30. package/dist/commands/node/message.js +6 -4
  31. package/dist/commands/node/wait.js +1 -1
  32. package/dist/commands/push.js +36 -37
  33. package/dist/commands/sys/daemon.js +21 -8
  34. package/dist/commands/sys/setup-core.js +2 -2
  35. package/dist/core/__tests__/broker-stream-watchdog-floor.test.d.ts +1 -0
  36. package/dist/core/__tests__/broker-stream-watchdog-floor.test.js +84 -0
  37. package/dist/core/__tests__/broker-turn-admission.test.d.ts +1 -0
  38. package/dist/core/__tests__/broker-turn-admission.test.js +44 -0
  39. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +100 -1
  40. package/dist/core/__tests__/child-death-wake.test.js +11 -7
  41. package/dist/core/__tests__/collectible.test.d.ts +1 -0
  42. package/dist/core/__tests__/collectible.test.js +88 -0
  43. package/dist/core/__tests__/context-intro.test.js +4 -41
  44. package/dist/core/__tests__/daemon-boot.test.js +30 -14
  45. package/dist/core/__tests__/daemon-wedge.test.js +25 -19
  46. package/dist/core/__tests__/fixtures/fake-engine.js +20 -2
  47. package/dist/core/__tests__/human-deliver.test.js +5 -5
  48. package/dist/core/__tests__/integration/deferred-no-wake.test.js +65 -4
  49. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +3 -3
  50. package/dist/core/__tests__/integration/revive.test.js +48 -0
  51. package/dist/core/__tests__/integration/spawn-root.test.js +36 -1
  52. package/dist/core/__tests__/integration/worktree-land.test.js +82 -3
  53. package/dist/core/__tests__/integration/worktree-reap.test.js +44 -6
  54. package/dist/core/__tests__/migration.test.js +30 -0
  55. package/dist/core/__tests__/passive-subscription.test.js +39 -1
  56. package/dist/core/__tests__/prune.test.js +12 -3
  57. package/dist/core/__tests__/relaunch-root.test.js +1 -1
  58. package/dist/core/__tests__/respawn-throttle.test.js +16 -146
  59. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +23 -11
  60. package/dist/core/__tests__/seam/broker-provider-retry.test.js +81 -2
  61. package/dist/core/__tests__/seam/dormancy-release.test.js +1 -1
  62. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.d.ts +1 -0
  63. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +63 -0
  64. package/dist/core/__tests__/seam/self-close-teardown.test.d.ts +1 -0
  65. package/dist/core/__tests__/seam/self-close-teardown.test.js +49 -0
  66. package/dist/core/__tests__/seam/yield-refresh-transaction.test.js +18 -10
  67. package/dist/core/canvas/canvas.d.ts +9 -15
  68. package/dist/core/canvas/canvas.js +41 -47
  69. package/dist/core/canvas/crons.d.ts +5 -8
  70. package/dist/core/canvas/crons.js +5 -8
  71. package/dist/core/canvas/history.d.ts +5 -0
  72. package/dist/core/canvas/history.js +12 -1
  73. package/dist/core/canvas/migrations.js +58 -1
  74. package/dist/core/canvas/pid.d.ts +1 -1
  75. package/dist/core/canvas/pid.js +5 -2
  76. package/dist/core/canvas/types.d.ts +4 -0
  77. package/dist/core/feed/feed.d.ts +4 -0
  78. package/dist/core/feed/feed.js +13 -8
  79. package/dist/core/feed/inbox.d.ts +2 -1
  80. package/dist/core/feed/inbox.js +22 -3
  81. package/dist/core/git.d.ts +3 -0
  82. package/dist/core/git.js +3 -1
  83. package/dist/core/human/feedback-companion.js +1 -0
  84. package/dist/core/preview-registry.js +0 -1
  85. package/dist/core/review/companion.js +1 -0
  86. package/dist/core/review/realize.js +1 -0
  87. package/dist/core/runtime/broker/auth-reload.d.ts +2 -0
  88. package/dist/core/runtime/broker/auth-reload.js +9 -3
  89. package/dist/core/runtime/broker/engine-drive.d.ts +2 -0
  90. package/dist/core/runtime/broker/engine-drive.js +39 -23
  91. package/dist/core/runtime/broker/event-projection.d.ts +4 -0
  92. package/dist/core/runtime/broker/event-projection.js +43 -23
  93. package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
  94. package/dist/core/runtime/broker/fault-retry.js +94 -8
  95. package/dist/core/runtime/broker/frame-dispatch.d.ts +2 -0
  96. package/dist/core/runtime/broker/frame-dispatch.js +4 -1
  97. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +9 -0
  98. package/dist/core/runtime/broker/held-deferred-inbox.js +8 -0
  99. package/dist/core/runtime/broker/inbox.js +4 -0
  100. package/dist/core/runtime/broker/rebind.js +18 -0
  101. package/dist/core/runtime/broker/turn-admission.d.ts +11 -0
  102. package/dist/core/runtime/broker/turn-admission.js +31 -0
  103. package/dist/core/runtime/broker/turn-ignition.d.ts +2 -0
  104. package/dist/core/runtime/broker/turn-ignition.js +25 -15
  105. package/dist/core/runtime/broker.js +21 -2
  106. package/dist/core/runtime/close.d.ts +11 -9
  107. package/dist/core/runtime/close.js +23 -19
  108. package/dist/core/runtime/fault.d.ts +21 -0
  109. package/dist/core/runtime/fault.js +129 -19
  110. package/dist/core/runtime/fleet.d.ts +0 -6
  111. package/dist/core/runtime/host.d.ts +7 -1
  112. package/dist/core/runtime/host.js +20 -2
  113. package/dist/core/runtime/nodes.d.ts +5 -1
  114. package/dist/core/runtime/nodes.js +24 -1
  115. package/dist/core/runtime/placement.d.ts +6 -6
  116. package/dist/core/runtime/placement.js +15 -8
  117. package/dist/core/runtime/reset.js +2 -2
  118. package/dist/core/runtime/revive.js +40 -4
  119. package/dist/core/runtime/spawn.d.ts +3 -0
  120. package/dist/core/runtime/spawn.js +1 -0
  121. package/dist/core/runtime/warm-pool.d.ts +4 -0
  122. package/dist/core/runtime/warm-pool.js +2 -0
  123. package/dist/core/worktree.d.ts +4 -3
  124. package/dist/core/worktree.js +73 -27
  125. package/dist/daemon/__tests__/integration/api-startup-readiness.test.d.ts +1 -0
  126. package/dist/daemon/__tests__/integration/api-startup-readiness.test.js +81 -0
  127. package/dist/daemon/api/__tests__/reopen-delivery.test.js +38 -0
  128. package/dist/daemon/api/__tests__/seam/api-server.test.js +1 -0
  129. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +13 -2
  130. package/dist/daemon/api/handlers/bash-jobs.js +2 -0
  131. package/dist/daemon/api/handlers/broker-ops.js +23 -2
  132. package/dist/daemon/api/handlers/human.js +1 -1
  133. package/dist/daemon/api/handlers/messages.js +11 -2
  134. package/dist/daemon/api/handlers/nodes.js +13 -1
  135. package/dist/daemon/api/handlers/reports.js +14 -6
  136. package/dist/daemon/api/map.js +1 -0
  137. package/dist/daemon/api/server.d.ts +9 -12
  138. package/dist/daemon/api/server.js +30 -19
  139. package/dist/daemon/companion-retire.js +3 -9
  140. package/dist/daemon/cron/sinks.js +7 -2
  141. package/dist/daemon/crtrd.js +4 -1
  142. package/dist/daemon/fleet.d.ts +2 -16
  143. package/dist/daemon/fleet.js +63 -150
  144. package/dist/daemon/human/finish.js +2 -0
  145. package/dist/daemon/manage.d.ts +11 -0
  146. package/dist/daemon/manage.js +32 -3
  147. package/dist/daemon/messaging/node-message.js +7 -1
  148. package/dist/daemon/reconcilers/bash-deadline.js +2 -0
  149. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -0
  150. package/dist/daemon/reconcilers/broker-supervision.js +22 -9
  151. package/dist/daemon/reconcilers/live-obligation.d.ts +16 -6
  152. package/dist/daemon/reconcilers/live-obligation.js +18 -6
  153. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +15 -4
  154. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +34 -3
  155. package/dist/daemon/reconcilers/node-lifecycle/terminating.d.ts +4 -1
  156. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +11 -2
  157. package/dist/daemon/reconcilers/node-lifecycle/tick.js +14 -7
  158. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -2
  159. package/dist/daemon/reconcilers/storage-maintenance.js +3 -3
  160. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
  161. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -34
  162. package/dist/pi-extensions/canvas-context-intro.js +4 -76
  163. package/dist/pi-extensions/canvas-inbox-watcher.js +105 -4
  164. package/dist/pi-extensions/canvas-review-boundary.d.ts +3 -24
  165. package/dist/pi-extensions/canvas-review-boundary.js +4 -29
  166. package/dist/pi-extensions/canvas-stophook.js +1 -6
  167. package/dist/shared/birth-announcement.d.ts +12 -0
  168. package/dist/shared/birth-announcement.js +25 -0
  169. package/dist/shared/generated-context.d.ts +8 -4
  170. package/dist/shared/generated-context.js +15 -9
  171. package/package.json +4 -4
  172. package/runtime.lock.json +2 -2
  173. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +0 -254
  174. package/dist/pi-extensions/truncate.d.ts +0 -5
  175. package/dist/pi-extensions/truncate.js +0 -14
@@ -1,254 +0,0 @@
1
- /**
2
- * Statusline + session-name badge.
3
- *
4
- * Footer (statusline): <model> [· subscription] · <tokens used> · <cycle>, with
5
- * <cwd last dir> (<git>) right-aligned on the far right.
6
- * Input bar border: session name rendered as a solid-background badge,
7
- * shown only when a name is set (via /name or
8
- * pi.setSessionName()).
9
- *
10
- * This extension owns only the statusline and session-name badge. Canvas
11
- * navigation and interactive chrome live in crouter's attach viewer.
12
- */
13
-
14
- import { execFile } from 'node:child_process';
15
- import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
16
- import { CustomEditor, type ExtensionContext } from '@earendil-works/pi-coding-agent';
17
- import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
18
-
19
- function lastDir(cwd: string): string {
20
- const trimmed = cwd.replace(/\/+$/, "");
21
- const base = trimmed.split("/").pop();
22
- return base && base.length > 0 ? base : "/";
23
- }
24
-
25
- function fmtTokens(n: number): string {
26
- return n < 1000 ? `${n}` : `${Math.round(n / 1000)}k`;
27
- }
28
-
29
- interface GitStatus {
30
- staged: number;
31
- modified: number;
32
- untracked: number;
33
- conflicts: number;
34
- ahead: number;
35
- behind: number;
36
- stashed: number;
37
- }
38
-
39
- /** Run `git status --porcelain=v1 --branch` and parse a summary. */
40
- function loadGitStatus(cwd: string): Promise<GitStatus | null> {
41
- return new Promise((resolve) => {
42
- execFile(
43
- "git",
44
- ["status", "--porcelain=v1", "--branch", "--untracked-files=all"],
45
- { cwd, timeout: 2000, windowsHide: true },
46
- (err, stdout) => {
47
- if (err) return resolve(null);
48
- const s: GitStatus = {
49
- staged: 0,
50
- modified: 0,
51
- untracked: 0,
52
- conflicts: 0,
53
- ahead: 0,
54
- behind: 0,
55
- stashed: 0,
56
- };
57
- for (const line of stdout.split("\n")) {
58
- if (line.startsWith("## ")) {
59
- const ahead = line.match(/ahead (\d+)/);
60
- const behind = line.match(/behind (\d+)/);
61
- if (ahead) s.ahead = Number(ahead[1]);
62
- if (behind) s.behind = Number(behind[1]);
63
- continue;
64
- }
65
- if (line.length < 2) continue;
66
- const x = line[0];
67
- const y = line[1];
68
- if (x === "?" && y === "?") {
69
- s.untracked++;
70
- } else if (x === "U" || y === "U" || (x === "A" && y === "A") || (x === "D" && y === "D")) {
71
- s.conflicts++;
72
- } else {
73
- if (x !== " " && x !== "?") s.staged++;
74
- if (y !== " " && y !== "?") s.modified++;
75
- }
76
- }
77
- resolve(s);
78
- },
79
- );
80
- });
81
- }
82
-
83
- /** Render git status using standard prompt symbols. */
84
- function fmtGitStatus(s: GitStatus | null): string {
85
- if (!s) return "";
86
- const parts: string[] = [];
87
- if (s.ahead) parts.push(`⇡${s.ahead}`); // ⇡ ahead
88
- if (s.behind) parts.push(`⇣${s.behind}`); // ⇣ behind
89
- if (s.conflicts) parts.push(`×${s.conflicts}`); // × conflicts
90
- if (s.staged) parts.push(`+${s.staged}`); // + staged
91
- if (s.modified) parts.push(`!${s.modified}`); // ! modified
92
- if (s.untracked) parts.push(`?${s.untracked}`); // ? untracked
93
- if (s.stashed) parts.push(`$${s.stashed}`); // $ stashed
94
- if (parts.length === 0) return "✓"; // ✓ clean
95
- return parts.join(" ");
96
- }
97
-
98
- function formatTokens(ctx: Pick<ExtensionContext, "getContextUsage">): string {
99
- const usage = ctx.getContextUsage();
100
- if (!usage || usage.tokens == null) return "0 tokens";
101
- return `${fmtTokens(usage.tokens)} tokens`;
102
- }
103
-
104
- interface FooterDataLike {
105
- // pi's provider reports "no branch" as null; keep undefined too so tests can pass a
106
- // bare stub.
107
- getGitBranch(): string | null | undefined;
108
- getExtensionStatuses(): ReadonlyMap<string, string>;
109
- }
110
-
111
- export function buildStatuslineFooterLine(
112
- width: number,
113
- ctx: Pick<ExtensionContext, "cwd" | "model" | "getContextUsage">,
114
- footerData: FooterDataLike,
115
- gitStatus: GitStatus | null,
116
- ): string {
117
- if (width <= 0) return "";
118
-
119
- const cwd = lastDir(ctx.cwd);
120
- const branch = footerData.getGitBranch();
121
- const status = fmtGitStatus(gitStatus);
122
- const gitStr = branch
123
- ? status
124
- ? `${branch} ${status}`
125
- : branch
126
- : "";
127
- const cwdStr = gitStr ? `${cwd} (${gitStr})` : cwd;
128
-
129
- const model = ctx.model?.id ?? "no model";
130
- const subscription = footerData.getExtensionStatuses().get("provider-rotation")?.trim() ?? "";
131
- const tokens = formatTokens(ctx);
132
- const cyclesEnv = process.env["CRTR_CYCLES"]?.trim();
133
- const cycleCount = cyclesEnv ? Number.parseInt(cyclesEnv, 10) : Number.NaN;
134
- const cycle = Number.isFinite(cycleCount) ? `↻${cycleCount}` : "";
135
-
136
- const leftParts = [model];
137
- if (subscription !== "") leftParts.push(subscription);
138
- leftParts.push(tokens);
139
- if (cycle !== "") leftParts.push(cycle);
140
- const leftRaw = leftParts.join(" · ");
141
- let rightRaw = cwdStr;
142
-
143
- let rightWidth = visibleWidth(rightRaw);
144
- if (rightWidth > width) {
145
- const cwdWidth = visibleWidth(cwd);
146
- if (cwdWidth < width) {
147
- rightRaw = cwd;
148
- rightWidth = cwdWidth;
149
- } else {
150
- return truncateToWidth(cwd, width);
151
- }
152
- }
153
-
154
- if (rightWidth === width) return rightRaw;
155
-
156
- const leftLimit = Math.max(0, width - rightWidth - 1);
157
- const leftRawClamped = truncateToWidth(leftRaw, leftLimit);
158
- const leftWidth = visibleWidth(leftRawClamped);
159
- const padWidth = Math.max(1, width - leftWidth - rightWidth);
160
- return `${leftRawClamped}${" ".repeat(padWidth)}${rightRaw}`;
161
- }
162
-
163
- /** Insert `badge` into a single border line at the left, after one corner cell. */
164
- function borderWithBadge(
165
- width: number,
166
- badge: string,
167
- border: (text: string) => string,
168
- ): string {
169
- if (width <= 0) return "";
170
- const badgeWidth = visibleWidth(badge);
171
- // 1 leading border cell + badge + fill out to width.
172
- if (badgeWidth + 1 >= width) {
173
- return border("─") + truncateToWidth(badge, Math.max(0, width - 1), "");
174
- }
175
- const fill = border("─".repeat(width - 1 - badgeWidth));
176
- return `${border("─")}${badge}${fill}`;
177
- }
178
-
179
- export default function (pi: ExtensionAPI) {
180
- pi.on("session_start", (_event, ctx) => {
181
- // Statusline (footer): model · [subscription] · tokens · cycle, with cwd/git right-aligned
182
- ctx.ui.setFooter((tui, theme, footerData) => {
183
- let gitStatus: GitStatus | null = null;
184
-
185
- const refreshStatus = () => {
186
- if (!footerData.getGitBranch()) {
187
- if (gitStatus) {
188
- gitStatus = null;
189
- tui.requestRender();
190
- }
191
- return;
192
- }
193
- void loadGitStatus(ctx.cwd).then((next) => {
194
- if (JSON.stringify(next) !== JSON.stringify(gitStatus)) {
195
- gitStatus = next;
196
- tui.requestRender();
197
- }
198
- });
199
- };
200
-
201
- refreshStatus();
202
- const unsubBranch = footerData.onBranchChange(() => {
203
- tui.requestRender();
204
- refreshStatus();
205
- });
206
- const timer = setInterval(refreshStatus, 4000);
207
-
208
- return {
209
- dispose() {
210
- unsubBranch();
211
- clearInterval(timer);
212
- },
213
- invalidate() {},
214
- render(width: number): string[] {
215
- return [theme.fg("dim", buildStatuslineFooterLine(width, ctx, footerData, gitStatus))];
216
- },
217
- };
218
- });
219
-
220
- // Input bar border: session-name badge with solid background
221
- // Compose with whatever editor is already installed instead of replacing it:
222
- // wrap the previous factory in a Proxy that overrides only render
223
- // (session-name badge on the top border). Other editor decorations keep
224
- // working regardless of load order.
225
- const previousEditorFactory = ctx.ui.getEditorComponent();
226
- ctx.ui.setEditorComponent((tui, theme, keybindings) => {
227
- const base = (
228
- previousEditorFactory
229
- ? previousEditorFactory(tui, theme, keybindings)
230
- : new CustomEditor(tui, theme, keybindings)
231
- ) as unknown as CustomEditor;
232
-
233
- const render = (width: number): string[] => {
234
- const lines = base.render(width);
235
- const name = pi.getSessionName();
236
- if (!name || lines.length === 0) return lines;
237
-
238
- const thm = ctx.ui.theme;
239
- const badge = thm.bg("selectedBg", thm.fg("text", ` ${name} `));
240
- const borderColor = (text: string) => base.borderColor(text);
241
- lines[0] = borderWithBadge(width, badge, borderColor);
242
- return lines;
243
- };
244
-
245
- return new Proxy(base, {
246
- get(target, prop) {
247
- if (prop === "render") return render;
248
- const value = Reflect.get(target, prop, target);
249
- return typeof value === "function" ? value.bind(target) : value;
250
- },
251
- });
252
- });
253
- });
254
- }
@@ -1,5 +0,0 @@
1
- /** Hard-truncate to `width` columns with an ellipsis when the text would
2
- * overflow. Extension-rendered content is ANSI-free plain text, so a
3
- * code-point count stands in for visible width. Every renderer MUST keep its
4
- * emitted lines within the terminal width or pi's TUI aborts the whole render. */
5
- export declare function truncateToWidth(text: string, width: number): string;
@@ -1,14 +0,0 @@
1
- /** Hard-truncate to `width` columns with an ellipsis when the text would
2
- * overflow. Extension-rendered content is ANSI-free plain text, so a
3
- * code-point count stands in for visible width. Every renderer MUST keep its
4
- * emitted lines within the terminal width or pi's TUI aborts the whole render. */
5
- export function truncateToWidth(text, width) {
6
- if (width <= 0)
7
- return '';
8
- const chars = Array.from(text);
9
- if (chars.length <= width)
10
- return text;
11
- if (width === 1)
12
- return '…';
13
- return chars.slice(0, width - 1).join('') + '…';
14
- }