@north-light/crouter 0.3.322 → 0.3.323

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 (57) hide show
  1. package/bin/progress-painter.mjs +89 -0
  2. package/bin/runtime-selector.mjs +79 -9
  3. package/dist/api/client.d.ts +6 -2
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/broker-ops.d.ts +9 -0
  6. package/dist/api/dto/canvas.d.ts +23 -1
  7. package/dist/api/dto/nodes.d.ts +8 -0
  8. package/dist/api/node-transport.js +1 -1
  9. package/dist/api/routes.d.ts +2 -0
  10. package/dist/api/routes.js +1 -1
  11. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  12. package/dist/clients/attach/overlays/graph.d.ts +6 -5
  13. package/dist/clients/attach/overlays/graph.js +1 -1
  14. package/dist/clients/attach/viewer.js +536 -536
  15. package/dist/commands/node/create.js +3 -3
  16. package/dist/commands/sys/panels/plugins-panel.js +1 -1
  17. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  18. package/dist/commands/sys/panels/provider-panel.js +1 -1
  19. package/dist/commands/sys/setup-core.js +7 -4
  20. package/dist/commands/sys/setup-wizard.d.ts +1 -1
  21. package/dist/commands/sys/setup-wizard.js +1 -1
  22. package/dist/core/canvas/canvas.d.ts +24 -0
  23. package/dist/core/canvas/canvas.js +29 -15
  24. package/dist/core/canvas/migrations.js +35 -32
  25. package/dist/core/canvas/nav-model.d.ts +1 -1
  26. package/dist/core/canvas/nav-model.js +1 -1
  27. package/dist/core/canvas/nav-render.d.ts +31 -25
  28. package/dist/core/canvas/nav-render.js +1 -1
  29. package/dist/core/canvas/render-source.d.ts +6 -16
  30. package/dist/core/canvas/render-source.js +9 -9
  31. package/dist/core/canvas/types.d.ts +16 -0
  32. package/dist/core/provider-credential.d.ts +6 -0
  33. package/dist/core/provider-credential.js +1 -0
  34. package/dist/core/runtime/boot-root.d.ts +2 -0
  35. package/dist/core/runtime/boot-root.js +1 -1
  36. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -1
  37. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  38. package/dist/core/runtime/front-door-login.d.ts +2 -0
  39. package/dist/core/runtime/front-door-login.js +1 -0
  40. package/dist/core/runtime/front-door.js +7 -5
  41. package/dist/core/runtime/nerd-font.d.ts +19 -1
  42. package/dist/core/runtime/nerd-font.js +2 -2
  43. package/dist/core/runtime/progress-bar.d.ts +13 -0
  44. package/dist/core/runtime/progress-bar.js +2 -0
  45. package/dist/core/runtime/provider-credential-gate.d.ts +4 -0
  46. package/dist/core/runtime/provider-credential-gate.js +2 -0
  47. package/dist/core/runtime/spawn-env.d.ts +7 -0
  48. package/dist/core/runtime/spawn-env.js +1 -1
  49. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  50. package/dist/daemon/api/handlers/canvas.js +4 -4
  51. package/dist/daemon/api/map.d.ts +15 -1
  52. package/dist/daemon/api/map.js +2 -2
  53. package/dist/daemon/fleet.js +1 -1
  54. package/dist/pi-extensions/canvas-stophook.js +1 -1
  55. package/package.json +1 -1
  56. package/runtime.lock.json +5 -5
  57. package/scripts/install-runtime.mjs +7 -3
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ // Draws one animated progress bar line for a long install step, in its own
3
+ // process.
4
+ //
5
+ // A separate process is what makes the bar move at all: the steps it covers
6
+ // (`uv` provisioning the renderer, a marketplace git clone, `npm ci` inside
7
+ // the runtime installer) block the parent's event loop, so a timer in the
8
+ // parent would render nothing until the work it describes had already
9
+ // finished. This process owns nothing but the line it draws — the parent's
10
+ // `✓ name` / `✗ name` line remains the authoritative outcome.
11
+ //
12
+ // Contract:
13
+ // argv[2] label drawn to the left of the bar
14
+ // stdin lines holding a fraction 0..1 switch the bar to determinate and
15
+ // set its fill; EOF ends the bar (line erased, exit 0)
16
+ // stdout the bar line — the parent maps this to whichever stream it wants
17
+ //
18
+ // Plain JS with no imports: `bin/runtime-selector.mjs` spawns it before any
19
+ // runtime generation's `dist/` is loaded.
20
+
21
+ const label = process.argv[2] ?? '';
22
+ const FRAME_MS = 80;
23
+ const MAX_TRACK = 24;
24
+ const MIN_TRACK = 8;
25
+ const SLIDER = 6;
26
+
27
+ let fraction = null;
28
+ let tick = 0;
29
+ let stopped = false;
30
+
31
+ /** Track width that leaves room for the label and the percent suffix in this
32
+ * terminal; the label is truncated only when even MIN_TRACK will not fit. */
33
+ function layout() {
34
+ // A pty with no window size set (a `script`-style capture) reports 0.
35
+ const columns = process.stdout.columns || 80;
36
+ const suffix = fraction === null ? 0 : 5;
37
+ const available = columns - label.length - suffix - 2;
38
+ if (available >= MIN_TRACK) return { text: label, track: Math.min(MAX_TRACK, available) };
39
+ const text = label.slice(0, Math.max(0, columns - suffix - MIN_TRACK - 3));
40
+ return { text: text === label ? text : `${text}…`, track: MIN_TRACK };
41
+ }
42
+
43
+ function bar(track) {
44
+ if (fraction !== null) {
45
+ const filled = Math.min(track, Math.round(fraction * track));
46
+ return '█'.repeat(filled) + '░'.repeat(track - filled);
47
+ }
48
+ // Indeterminate: a lit segment sliding to the end of the track and back.
49
+ const span = Math.max(1, track - SLIDER);
50
+ const at = tick % (span * 2);
51
+ const start = at <= span ? at : span * 2 - at;
52
+ const width = Math.min(SLIDER, track);
53
+ return '░'.repeat(start) + '█'.repeat(width) + '░'.repeat(Math.max(0, track - start - width));
54
+ }
55
+
56
+ function render() {
57
+ const { text, track } = layout();
58
+ const percent = fraction === null ? '' : ` ${String(Math.round(fraction * 100)).padStart(3)}%`;
59
+ process.stdout.write(`\r\x1b[2K${text} ${bar(track)}${percent}`);
60
+ tick += 1;
61
+ }
62
+
63
+ function stop(code) {
64
+ if (stopped) return;
65
+ stopped = true;
66
+ clearInterval(timer);
67
+ process.stdout.write('\r\x1b[2K\x1b[?25h');
68
+ process.exit(code);
69
+ }
70
+
71
+ process.stdout.write('\x1b[?25l');
72
+ render();
73
+ const timer = setInterval(render, FRAME_MS);
74
+
75
+ let pending = '';
76
+ process.stdin.setEncoding('utf8');
77
+ process.stdin.on('data', (chunk) => {
78
+ pending += chunk;
79
+ const lines = pending.split('\n');
80
+ pending = lines.pop() ?? '';
81
+ for (const line of lines) {
82
+ const value = Number(line.trim());
83
+ if (Number.isFinite(value) && value >= 0 && value <= 1) fraction = value;
84
+ }
85
+ });
86
+ process.stdin.on('end', () => stop(0));
87
+ process.stdin.on('error', () => stop(0));
88
+ process.on('SIGINT', () => stop(130));
89
+ process.on('SIGTERM', () => stop(143));
@@ -1,4 +1,4 @@
1
- import { spawnSync } from 'node:child_process';
1
+ import { spawn, spawnSync } from 'node:child_process';
2
2
  import { existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
@@ -19,6 +19,41 @@ function isSourceCheckout() {
19
19
  return existsSync(join(PACKAGE_ROOT, '.git'));
20
20
  }
21
21
 
22
+ /**
23
+ * One line for a long first-run step. At a terminal it is an animated bar
24
+ * drawn by `bin/progress-painter.mjs` in its own process (the installer and
25
+ * the renderer provision both block this event loop), replaced by a `✓`/`✗`
26
+ * line when the step ends. Off a terminal it is the same one-time notice this
27
+ * shim has always printed, and nothing else.
28
+ *
29
+ * Both steps are indeterminate: neither the runtime installer nor `uv`
30
+ * reports a count this shim could fill a bar from, and a bar that invents one
31
+ * would be lying about progress it cannot see.
32
+ */
33
+ function beginStep(command, notice) {
34
+ if (!process.stderr.isTTY) {
35
+ process.stderr.write(`${command}: ${notice}\n`);
36
+ return null;
37
+ }
38
+ let child;
39
+ try {
40
+ child = spawn(process.execPath, [join(dirname(fileURLToPath(import.meta.url)), 'progress-painter.mjs'), `${command}: ${notice}`], { stdio: ['pipe', 2, 'ignore'] });
41
+ } catch {
42
+ process.stderr.write(`${command}: ${notice}\n`);
43
+ return null;
44
+ }
45
+ let alive = true;
46
+ const exited = new Promise((resolve) => {
47
+ child.once('exit', () => { alive = false; resolve(); });
48
+ child.once('error', () => { alive = false; resolve(); });
49
+ });
50
+ return async (outcome) => {
51
+ if (alive) child.stdin.end();
52
+ await Promise.race([exited, new Promise((resolve) => setTimeout(() => { child.kill('SIGKILL'); resolve(); }, 1000).unref())]);
53
+ process.stderr.write(`\r\x1b[2K\x1b[?25h${command}: ${outcome}\n`);
54
+ };
55
+ }
56
+
22
57
  function remediation() {
23
58
  return isSourceCheckout()
24
59
  ? 'Run `npm run build && npm run install-runtime` in the crouter source checkout, then retry.'
@@ -40,11 +75,34 @@ function remediation() {
40
75
  * and a source checkout keeps its explicit `npm run install-runtime` because
41
76
  * its `dist/` may be stale or absent.
42
77
  */
43
- function installFirstGeneration(command) {
78
+ async function installFirstGeneration(command) {
44
79
  if (isSourceCheckout() || !existsSync(join(PACKAGE_ROOT, 'dist', 'index.js'))) return false;
45
- process.stderr.write(`${command}: first run — installing the runtime generation (one-time)\n`);
46
- const result = spawnSync(process.execPath, [join(PACKAGE_ROOT, 'scripts', 'install-runtime.mjs'), PACKAGE_ROOT], { cwd: PACKAGE_ROOT, stdio: 'inherit' });
47
- return result.status === 0;
80
+ const end = beginStep(command, 'first run — installing the runtime generation (one-time)');
81
+ const result = await runInstaller(end !== null);
82
+ if (end !== null) await end(result.ok ? '✓ runtime generation' : `✗ runtime generation — ${firstLine(result.output) ?? 'installer failed'}`);
83
+ if (!result.ok && result.output !== '') process.stderr.write(result.output.endsWith('\n') ? result.output : `${result.output}\n`);
84
+ return result.ok;
85
+ }
86
+
87
+ /** Run the runtime installer. Behind a bar its output is captured so installer
88
+ * chatter cannot overwrite the bar line — the capture is printed in full if
89
+ * the install fails. With no bar (no terminal) the installer keeps writing
90
+ * through, exactly as it always has. */
91
+ function runInstaller(capture) {
92
+ return new Promise((resolve) => {
93
+ const child = spawn(process.execPath, [join(PACKAGE_ROOT, 'scripts', 'install-runtime.mjs'), PACKAGE_ROOT], { cwd: PACKAGE_ROOT, stdio: capture ? ['ignore', 'pipe', 'pipe'] : 'inherit' });
94
+ let output = '';
95
+ child.stdout?.setEncoding('utf8');
96
+ child.stderr?.setEncoding('utf8');
97
+ child.stdout?.on('data', (chunk) => { output += chunk; });
98
+ child.stderr?.on('data', (chunk) => { output += chunk; });
99
+ child.on('error', (error) => resolve({ ok: false, output: `${output}${errorMessage(error)}\n` }));
100
+ child.on('close', (status) => resolve({ ok: status === 0, output }));
101
+ });
102
+ }
103
+
104
+ function firstLine(text) {
105
+ return text.split(/\r?\n/).find((line) => line.trim() !== '')?.trim();
48
106
  }
49
107
 
50
108
  /**
@@ -58,9 +116,21 @@ async function provisionFirstRenderer(command, entryPath) {
58
116
  try {
59
117
  const mod = await import(pathToFileURL(join(dirname(entryPath), 'core', 'termrender', 'termrender.js')).href);
60
118
  if (mod.isRendererReady()) return;
61
- process.stderr.write(`${command}: first run — provisioning the markdown renderer (one-time)\n`);
62
- mod.ensureRenderer();
63
- if (!mod.isRendererReady()) process.stderr.write(`${command}: renderer not provisioned; it will be retried on first render.\n`);
119
+ const end = beginStep(command, 'first run — provisioning the markdown renderer (one-time)');
120
+ if (end === null) {
121
+ // No bar to protect: the provisioner's own diagnostics stream as they
122
+ // always have, before the outcome line.
123
+ mod.ensureRenderer();
124
+ if (!mod.isRendererReady()) process.stderr.write(`${command}: renderer not provisioned; it will be retried on first render.\n`);
125
+ return;
126
+ }
127
+ // Behind a bar the diagnostics are captured so they cannot overwrite the
128
+ // bar line; the first of them is the cause the ✗ line names.
129
+ let diagnostics = '';
130
+ mod.ensureRenderer((message) => { diagnostics += message; });
131
+ const ready = mod.isRendererReady();
132
+ await end(ready ? '✓ markdown renderer' : `✗ markdown renderer — ${firstLine(diagnostics) ?? 'not provisioned; it will be retried on first render'}`);
133
+ if (diagnostics !== '') process.stderr.write(diagnostics.endsWith('\n') ? diagnostics : `${diagnostics}\n`);
64
134
  } catch (error) {
65
135
  process.stderr.write(`${command}: renderer provisioning skipped: ${errorMessage(error)}\n`);
66
136
  }
@@ -413,7 +483,7 @@ export function selectRuntime(command, entryName) {
413
483
 
414
484
  export async function runSelected(command, entryName) {
415
485
  let result = tryResolveRuntime(entryName);
416
- if (!result.ok && result.code === 'missing-selection' && installFirstGeneration(command)) {
486
+ if (!result.ok && result.code === 'missing-selection' && await installFirstGeneration(command)) {
417
487
  result = tryResolveRuntime(entryName);
418
488
  if (result.ok) await provisionFirstRenderer(command, result.runtime.entryPath);
419
489
  }
@@ -19,9 +19,9 @@ import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, Review
19
19
  import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentForkDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
20
20
  import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageFeedbackResolutionDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
21
21
  import type { CreateHumanRequestDTO, CreateHumanRequestRequest, HumanRequestDTO, HumanRequestIdDTO, ReplaceHumanRequestRequest, RespondHumanRequestRequest, SettleHumanRequestRequest } from './dto/human-requests.js';
22
- import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryStatsQuery, HistoryStatsResultDTO, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
22
+ import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryStatsQuery, HistoryStatsResultDTO, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, GraphDTO, PruneRequest, PruneResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
23
23
  import type { AbandonWorktreeRequest, AbandonWorktreeResultDTO, CloseWorktreeResultDTO, QuarantinedWorktreeDTO } from './dto/worktree.js';
24
- import type { BrokerExtensionStateDTO, BrokerExecutionRequest, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
24
+ import type { BrokerExtensionStateDTO, BrokerExecutionRequest, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest, BrokerTelemetryRequest } from './dto/broker-ops.js';
25
25
  import type { AcknowledgeMailRequest, AcknowledgeMailResultDTO, ClaimMailRequest, ClaimMailResultDTO } from './dto/mail.js';
26
26
  import type { BrokerFaultInputDTO, BrokerFaultRequest, BrokerFaultResultDTO, BrokerProviderRetryRequest, BrokerProviderRetryResultDTO, BrokerTurnRequest, BrokerTurnResultDTO, NodeFaultClearResultDTO, RecoveryStateDTO } from './dto/recovery.js';
27
27
  export interface CrtrClientOptions {
@@ -129,6 +129,7 @@ export declare class CrtrClient {
129
129
  settleBroker(id: string, req: BrokerSettleRequest): Promise<BrokerSettleDirective>;
130
130
  completeBrokerPark(id: string, req: BrokerParkCompleteRequest): Promise<BrokerSettleDirective>;
131
131
  recordBrokerParkActivity(id: string, req: BrokerExecutionRequest): Promise<BrokerParkActivityResultDTO>;
132
+ recordBrokerTelemetry(id: string, req: BrokerTelemetryRequest): Promise<void>;
132
133
  claimNodeMail(id: string, req: ClaimMailRequest): Promise<ClaimMailResultDTO>;
133
134
  acknowledgeNodeMail(id: string, req: AcknowledgeMailRequest): Promise<AcknowledgeMailResultDTO>;
134
135
  recordBrokerTurn(id: string, req: BrokerTurnRequest): Promise<BrokerTurnResultDTO>;
@@ -315,6 +316,9 @@ export declare class CrtrClient {
315
316
  * poll target for attach/browser topology; use `canvasSnapshot` for the
316
317
  * enriched on-demand view. */
317
318
  canvasRoster(): Promise<RosterDTO>;
319
+ /** The lean attach-graph projection: display rows, topology, and focus state
320
+ * in one daemon-owned read rather than the full node-summary list. */
321
+ canvasGraph(): Promise<GraphDTO>;
318
322
  prune(req: PruneRequest): Promise<PruneResultDTO>;
319
323
  /** Raw request for routes not yet method-wrapped. Applies the same
320
324
  * autostart + retry + error-mapping semantics. */
@@ -1,2 +1,2 @@
1
- var p=Object.defineProperty;var d=(s,e)=>p(s,"name",{value:e,configurable:!0});import{ApiError as h,isErrorBody as b}from"./errors.js";import{routes as r}from"./routes.js";import{isSafeNodeId as S}from"./dto/common.js";import{isSafeBashJobId as R}from"./dto/bash-jobs.js";import{isSafeCronId as g}from"./dto/crons.js";const k=3e4,C=Symbol.for("@north-light/crouter-api/local-socket-fetch"),G=1e4,N=200;async function _({windowMs:s,probe:e,initialError:t,pollIntervalMs:n=N,retry:i=d(()=>!0,"retry"),now:o=Date.now,sleep:P=w}){const l=o()+s;let u=t;for(;;){const c=l-o();if(c<=0)throw u??new Error("crtrd availability window expired without a probe failure");try{await e(c);return}catch(f){if(u=f,!i(f))throw f}const m=l-o();if(m<=0)throw u;await P(Math.min(n,m))}}d(_,"waitForDaemonAvailability");class U{static{d(this,"CrtrClient")}baseUrl;fetch;headers;autostart;timeoutMs;maxRetries;localSocketTransport;onColdSocket;coldStartDiagnostic;coldStartPollWindowMs;coldStartAttempted=!1;constructor(e){if(e.baseUrl==="")throw new TypeError("CrtrClient requires baseUrl");this.baseUrl=new URL(e.baseUrl),this.fetch=e.fetch??globalThis.fetch,this.headers={...e.headers},this.autostart=e.autostart??!1,this.timeoutMs=e.timeoutMs??k,this.maxRetries=e.maxRetries??2,this.localSocketTransport=this.fetch[C]===!0,e.onColdSocket!==void 0&&(this.onColdSocket=e.onColdSocket),e.coldStartDiagnostic!==void 0&&(this.coldStartDiagnostic=e.coldStartDiagnostic),this.coldStartPollWindowMs=e.coldStartPollWindowMs??G}healthz(){return this.request("GET",r.healthz())}async probeHealthz(e){const t=await this.transport("GET",r.healthz(),void 0,{timeout:e});if(t.status===503)try{const n=await t.clone().json();if(typeof n.startup_blocked=="string")return n}catch{}return O(t)}status(){return this.request("GET",r.status())}restartDaemon(){return this.request("POST",r.daemonRestart())}admitDaemon(){return this.request("POST",r.daemonAdmit())}migrateState(e){return this.request("POST",r.daemonMigrate(),e)}createNode(e){return this.request("POST",r.nodes(),e)}listNodes(e){return this.request("GET",a(r.nodes(),e))}getNode(e){return this.request("GET",r.node(this.nodePath(e)))}getNodeOutcome(e,{waitSeconds:t}={}){if(t!==void 0&&(!Number.isInteger(t)||t<0||t>25))throw new RangeError("waitSeconds must be an integer between 0 and 25");return this.request("GET",a(r.nodeOutcome(this.nodePath(e)),{wait:t}),void 0,{timeout:(t??0)*1e3+this.timeoutMs})}registerOutcomeDelivery(e,t){return this.request("PUT",r.nodeOutcomeDelivery(this.nodePath(e)),t)}getOutcomeDelivery(e){return this.request("GET",r.nodeOutcomeDelivery(this.nodePath(e)))}async disarmOutcomeDelivery(e){await this.request("DELETE",r.nodeOutcomeDelivery(this.nodePath(e)))}listBashJobs(e){return this.request("GET",r.nodeJobs(this.nodePath(e)))}stopBashJob(e,t){return this.request("DELETE",r.nodeJob(this.nodePath(e),this.jobPath(t)))}sendMessage(e,t){return this.request("POST",r.nodeMessages(this.nodePath(e)),t)}interruptNode(e){return this.request("POST",r.nodeInterrupt(this.nodePath(e)),{})}pushReport(e,t){return this.request("POST",r.nodeReports(this.nodePath(e)),t)}submitResult(e,t){return this.request("POST",r.nodeResult(this.nodePath(e)),t)}forkNode(e){return this.request("POST",r.nodeFork(this.nodePath(e)),{})}reviveNode(e,t){return this.request("POST",r.nodeRevive(this.nodePath(e)),t??{})}relaunchRoot(e){return this.request("POST",r.nodeRelaunchRoot(this.nodePath(e)),{})}bindBrokerSession(e,t){return this.request("POST",r.nodeBrokerSessionBound(this.nodePath(e)),t)}settleBroker(e,t){return this.request("POST",r.nodeBrokerSettle(this.nodePath(e)),t)}completeBrokerPark(e,t){return this.request("POST",r.nodeBrokerParkComplete(this.nodePath(e)),t)}recordBrokerParkActivity(e,t){return this.request("POST",r.nodeBrokerParkActivity(this.nodePath(e)),t)}claimNodeMail(e,t){return this.request("POST",r.nodeMailClaim(this.nodePath(e)),t)}acknowledgeNodeMail(e,t){return this.request("POST",r.nodeMailAcknowledge(this.nodePath(e)),t)}recordBrokerTurn(e,t){return this.request("POST",r.brokerTurn(this.nodePath(e)),t)}mutateBrokerProviderRetry(e,t){return this.request("POST",r.brokerProviderRetry(this.nodePath(e)),t)}mutateBrokerFault(e,t){return this.request("POST",r.brokerFault(this.nodePath(e)),t)}getBrokerRecovery(e,t){return this.request("GET",`${r.brokerRecovery(this.nodePath(e))}?expected_execution_id=${encodeURIComponent(t)}`)}recordNodeFault(e,t){return this.request("POST",r.nodeFault(this.nodePath(e)),t)}clearNodeFault(e,t={}){const n=new URLSearchParams;t.link!==void 0&&n.set("link",t.link),t.preserve_episode!==void 0&&n.set("preserve_episode",String(t.preserve_episode));const i=n.size===0?"":`?${n.toString()}`;return this.request("DELETE",`${r.nodeFault(this.nodePath(e))}${i}`)}commitBrokerModel(e,t){return this.request("POST",r.nodeBrokerModel(this.nodePath(e)),t)}brokerExtensionState(e){return this.request("GET",r.nodeBrokerExtensionState(this.nodePath(e)))}commitBrokerGeneratedName(e,t){return this.request("POST",r.nodeBrokerGeneratedName(this.nodePath(e)),t)}commitBrokerPersonaAck(e,t){return this.request("POST",r.nodeBrokerPersonaAck(this.nodePath(e)),t)}closeNode(e,t){return this.request("POST",r.nodeClose(this.nodePath(e)),t??{})}recycleNode(e){return this.request("POST",r.nodeRecycle(this.nodePath(e)),{})}demoteNode(e){return this.request("POST",r.nodeDemote(this.nodePath(e)),{})}promoteNode(e,t){return this.request("POST",r.nodePromote(this.nodePath(e)),t)}yieldNode(e,t){return this.request("POST",r.nodeYield(this.nodePath(e)),t)}waitNode(e,t){return this.request("POST",r.nodeWait(this.nodePath(e)),t)}patchConfig(e,t){return this.request("PATCH",r.nodeConfig(this.nodePath(e)),t)}closeWorktree(e){return this.request("POST",r.nodeWorktreeClose(this.nodePath(e)),{})}abandonWorktree(e,t){return this.request("POST",r.nodeWorktreeAbandon(this.nodePath(e)),t)}listQuarantinedWorktrees(){return this.request("GET",r.quarantinedWorktrees())}subscribe(e,t){return this.request("POST",r.nodeSubscriptions(this.nodePath(e)),t)}listFocuses(){return this.request("GET",r.focuses())}focusOf(e){return this.request("GET",a(r.focusByNode(),{node_id:e}))}focusByPane(e){return this.request("GET",a(r.focusByPane(),{pane:e}))}registerFocus(e){return this.request("POST",r.focuses(),e)}async setFocusPane(e,t){await this.request("PATCH",r.focus(e),t)}async closeFocus(e){await this.request("DELETE",r.focus(e))}async unsubscribe(e,t){await this.request("DELETE",r.nodeSubscription(this.nodePath(e),this.nodePath(t)))}armCron(e){return this.request("POST",r.crons(),e)}listCrons(e){return this.request("GET",a(r.crons(),e))}showCron(e,t){return this.request("GET",a(r.cron(this.cronPath(e)),t))}pauseCron(e,t){return this.request("POST",a(r.cronPause(this.cronPath(e)),t),{})}resumeCron(e,t){return this.request("POST",a(r.cronResume(this.cronPath(e)),t),{})}runCron(e,t){return this.request("POST",a(r.cronRun(this.cronPath(e)),t),{})}async cancelCron(e,t){await this.request("DELETE",a(r.cron(this.cronPath(e)),t))}pokeCrons(){return this.request("POST",r.cronsPoke(),{})}ensureAttach(e,t){return this.request("POST",r.nodeAttach(this.nodePath(e)),t??{})}getReports(e,t){return this.request("GET",a(r.nodeReports(this.nodePath(e)),t))}getTranscript(e,t){return this.request("GET",a(r.nodeTranscript(this.nodePath(e)),t))}getSnapshot(e){return this.request("GET",r.nodeSnapshot(this.nodePath(e)))}nodeSubject(e){return this.request("GET",r.nodeSubject(this.nodePath(e)))}getNodeMessages(e,t){return this.request("GET",a(r.nodeMessages(this.nodePath(e)),t))}getSession(e){return this.request("GET",r.nodeSession(this.nodePath(e)))}getChatInventory(e){return this.request("GET",r.nodeChatInventory(this.nodePath(e)))}getProspectiveChatInventory(e){return this.request("GET",a(r.prospectiveChatInventory(),e))}getArtifacts(e,t){return this.request("GET",a(r.nodeArtifacts(this.nodePath(e)),t))}getContext(e){return this.request("GET",r.nodeContext(this.nodePath(e)))}peekFile(e){return this.request("GET",a(r.filePeek(),{path:e}))}resolveMemoryDoc(e,t){return this.request("GET",a(r.memoryResolve(),{name:e,node:t}))}ensureProfile(e,t){return this.request("PUT",r.profile(e),t??{})}listProfiles(){return this.request("GET",r.profiles())}getProfile(e){return this.request("GET",r.profile(e))}pauseProfile(e){return this.request("POST",r.profilePause(e),{})}resumeProfile(e){return this.request("POST",r.profileResume(e),{})}updateProfileMetadata(e,t){return this.request("PATCH",r.profileMetadata(e),t)}deleteProfile(e,t){return this.request("DELETE",r.profile(e),t)}listModelAuth(){return this.request("GET",r.modelAuths())}getModelAuthReadiness(e){return this.request("GET",a(r.modelAuthReadiness(),e))}installCredential(e,t){return this.request("PUT",r.modelAuth(e),t)}removeCredential(e){return this.request("DELETE",r.modelAuth(e))}createReview(e){return this.request("POST",r.humanReviews(),e)}listReviews(e){return this.request("GET",a(r.humanReviews(),e))}getReview(e){return this.request("GET",r.humanReview(this.reviewPath(e)))}submitReview(e){return this.request("POST",r.humanReviewSubmit(this.reviewPath(e)),{})}cancelReview(e,t={}){return this.request("POST",r.humanReviewCancel(this.reviewPath(e)),t)}getReviewDocumentBase(e){return this.request("GET",r.humanReviewDocument(this.reviewPath(e)))}createReviewComment(e,t){const n=e===void 0?"self":this.reviewPath(e);return this.request("POST",r.humanReviewComments(n),t)}listReviewComments(e,t){const n=e===void 0?"self":this.reviewPath(e);return this.request("GET",a(r.humanReviewComments(n),t))}readReviewCommentEvents(e,t){return this.request("GET",a(r.humanReviewCommentEvents(this.reviewPath(e)),t))}updateReviewCommentRanges(e,t){return this.request("POST",r.humanReviewCommentRanges(this.reviewPath(e)),t)}getReviewComment(e){return this.request("GET",r.humanComment(this.commentPath(e)))}editReviewComment(e,t){return this.request("POST",r.humanCommentEdit(this.commentPath(e)),t)}resolveReviewComment(e,t={}){return this.request("POST",r.humanCommentResolve(this.commentPath(e)),t)}reopenReviewComment(e,t={}){return this.request("POST",r.humanCommentReopen(this.commentPath(e)),t)}deleteReviewComment(e,t={}){return this.request("POST",r.humanCommentDelete(this.commentPath(e)),t)}forkReviewComment(e){return this.request("POST",r.humanCommentFork(this.commentPath(e)),{})}listHumanInbox(){return this.request("GET",r.humanInbox())}getHumanInboxPage(e){return this.request("GET",r.humanInboxTicket(this.ticketId(e)))}getInboxHistory(e){if(e===void 0)return this.request("GET",r.humanInbox()+"/history");if(typeof e!="string"||e==="")throw new TypeError(`invalid node id: ${JSON.stringify(e)}`);return this.request("GET",a(r.humanInbox()+"/history",{node_id:e}))}respondHumanInboxPage(e,t){return this.request("POST",r.humanInboxRespond(this.ticketId(e)),t)}postInboxProgress(e,t){return this.request("POST",r.humanInboxProgress(this.ticketId(e)),{responses:t})}getInboxResponse(e){return this.request("GET",r.humanInboxResponse(this.ticketId(e)))}cancelHumanInboxTicket(e,t){return this.request("POST",r.humanInboxCancel(this.ticketId(e)),t??{})}createHumanRequest(e){return this.request("POST",r.humanRequests(),e)}getHumanRequest(e){return this.request("GET",r.humanRequest(this.requestPath(e)))}replaceHumanRequest(e,t){return this.request("POST",r.humanRequestReplace(this.requestPath(e)),t)}respondHumanRequest(e,t){return this.request("POST",r.humanRequestRespond(this.requestPath(e)),t)}dismissHumanRequest(e,t={}){return this.request("POST",r.humanRequestDismiss(this.requestPath(e)),t)}cancelHumanRequest(e,t={}){return this.request("POST",r.humanRequestCancel(this.requestPath(e)),t)}resolvePageFeedbackComment(e,t,n){if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(t))throw new TypeError(`invalid feedback comment id: ${JSON.stringify(t)}`);return this.request("POST",r.humanInboxFeedbackResolve(this.ticketId(e),t),{node_id:n})}async dashboard(e){const t=e?.under!==void 0?{under:e.under}:void 0,[n,i]=await Promise.all([this.listNodes(t),this.status()]);return{nodes:n,counts:i.node_counts,generated_at:new Date().toISOString()}}attention(){return this.request("GET",r.canvasAttention())}attentionCounts(e){const t={node_ids:e};return this.request("POST",r.canvasAttentionCounts(),t)}historySearch(e){return this.request("POST",r.canvasHistorySearch(),e)}historyGrep(e){return this.request("POST",r.canvasHistoryGrep(),e)}historyRead(e){return this.request("GET",a(r.canvasHistoryRead(),e))}historyStats(e){return this.request("POST",r.canvasHistoryStats(),e)}canvasSnapshot(){return this.request("GET",r.canvasSnapshot())}canvasRoster(){return this.request("GET",r.canvasRoster())}prune(e){return this.request("POST",r.canvasPrune(),e)}async request(e,t,n,i){try{return await O(await this.send(e,t,n,i))}catch(o){throw T(o,i?.signal)}}async send(e,t,n,i={}){const o=e==="GET"||e==="HEAD"||e==="DELETE",P=i.maxRetries??this.maxRetries;for(let l=0;;l++){let u;try{u=await this.transport(e,t,n,i)}catch(c){if(this.isColdSocketError(c))try{await this.handleColdSocket(c),u=await this.transport(e,t,n,i)}catch(m){throw T(m,i.signal)}else{if(this.isInterruptedSocketError(c)&&this.localSocketTransport&&(!o||l<P))return await this.rideOutInterruptedRequest(e,t,n,i);if(o&&l<P&&!A(c,i.signal)&&(!this.localSocketTransport||!this.isInterruptedSocketError(c))){await w(v(l+1));continue}else throw T(c,i.signal)}}if(o&&l<P&&x(u.status)){await D(u),await w(v(l+1));continue}return u}}nodePath(e){if(!S(e))throw new h(400,"invalid_node_id",`invalid node id: ${JSON.stringify(e)}`);return e}jobPath(e){if(!R(e))throw new h(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(e)}`);return e}cronPath(e){if(!g(e))throw new h(400,"invalid_cron_id",`invalid cron id: ${JSON.stringify(e)}`);return e}requestPath(e){if(!S(e))throw new h(400,"invalid_request_id",`invalid request id: ${JSON.stringify(e)}`);return e}ticketId(e){if(!/^[a-f0-9]{64}$/.test(e))throw new TypeError(`invalid inbox ticket id: ${JSON.stringify(e)}`);return e}reviewPath(e){if(!S(e))throw new h(400,"invalid_review_id",`invalid review id: ${JSON.stringify(e)}`);return e}commentPath(e){if(!/^[a-f0-9]{32}$/.test(e))throw new h(400,"invalid_comment_id",`invalid comment id: ${JSON.stringify(e)}`);return e}transport(e,t,n,i={}){const o=n===void 0?void 0:JSON.stringify(n),P={accept:"application/json",...this.headers,...i.headers};o!==void 0&&(P["content-type"]="application/json");const l=i.timeout??this.timeoutMs,u=new AbortController,c=l>0?setTimeout(()=>u.abort(new DOMException("request timed out","TimeoutError")),l):void 0,m=i.signal,f=d(()=>u.abort(m?.reason),"onExternalAbort");m!==void 0&&(m.aborted?u.abort(m.reason):m.addEventListener("abort",f,{once:!0}));const y=d(()=>{c!==void 0&&clearTimeout(c),m?.removeEventListener("abort",f)},"finish");return this.fetch(new URL(t,this.baseUrl),{method:e,headers:P,body:o,signal:u.signal}).then(q=>this.retainRequestLifetime(q,y,()=>u.signal.aborted?u.signal.reason:void 0),q=>{throw y(),q})}retainRequestLifetime(e,t,n){if(e.body===null)return t(),e;const i=e.body.getReader();let o=!1;const P=d(()=>{o||(o=!0,t())},"close"),l=new ReadableStream({async pull(u){try{const{done:c,value:m}=await i.read();c?(P(),u.close()):u.enqueue(m)}catch(c){P(),u.error(n()??c)}},async cancel(u){P(),await i.cancel(u)}});return new Response(l,{status:e.status,statusText:e.statusText,headers:e.headers})}isColdSocketError(e){const t=E(e);return t==="ECONNREFUSED"||t==="ENOENT"||t==="ENOTSOCK"}isInterruptedSocketError(e){const t=E(e);return t==="ECONNRESET"||t==="EPIPE"}async rideOutInterruptedRequest(e,t,n,i={}){try{await this.awaitAvailability()}catch(o){throw T(o,i.signal)}if(e!=="GET"&&e!=="HEAD")throw new h(503,"daemon_request_interrupted",`crtrd connection ended before this ${e} response; the request may or may not have been applied.`);try{return await this.transport(e,t,n,i)}catch(o){throw T(o,i.signal)}}async awaitAvailability(e){await _({windowMs:this.coldStartPollWindowMs,initialError:e,probe:d(async t=>{const n=await this.transport("GET",r.healthz(),void 0,{timeout:t});if(n.status>=200&&n.status<300)return;const i=await n.text();try{if(typeof JSON.parse(i).startup_blocked=="string")return}catch{}throw new h(n.status,"daemon_health_unavailable",`crtrd health check returned HTTP ${n.status}: ${i.slice(0,500)}`)},"probe")})}async handleColdSocket(e){const t=this.autostart&&this.onColdSocket!==void 0&&!this.coldStartAttempted;t&&(this.coldStartAttempted=!0,await this.onColdSocket());try{await this.awaitAvailability(e)}catch(n){if(t){const i=M(this.coldStartDiagnostic);if(i!==void 0){const o=T(n);throw new h(o.status,o.code,`${o.message}
2
- ${i}`)}}throw n}}}function a(s,e){if(e===void 0)return s;const t=new URLSearchParams;for(const[i,o]of Object.entries(e))o!=null&&t.set(i,String(o));const n=t.toString();return n===""?s:`${s}?${n}`}d(a,"withQuery");async function O(s){const e=s.status>=200&&s.status<300,t=(await s.text()).trim();let n;if(t!=="")try{n=JSON.parse(t)}catch{if(e)return;throw new h(s.status,"invalid_response",t.slice(0,500),void 0,s.headers)}if(e)return n;throw b(n)?new h(s.status,n.error.code,n.error.message,n.error.details,s.headers):new h(s.status,"internal",`request failed with status ${s.status}`,void 0,s.headers)}d(O,"parse");function x(s){return s===429||s>=500}d(x,"isRetryableStatus");async function D(s){try{await s.body?.cancel()}catch{}}d(D,"drainResponseBody");function v(s){return Math.min(2e3,250*2**(s-1))}d(v,"retryDelayMs");function E(s){if(typeof s!="object"||s===null)return;const e=s.code;if(typeof e=="string")return e;const t=s.cause;if(typeof t=="object"&&t!==null){const n=t.code;if(typeof n=="string")return n}}d(E,"transportErrorCode");function A(s,e){return e?.aborted?!0:s instanceof DOMException&&(s.name==="AbortError"||s.name==="TimeoutError")}d(A,"isAbortError");function T(s,e){if(e?.aborted)return new h(0,"request_aborted","request aborted by caller signal");if(s instanceof h)return s;if(s instanceof DOMException&&s.name==="TimeoutError")return new h(504,"request_timeout",`crtrd request timed out: ${s.message}`);if(s instanceof DOMException&&s.name==="AbortError")return new h(0,"request_aborted","request aborted by caller signal");const t=E(s),n=s instanceof Error?s.message:String(s);return t==="ECONNREFUSED"||t==="ENOENT"||t==="ENOTSOCK"?new h(503,"daemon_unavailable",`crtrd is not reachable: ${n}`):t==="ETIMEDOUT"?new h(504,"request_timeout",`crtrd request timed out: ${n}`):new h(503,"transport_error",n)}d(T,"toTransportApiError");function w(s){return new Promise(e=>setTimeout(e,s))}d(w,"sleepMs");function M(s){if(s!==void 0)try{return s()}catch{return}}d(M,"safeColdStartDiagnostic");export{U as CrtrClient,M as safeColdStartDiagnostic,_ as waitForDaemonAvailability};
1
+ var p=Object.defineProperty;var d=(s,e)=>p(s,"name",{value:e,configurable:!0});import{ApiError as h,isErrorBody as b}from"./errors.js";import{routes as r}from"./routes.js";import{isSafeNodeId as S}from"./dto/common.js";import{isSafeBashJobId as R}from"./dto/bash-jobs.js";import{isSafeCronId as g}from"./dto/crons.js";const k=3e4,C=Symbol.for("@north-light/crouter-api/local-socket-fetch"),G=1e4,N=200;async function _({windowMs:s,probe:e,initialError:t,pollIntervalMs:n=N,retry:i=d(()=>!0,"retry"),now:o=Date.now,sleep:P=w}){const l=o()+s;let u=t;for(;;){const c=l-o();if(c<=0)throw u??new Error("crtrd availability window expired without a probe failure");try{await e(c);return}catch(f){if(u=f,!i(f))throw f}const m=l-o();if(m<=0)throw u;await P(Math.min(n,m))}}d(_,"waitForDaemonAvailability");class U{static{d(this,"CrtrClient")}baseUrl;fetch;headers;autostart;timeoutMs;maxRetries;localSocketTransport;onColdSocket;coldStartDiagnostic;coldStartPollWindowMs;coldStartAttempted=!1;constructor(e){if(e.baseUrl==="")throw new TypeError("CrtrClient requires baseUrl");this.baseUrl=new URL(e.baseUrl),this.fetch=e.fetch??globalThis.fetch,this.headers={...e.headers},this.autostart=e.autostart??!1,this.timeoutMs=e.timeoutMs??k,this.maxRetries=e.maxRetries??2,this.localSocketTransport=this.fetch[C]===!0,e.onColdSocket!==void 0&&(this.onColdSocket=e.onColdSocket),e.coldStartDiagnostic!==void 0&&(this.coldStartDiagnostic=e.coldStartDiagnostic),this.coldStartPollWindowMs=e.coldStartPollWindowMs??G}healthz(){return this.request("GET",r.healthz())}async probeHealthz(e){const t=await this.transport("GET",r.healthz(),void 0,{timeout:e});if(t.status===503)try{const n=await t.clone().json();if(typeof n.startup_blocked=="string")return n}catch{}return v(t)}status(){return this.request("GET",r.status())}restartDaemon(){return this.request("POST",r.daemonRestart())}admitDaemon(){return this.request("POST",r.daemonAdmit())}migrateState(e){return this.request("POST",r.daemonMigrate(),e)}createNode(e){return this.request("POST",r.nodes(),e)}listNodes(e){return this.request("GET",a(r.nodes(),e))}getNode(e){return this.request("GET",r.node(this.nodePath(e)))}getNodeOutcome(e,{waitSeconds:t}={}){if(t!==void 0&&(!Number.isInteger(t)||t<0||t>25))throw new RangeError("waitSeconds must be an integer between 0 and 25");return this.request("GET",a(r.nodeOutcome(this.nodePath(e)),{wait:t}),void 0,{timeout:(t??0)*1e3+this.timeoutMs})}registerOutcomeDelivery(e,t){return this.request("PUT",r.nodeOutcomeDelivery(this.nodePath(e)),t)}getOutcomeDelivery(e){return this.request("GET",r.nodeOutcomeDelivery(this.nodePath(e)))}async disarmOutcomeDelivery(e){await this.request("DELETE",r.nodeOutcomeDelivery(this.nodePath(e)))}listBashJobs(e){return this.request("GET",r.nodeJobs(this.nodePath(e)))}stopBashJob(e,t){return this.request("DELETE",r.nodeJob(this.nodePath(e),this.jobPath(t)))}sendMessage(e,t){return this.request("POST",r.nodeMessages(this.nodePath(e)),t)}interruptNode(e){return this.request("POST",r.nodeInterrupt(this.nodePath(e)),{})}pushReport(e,t){return this.request("POST",r.nodeReports(this.nodePath(e)),t)}submitResult(e,t){return this.request("POST",r.nodeResult(this.nodePath(e)),t)}forkNode(e){return this.request("POST",r.nodeFork(this.nodePath(e)),{})}reviveNode(e,t){return this.request("POST",r.nodeRevive(this.nodePath(e)),t??{})}relaunchRoot(e){return this.request("POST",r.nodeRelaunchRoot(this.nodePath(e)),{})}bindBrokerSession(e,t){return this.request("POST",r.nodeBrokerSessionBound(this.nodePath(e)),t)}settleBroker(e,t){return this.request("POST",r.nodeBrokerSettle(this.nodePath(e)),t)}completeBrokerPark(e,t){return this.request("POST",r.nodeBrokerParkComplete(this.nodePath(e)),t)}recordBrokerParkActivity(e,t){return this.request("POST",r.nodeBrokerParkActivity(this.nodePath(e)),t)}async recordBrokerTelemetry(e,t){await this.request("POST",r.nodeBrokerTelemetry(this.nodePath(e)),t)}claimNodeMail(e,t){return this.request("POST",r.nodeMailClaim(this.nodePath(e)),t)}acknowledgeNodeMail(e,t){return this.request("POST",r.nodeMailAcknowledge(this.nodePath(e)),t)}recordBrokerTurn(e,t){return this.request("POST",r.brokerTurn(this.nodePath(e)),t)}mutateBrokerProviderRetry(e,t){return this.request("POST",r.brokerProviderRetry(this.nodePath(e)),t)}mutateBrokerFault(e,t){return this.request("POST",r.brokerFault(this.nodePath(e)),t)}getBrokerRecovery(e,t){return this.request("GET",`${r.brokerRecovery(this.nodePath(e))}?expected_execution_id=${encodeURIComponent(t)}`)}recordNodeFault(e,t){return this.request("POST",r.nodeFault(this.nodePath(e)),t)}clearNodeFault(e,t={}){const n=new URLSearchParams;t.link!==void 0&&n.set("link",t.link),t.preserve_episode!==void 0&&n.set("preserve_episode",String(t.preserve_episode));const i=n.size===0?"":`?${n.toString()}`;return this.request("DELETE",`${r.nodeFault(this.nodePath(e))}${i}`)}commitBrokerModel(e,t){return this.request("POST",r.nodeBrokerModel(this.nodePath(e)),t)}brokerExtensionState(e){return this.request("GET",r.nodeBrokerExtensionState(this.nodePath(e)))}commitBrokerGeneratedName(e,t){return this.request("POST",r.nodeBrokerGeneratedName(this.nodePath(e)),t)}commitBrokerPersonaAck(e,t){return this.request("POST",r.nodeBrokerPersonaAck(this.nodePath(e)),t)}closeNode(e,t){return this.request("POST",r.nodeClose(this.nodePath(e)),t??{})}recycleNode(e){return this.request("POST",r.nodeRecycle(this.nodePath(e)),{})}demoteNode(e){return this.request("POST",r.nodeDemote(this.nodePath(e)),{})}promoteNode(e,t){return this.request("POST",r.nodePromote(this.nodePath(e)),t)}yieldNode(e,t){return this.request("POST",r.nodeYield(this.nodePath(e)),t)}waitNode(e,t){return this.request("POST",r.nodeWait(this.nodePath(e)),t)}patchConfig(e,t){return this.request("PATCH",r.nodeConfig(this.nodePath(e)),t)}closeWorktree(e){return this.request("POST",r.nodeWorktreeClose(this.nodePath(e)),{})}abandonWorktree(e,t){return this.request("POST",r.nodeWorktreeAbandon(this.nodePath(e)),t)}listQuarantinedWorktrees(){return this.request("GET",r.quarantinedWorktrees())}subscribe(e,t){return this.request("POST",r.nodeSubscriptions(this.nodePath(e)),t)}listFocuses(){return this.request("GET",r.focuses())}focusOf(e){return this.request("GET",a(r.focusByNode(),{node_id:e}))}focusByPane(e){return this.request("GET",a(r.focusByPane(),{pane:e}))}registerFocus(e){return this.request("POST",r.focuses(),e)}async setFocusPane(e,t){await this.request("PATCH",r.focus(e),t)}async closeFocus(e){await this.request("DELETE",r.focus(e))}async unsubscribe(e,t){await this.request("DELETE",r.nodeSubscription(this.nodePath(e),this.nodePath(t)))}armCron(e){return this.request("POST",r.crons(),e)}listCrons(e){return this.request("GET",a(r.crons(),e))}showCron(e,t){return this.request("GET",a(r.cron(this.cronPath(e)),t))}pauseCron(e,t){return this.request("POST",a(r.cronPause(this.cronPath(e)),t),{})}resumeCron(e,t){return this.request("POST",a(r.cronResume(this.cronPath(e)),t),{})}runCron(e,t){return this.request("POST",a(r.cronRun(this.cronPath(e)),t),{})}async cancelCron(e,t){await this.request("DELETE",a(r.cron(this.cronPath(e)),t))}pokeCrons(){return this.request("POST",r.cronsPoke(),{})}ensureAttach(e,t){return this.request("POST",r.nodeAttach(this.nodePath(e)),t??{})}getReports(e,t){return this.request("GET",a(r.nodeReports(this.nodePath(e)),t))}getTranscript(e,t){return this.request("GET",a(r.nodeTranscript(this.nodePath(e)),t))}getSnapshot(e){return this.request("GET",r.nodeSnapshot(this.nodePath(e)))}nodeSubject(e){return this.request("GET",r.nodeSubject(this.nodePath(e)))}getNodeMessages(e,t){return this.request("GET",a(r.nodeMessages(this.nodePath(e)),t))}getSession(e){return this.request("GET",r.nodeSession(this.nodePath(e)))}getChatInventory(e){return this.request("GET",r.nodeChatInventory(this.nodePath(e)))}getProspectiveChatInventory(e){return this.request("GET",a(r.prospectiveChatInventory(),e))}getArtifacts(e,t){return this.request("GET",a(r.nodeArtifacts(this.nodePath(e)),t))}getContext(e){return this.request("GET",r.nodeContext(this.nodePath(e)))}peekFile(e){return this.request("GET",a(r.filePeek(),{path:e}))}resolveMemoryDoc(e,t){return this.request("GET",a(r.memoryResolve(),{name:e,node:t}))}ensureProfile(e,t){return this.request("PUT",r.profile(e),t??{})}listProfiles(){return this.request("GET",r.profiles())}getProfile(e){return this.request("GET",r.profile(e))}pauseProfile(e){return this.request("POST",r.profilePause(e),{})}resumeProfile(e){return this.request("POST",r.profileResume(e),{})}updateProfileMetadata(e,t){return this.request("PATCH",r.profileMetadata(e),t)}deleteProfile(e,t){return this.request("DELETE",r.profile(e),t)}listModelAuth(){return this.request("GET",r.modelAuths())}getModelAuthReadiness(e){return this.request("GET",a(r.modelAuthReadiness(),e))}installCredential(e,t){return this.request("PUT",r.modelAuth(e),t)}removeCredential(e){return this.request("DELETE",r.modelAuth(e))}createReview(e){return this.request("POST",r.humanReviews(),e)}listReviews(e){return this.request("GET",a(r.humanReviews(),e))}getReview(e){return this.request("GET",r.humanReview(this.reviewPath(e)))}submitReview(e){return this.request("POST",r.humanReviewSubmit(this.reviewPath(e)),{})}cancelReview(e,t={}){return this.request("POST",r.humanReviewCancel(this.reviewPath(e)),t)}getReviewDocumentBase(e){return this.request("GET",r.humanReviewDocument(this.reviewPath(e)))}createReviewComment(e,t){const n=e===void 0?"self":this.reviewPath(e);return this.request("POST",r.humanReviewComments(n),t)}listReviewComments(e,t){const n=e===void 0?"self":this.reviewPath(e);return this.request("GET",a(r.humanReviewComments(n),t))}readReviewCommentEvents(e,t){return this.request("GET",a(r.humanReviewCommentEvents(this.reviewPath(e)),t))}updateReviewCommentRanges(e,t){return this.request("POST",r.humanReviewCommentRanges(this.reviewPath(e)),t)}getReviewComment(e){return this.request("GET",r.humanComment(this.commentPath(e)))}editReviewComment(e,t){return this.request("POST",r.humanCommentEdit(this.commentPath(e)),t)}resolveReviewComment(e,t={}){return this.request("POST",r.humanCommentResolve(this.commentPath(e)),t)}reopenReviewComment(e,t={}){return this.request("POST",r.humanCommentReopen(this.commentPath(e)),t)}deleteReviewComment(e,t={}){return this.request("POST",r.humanCommentDelete(this.commentPath(e)),t)}forkReviewComment(e){return this.request("POST",r.humanCommentFork(this.commentPath(e)),{})}listHumanInbox(){return this.request("GET",r.humanInbox())}getHumanInboxPage(e){return this.request("GET",r.humanInboxTicket(this.ticketId(e)))}getInboxHistory(e){if(e===void 0)return this.request("GET",r.humanInbox()+"/history");if(typeof e!="string"||e==="")throw new TypeError(`invalid node id: ${JSON.stringify(e)}`);return this.request("GET",a(r.humanInbox()+"/history",{node_id:e}))}respondHumanInboxPage(e,t){return this.request("POST",r.humanInboxRespond(this.ticketId(e)),t)}postInboxProgress(e,t){return this.request("POST",r.humanInboxProgress(this.ticketId(e)),{responses:t})}getInboxResponse(e){return this.request("GET",r.humanInboxResponse(this.ticketId(e)))}cancelHumanInboxTicket(e,t){return this.request("POST",r.humanInboxCancel(this.ticketId(e)),t??{})}createHumanRequest(e){return this.request("POST",r.humanRequests(),e)}getHumanRequest(e){return this.request("GET",r.humanRequest(this.requestPath(e)))}replaceHumanRequest(e,t){return this.request("POST",r.humanRequestReplace(this.requestPath(e)),t)}respondHumanRequest(e,t){return this.request("POST",r.humanRequestRespond(this.requestPath(e)),t)}dismissHumanRequest(e,t={}){return this.request("POST",r.humanRequestDismiss(this.requestPath(e)),t)}cancelHumanRequest(e,t={}){return this.request("POST",r.humanRequestCancel(this.requestPath(e)),t)}resolvePageFeedbackComment(e,t,n){if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(t))throw new TypeError(`invalid feedback comment id: ${JSON.stringify(t)}`);return this.request("POST",r.humanInboxFeedbackResolve(this.ticketId(e),t),{node_id:n})}async dashboard(e){const t=e?.under!==void 0?{under:e.under}:void 0,[n,i]=await Promise.all([this.listNodes(t),this.status()]);return{nodes:n,counts:i.node_counts,generated_at:new Date().toISOString()}}attention(){return this.request("GET",r.canvasAttention())}attentionCounts(e){const t={node_ids:e};return this.request("POST",r.canvasAttentionCounts(),t)}historySearch(e){return this.request("POST",r.canvasHistorySearch(),e)}historyGrep(e){return this.request("POST",r.canvasHistoryGrep(),e)}historyRead(e){return this.request("GET",a(r.canvasHistoryRead(),e))}historyStats(e){return this.request("POST",r.canvasHistoryStats(),e)}canvasSnapshot(){return this.request("GET",r.canvasSnapshot())}canvasRoster(){return this.request("GET",r.canvasRoster())}canvasGraph(){return this.request("GET",r.canvasGraph())}prune(e){return this.request("POST",r.canvasPrune(),e)}async request(e,t,n,i){try{return await v(await this.send(e,t,n,i))}catch(o){throw T(o,i?.signal)}}async send(e,t,n,i={}){const o=e==="GET"||e==="HEAD"||e==="DELETE",P=i.maxRetries??this.maxRetries;for(let l=0;;l++){let u;try{u=await this.transport(e,t,n,i)}catch(c){if(this.isColdSocketError(c))try{await this.handleColdSocket(c),u=await this.transport(e,t,n,i)}catch(m){throw T(m,i.signal)}else{if(this.isInterruptedSocketError(c)&&this.localSocketTransport&&(!o||l<P))return await this.rideOutInterruptedRequest(e,t,n,i);if(o&&l<P&&!A(c,i.signal)&&(!this.localSocketTransport||!this.isInterruptedSocketError(c))){await w(O(l+1));continue}else throw T(c,i.signal)}}if(o&&l<P&&x(u.status)){await D(u),await w(O(l+1));continue}return u}}nodePath(e){if(!S(e))throw new h(400,"invalid_node_id",`invalid node id: ${JSON.stringify(e)}`);return e}jobPath(e){if(!R(e))throw new h(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(e)}`);return e}cronPath(e){if(!g(e))throw new h(400,"invalid_cron_id",`invalid cron id: ${JSON.stringify(e)}`);return e}requestPath(e){if(!S(e))throw new h(400,"invalid_request_id",`invalid request id: ${JSON.stringify(e)}`);return e}ticketId(e){if(!/^[a-f0-9]{64}$/.test(e))throw new TypeError(`invalid inbox ticket id: ${JSON.stringify(e)}`);return e}reviewPath(e){if(!S(e))throw new h(400,"invalid_review_id",`invalid review id: ${JSON.stringify(e)}`);return e}commentPath(e){if(!/^[a-f0-9]{32}$/.test(e))throw new h(400,"invalid_comment_id",`invalid comment id: ${JSON.stringify(e)}`);return e}transport(e,t,n,i={}){const o=n===void 0?void 0:JSON.stringify(n),P={accept:"application/json",...this.headers,...i.headers};o!==void 0&&(P["content-type"]="application/json");const l=i.timeout??this.timeoutMs,u=new AbortController,c=l>0?setTimeout(()=>u.abort(new DOMException("request timed out","TimeoutError")),l):void 0,m=i.signal,f=d(()=>u.abort(m?.reason),"onExternalAbort");m!==void 0&&(m.aborted?u.abort(m.reason):m.addEventListener("abort",f,{once:!0}));const y=d(()=>{c!==void 0&&clearTimeout(c),m?.removeEventListener("abort",f)},"finish");return this.fetch(new URL(t,this.baseUrl),{method:e,headers:P,body:o,signal:u.signal}).then(q=>this.retainRequestLifetime(q,y,()=>u.signal.aborted?u.signal.reason:void 0),q=>{throw y(),q})}retainRequestLifetime(e,t,n){if(e.body===null)return t(),e;const i=e.body.getReader();let o=!1;const P=d(()=>{o||(o=!0,t())},"close"),l=new ReadableStream({async pull(u){try{const{done:c,value:m}=await i.read();c?(P(),u.close()):u.enqueue(m)}catch(c){P(),u.error(n()??c)}},async cancel(u){P(),await i.cancel(u)}});return new Response(l,{status:e.status,statusText:e.statusText,headers:e.headers})}isColdSocketError(e){const t=E(e);return t==="ECONNREFUSED"||t==="ENOENT"||t==="ENOTSOCK"}isInterruptedSocketError(e){const t=E(e);return t==="ECONNRESET"||t==="EPIPE"}async rideOutInterruptedRequest(e,t,n,i={}){try{await this.awaitAvailability()}catch(o){throw T(o,i.signal)}if(e!=="GET"&&e!=="HEAD")throw new h(503,"daemon_request_interrupted",`crtrd connection ended before this ${e} response; the request may or may not have been applied.`);try{return await this.transport(e,t,n,i)}catch(o){throw T(o,i.signal)}}async awaitAvailability(e){await _({windowMs:this.coldStartPollWindowMs,initialError:e,probe:d(async t=>{const n=await this.transport("GET",r.healthz(),void 0,{timeout:t});if(n.status>=200&&n.status<300)return;const i=await n.text();try{if(typeof JSON.parse(i).startup_blocked=="string")return}catch{}throw new h(n.status,"daemon_health_unavailable",`crtrd health check returned HTTP ${n.status}: ${i.slice(0,500)}`)},"probe")})}async handleColdSocket(e){const t=this.autostart&&this.onColdSocket!==void 0&&!this.coldStartAttempted;t&&(this.coldStartAttempted=!0,await this.onColdSocket());try{await this.awaitAvailability(e)}catch(n){if(t){const i=M(this.coldStartDiagnostic);if(i!==void 0){const o=T(n);throw new h(o.status,o.code,`${o.message}
2
+ ${i}`)}}throw n}}}function a(s,e){if(e===void 0)return s;const t=new URLSearchParams;for(const[i,o]of Object.entries(e))o!=null&&t.set(i,String(o));const n=t.toString();return n===""?s:`${s}?${n}`}d(a,"withQuery");async function v(s){const e=s.status>=200&&s.status<300,t=(await s.text()).trim();let n;if(t!=="")try{n=JSON.parse(t)}catch{if(e)return;throw new h(s.status,"invalid_response",t.slice(0,500),void 0,s.headers)}if(e)return n;throw b(n)?new h(s.status,n.error.code,n.error.message,n.error.details,s.headers):new h(s.status,"internal",`request failed with status ${s.status}`,void 0,s.headers)}d(v,"parse");function x(s){return s===429||s>=500}d(x,"isRetryableStatus");async function D(s){try{await s.body?.cancel()}catch{}}d(D,"drainResponseBody");function O(s){return Math.min(2e3,250*2**(s-1))}d(O,"retryDelayMs");function E(s){if(typeof s!="object"||s===null)return;const e=s.code;if(typeof e=="string")return e;const t=s.cause;if(typeof t=="object"&&t!==null){const n=t.code;if(typeof n=="string")return n}}d(E,"transportErrorCode");function A(s,e){return e?.aborted?!0:s instanceof DOMException&&(s.name==="AbortError"||s.name==="TimeoutError")}d(A,"isAbortError");function T(s,e){if(e?.aborted)return new h(0,"request_aborted","request aborted by caller signal");if(s instanceof h)return s;if(s instanceof DOMException&&s.name==="TimeoutError")return new h(504,"request_timeout",`crtrd request timed out: ${s.message}`);if(s instanceof DOMException&&s.name==="AbortError")return new h(0,"request_aborted","request aborted by caller signal");const t=E(s),n=s instanceof Error?s.message:String(s);return t==="ECONNREFUSED"||t==="ENOENT"||t==="ENOTSOCK"?new h(503,"daemon_unavailable",`crtrd is not reachable: ${n}`):t==="ETIMEDOUT"?new h(504,"request_timeout",`crtrd request timed out: ${n}`):new h(503,"transport_error",n)}d(T,"toTransportApiError");function w(s){return new Promise(e=>setTimeout(e,s))}d(w,"sleepMs");function M(s){if(s!==void 0)try{return s()}catch{return}}d(M,"safeColdStartDiagnostic");export{U as CrtrClient,M as safeColdStartDiagnostic,_ as waitForDaemonAvailability};
@@ -29,6 +29,15 @@ export interface BrokerSettleRequest extends BrokerExecutionRequest {
29
29
  backgroundJobsRunning: boolean;
30
30
  pushedFinal: boolean;
31
31
  }
32
+ /** `POST /v1/nodes/{id}/broker/telemetry` body. Tokens are cumulative within
33
+ * the broker's current Pi session; null context/activity values preserve the
34
+ * last usable value in the daemon projection, matching telemetry.json. */
35
+ export interface BrokerTelemetryRequest extends BrokerExecutionRequest {
36
+ tokens_in: number;
37
+ context_tokens: number | null;
38
+ last_activity: string | null;
39
+ updated_at: string;
40
+ }
32
41
  /** The only consequence a settle caller may enact. crtrd has already committed
33
42
  * every canvas and placement effect before returning this directive. */
34
43
  export type BrokerSettleDirective = {
@@ -1,5 +1,5 @@
1
1
  import type { Cursor, IsoTime, NodeIdDTO, NodeStatusDTO } from './common.js';
2
- import type { NodeSummaryDTO } from './nodes.js';
2
+ import type { NodeFaultDTO, NodeSummaryDTO } from './nodes.js';
3
3
  /** `GET /v1/nodes` + `GET /v1/status` composed for the dashboard view. */
4
4
  export interface DashboardQuery {
5
5
  /** Restrict to the subtree under this node. */
@@ -280,6 +280,28 @@ export interface RosterDTO {
280
280
  nodes: RosterNodeDTO[];
281
281
  edges: RosterEdgeDTO[];
282
282
  }
283
+ /** One row in `GET /v1/canvas/graph`: exactly the node fields the attach graph displays. */
284
+ export interface GraphNodeDTO {
285
+ node_id: NodeIdDTO;
286
+ name: string;
287
+ description: string | null;
288
+ cycles: number | null;
289
+ kind: string;
290
+ status: NodeStatusDTO;
291
+ frozen_at: IsoTime | null;
292
+ pi_pid: number | null;
293
+ telemetry_context_tokens: number | null;
294
+ telemetry_last_activity: string | null;
295
+ fault: NodeFaultDTO | null;
296
+ streaming: boolean;
297
+ }
298
+ /** `GET /v1/canvas/graph` — the attach graph's one-read projection: display rows, subscription topology, and the current local viewer-focus set. */
299
+ export interface GraphDTO {
300
+ generated_at: IsoTime;
301
+ nodes: GraphNodeDTO[];
302
+ edges: RosterEdgeDTO[];
303
+ focused_node_ids: NodeIdDTO[];
304
+ }
283
305
  /** `POST /v1/canvas/prune` body — the three exclusive prune modes of
284
306
  * `crtr canvas prune`, precedence COUNT (`limit`) > EMPTY (`empty`) > TTL sweep. */
285
307
  export interface PruneRequest {
@@ -105,6 +105,14 @@ export interface NodeSummaryDTO {
105
105
  final_report: string | null;
106
106
  finalized_at: IsoTime | null;
107
107
  deadline_at: IsoTime | null;
108
+ /** Cumulative input tokens reported by the broker telemetry producer. */
109
+ telemetry_tokens_in?: number | null;
110
+ /** Latest context-window token gauge reported by the broker. */
111
+ telemetry_context_tokens?: number | null;
112
+ /** Latest tool summary reported by the broker. */
113
+ telemetry_last_activity?: string | null;
114
+ /** Timestamp of the latest broker telemetry update. */
115
+ telemetry_updated_at?: IsoTime | null;
108
116
  outcome: NodeOutcomeSummaryDTO | null;
109
117
  fault?: NodeFaultDTO | null;
110
118
  streaming?: boolean;
@@ -1 +1 @@
1
- var C=Object.defineProperty;var a=(e,o)=>C(e,"name",{value:o,configurable:!0});import{request as v}from"node:http";import{homedir as A}from"node:os";import{join as b}from"node:path";import{CrtrClient as R}from"./client.js";import{envHomeOverride as S}from"../shared/env.js";const T=".crouter",O="crtrd.sock",k=Symbol.for("@north-light/crouter-api/local-socket-fetch");function L(){const e=S(),o=e!==void 0&&e!==""?e:b(A(),T,"canvas");return b(o,O)}a(L,"defaultSocketPath");function x(e){const o=a(function(n,s={}){const m=n instanceof URL?n:new URL(typeof n=="string"?n:n.url),w=s.method??"GET",h={};if(s.headers!==void 0)for(const[l,u]of new Headers(s.headers).entries())h[l]=u;const f=typeof s.body=="string"?s.body:void 0;return f!==void 0&&(h["content-length"]=String(Buffer.byteLength(f))),new Promise((l,u)=>{const i=v({socketPath:e,path:m.pathname+m.search,method:w,headers:h},t=>{const E=new ReadableStream({start(d){t.on("data",r=>d.enqueue(new Uint8Array(r))),t.on("end",()=>d.close()),t.on("error",r=>d.error(r))},cancel(){t.destroy()}}),y=new Headers;for(const[d,r]of Object.entries(t.headers))if(r!==void 0)for(const g of Array.isArray(r)?r:[r])y.append(d,g);l(new Response(E,{status:t.statusCode??0,statusText:t.statusMessage,headers:y}))});i.on("error",t=>u(new TypeError("fetch failed",{cause:t})));const c=s.signal,p=a(()=>{i.destroy(),u(c?.reason??new DOMException("The operation was aborted.","AbortError"))},"abort");if(c!=null){if(c.aborted){p();return}c.addEventListener("abort",p,{once:!0})}f!==void 0&&i.write(f),i.end()})},"fetchOverSocket");return o[k]=!0,o}a(x,"socketFetch");function B(e={}){const{socketPath:o,...n}=e;return new R({baseUrl:"http://localhost",fetch:x(o??L()),autostart:!0,...n})}a(B,"localClient");export{L as defaultSocketPath,B as localClient,x as socketFetch};
1
+ var v=Object.defineProperty;var a=(e,o)=>v(e,"name",{value:o,configurable:!0});import{request as A}from"node:http";import{homedir as R}from"node:os";import{join as w}from"node:path";import{CrtrClient as S}from"./client.js";import{envHomeOverride as T}from"../shared/env.js";const O=".crouter",k="crtrd.sock",L=Symbol.for("@north-light/crouter-api/local-socket-fetch");function x(){const e=T(),o=e!==void 0&&e!==""?e:w(R(),O,"canvas");return w(o,k)}a(x,"defaultSocketPath");function H(e){const o=a(function(n,s={}){const m=n instanceof URL?n:new URL(typeof n=="string"?n:n.url),E=s.method??"GET",h={};if(s.headers!==void 0)for(const[l,u]of new Headers(s.headers).entries())h[l]=u;const f=typeof s.body=="string"?s.body:void 0;return f!==void 0&&(h["content-length"]=String(Buffer.byteLength(f))),new Promise((l,u)=>{const i=A({socketPath:e,path:m.pathname+m.search,method:E,headers:h},t=>{const g=new ReadableStream({start(d){t.on("data",r=>d.enqueue(new Uint8Array(r))),t.on("end",()=>d.close()),t.on("error",r=>d.error(r))},cancel(){t.destroy()}}),y=new Headers;for(const[d,r]of Object.entries(t.headers))if(r!==void 0)for(const C of Array.isArray(r)?r:[r])y.append(d,C);const b=t.statusCode??0;l(new Response(b===204?null:g,{status:b,statusText:t.statusMessage,headers:y}))});i.on("error",t=>u(new TypeError("fetch failed",{cause:t})));const c=s.signal,p=a(()=>{i.destroy(),u(c?.reason??new DOMException("The operation was aborted.","AbortError"))},"abort");if(c!=null){if(c.aborted){p();return}c.addEventListener("abort",p,{once:!0})}f!==void 0&&i.write(f),i.end()})},"fetchOverSocket");return o[L]=!0,o}a(H,"socketFetch");function D(e={}){const{socketPath:o,...n}=e;return new S({baseUrl:"http://localhost",fetch:H(o??x()),autostart:!0,...n})}a(D,"localClient");export{x as defaultSocketPath,D as localClient,H as socketFetch};
@@ -33,6 +33,7 @@ export declare const routes: {
33
33
  readonly nodeBrokerSettle: (id: string) => string;
34
34
  readonly nodeBrokerParkComplete: (id: string) => string;
35
35
  readonly nodeBrokerParkActivity: (id: string) => string;
36
+ readonly nodeBrokerTelemetry: (id: string) => string;
36
37
  readonly nodeMailClaim: (id: string) => string;
37
38
  readonly nodeMailAcknowledge: (id: string) => string;
38
39
  readonly nodeBrokerModel: (id: string) => string;
@@ -75,6 +76,7 @@ export declare const routes: {
75
76
  readonly canvasHistoryStats: () => string;
76
77
  readonly canvasSnapshot: () => string;
77
78
  readonly canvasRoster: () => string;
79
+ readonly canvasGraph: () => string;
78
80
  readonly canvasPrune: () => string;
79
81
  readonly humanReviews: () => string;
80
82
  readonly humanReview: (reviewId: string) => string;
@@ -1 +1 @@
1
- var s=Object.defineProperty;var o=(e,n)=>s(e,"name",{value:n,configurable:!0});const a="v1",$="/v1",t={healthz:o(()=>"/healthz","healthz"),status:o(()=>"/v1/status","status"),daemonRestart:o(()=>"/v1/daemon/restart","daemonRestart"),daemonMigrate:o(()=>"/v1/daemon/migrate","daemonMigrate"),daemonAdmit:o(()=>"/v1/daemon/admit","daemonAdmit"),nodes:o(()=>"/v1/nodes","nodes"),reviveAll:o(()=>"/v1/nodes/revive-all","reviveAll"),node:o(e=>`/v1/nodes/${e}`,"node"),nodeOutcome:o(e=>`/v1/nodes/${e}/outcome`,"nodeOutcome"),nodeOutcomeDelivery:o(e=>`/v1/nodes/${e}/outcome-delivery`,"nodeOutcomeDelivery"),nodeSnapshot:o(e=>`/v1/nodes/${e}/snapshot`,"nodeSnapshot"),nodeSubject:o(e=>`/v1/nodes/${e}/subject`,"nodeSubject"),nodeSession:o(e=>`/v1/nodes/${e}/session`,"nodeSession"),nodeChatInventory:o(e=>`/v1/nodes/${e}/chat-inventory`,"nodeChatInventory"),prospectiveChatInventory:o(()=>"/v1/prospective-chat-inventory","prospectiveChatInventory"),nodeTranscript:o(e=>`/v1/nodes/${e}/transcript`,"nodeTranscript"),nodeContext:o(e=>`/v1/nodes/${e}/context`,"nodeContext"),nodeArtifacts:o(e=>`/v1/nodes/${e}/artifacts`,"nodeArtifacts"),nodeReports:o(e=>`/v1/nodes/${e}/reports`,"nodeReports"),nodeResult:o(e=>`/v1/nodes/${e}/result`,"nodeResult"),nodeJobs:o(e=>`/v1/nodes/${e}/jobs`,"nodeJobs"),nodeJob:o((e,n)=>`/v1/nodes/${e}/jobs/${n}`,"nodeJob"),nodeMessages:o(e=>`/v1/nodes/${e}/messages`,"nodeMessages"),nodeInterrupt:o(e=>`/v1/nodes/${e}/interrupt`,"nodeInterrupt"),nodeFork:o(e=>`/v1/nodes/${e}/fork`,"nodeFork"),nodeRevive:o(e=>`/v1/nodes/${e}/revive`,"nodeRevive"),nodeRelaunchRoot:o(e=>`/v1/nodes/${e}/relaunch-root`,"nodeRelaunchRoot"),nodeBrokerSessionBound:o(e=>`/v1/nodes/${e}/broker/session-bound`,"nodeBrokerSessionBound"),nodeBrokerSettle:o(e=>`/v1/nodes/${e}/broker/settle`,"nodeBrokerSettle"),nodeBrokerParkComplete:o(e=>`/v1/nodes/${e}/broker/park-complete`,"nodeBrokerParkComplete"),nodeBrokerParkActivity:o(e=>`/v1/nodes/${e}/broker/park-activity`,"nodeBrokerParkActivity"),nodeMailClaim:o(e=>`/v1/nodes/${e}/mail/claim`,"nodeMailClaim"),nodeMailAcknowledge:o(e=>`/v1/nodes/${e}/mail/acknowledge`,"nodeMailAcknowledge"),nodeBrokerModel:o(e=>`/v1/nodes/${e}/broker/model`,"nodeBrokerModel"),nodeBrokerExtensionState:o(e=>`/v1/nodes/${e}/broker/extension-state`,"nodeBrokerExtensionState"),nodeBrokerGeneratedName:o(e=>`/v1/nodes/${e}/broker/generated-name`,"nodeBrokerGeneratedName"),nodeBrokerPersonaAck:o(e=>`/v1/nodes/${e}/broker/persona-ack`,"nodeBrokerPersonaAck"),brokerTurn:o(e=>`/v1/broker/${e}/turn`,"brokerTurn"),brokerProviderRetry:o(e=>`/v1/broker/${e}/provider-retry`,"brokerProviderRetry"),brokerFault:o(e=>`/v1/broker/${e}/fault`,"brokerFault"),brokerRecovery:o(e=>`/v1/broker/${e}/recovery`,"brokerRecovery"),nodeFault:o(e=>`/v1/nodes/${e}/fault`,"nodeFault"),nodeClose:o(e=>`/v1/nodes/${e}/close`,"nodeClose"),nodeRecycle:o(e=>`/v1/nodes/${e}/recycle`,"nodeRecycle"),nodeDemote:o(e=>`/v1/nodes/${e}/demote`,"nodeDemote"),nodePromote:o(e=>`/v1/nodes/${e}/promote`,"nodePromote"),nodeYield:o(e=>`/v1/nodes/${e}/yield`,"nodeYield"),nodeWait:o(e=>`/v1/nodes/${e}/wait`,"nodeWait"),nodeConfig:o(e=>`/v1/nodes/${e}/config`,"nodeConfig"),nodeWorktreeClose:o(e=>`/v1/nodes/${e}/worktree/close`,"nodeWorktreeClose"),nodeWorktreeAbandon:o(e=>`/v1/nodes/${e}/worktree/abandon`,"nodeWorktreeAbandon"),quarantinedWorktrees:o(()=>"/v1/worktrees/quarantined","quarantinedWorktrees"),nodeAttach:o(e=>`/v1/nodes/${e}/attach`,"nodeAttach"),focuses:o(()=>"/v1/focuses","focuses"),focusByNode:o(()=>"/v1/focuses/by-node","focusByNode"),focusByPane:o(()=>"/v1/focuses/by-pane","focusByPane"),focus:o(e=>`/v1/focuses/${e}`,"focus"),nodeSubscriptions:o(e=>`/v1/nodes/${e}/subscriptions`,"nodeSubscriptions"),nodeSubscription:o((e,n)=>`/v1/nodes/${e}/subscriptions/${n}`,"nodeSubscription"),crons:o(()=>"/v1/crons","crons"),cron:o(e=>`/v1/crons/${e}`,"cron"),cronPause:o(e=>`/v1/crons/${e}/pause`,"cronPause"),cronResume:o(e=>`/v1/crons/${e}/resume`,"cronResume"),cronRun:o(e=>`/v1/crons/${e}/run`,"cronRun"),cronsPoke:o(()=>"/v1/crons/poke","cronsPoke"),canvasAttention:o(()=>"/v1/canvas/attention","canvasAttention"),canvasAttentionCounts:o(()=>"/v1/canvas/attention/counts","canvasAttentionCounts"),canvasHistorySearch:o(()=>"/v1/canvas/history/search","canvasHistorySearch"),canvasHistoryGrep:o(()=>"/v1/canvas/history/grep","canvasHistoryGrep"),canvasHistoryRead:o(()=>"/v1/canvas/history/read","canvasHistoryRead"),canvasHistoryStats:o(()=>"/v1/canvas/history/stats","canvasHistoryStats"),canvasSnapshot:o(()=>"/v1/canvas/snapshot","canvasSnapshot"),canvasRoster:o(()=>"/v1/canvas/roster","canvasRoster"),canvasPrune:o(()=>"/v1/canvas/prune","canvasPrune"),humanReviews:o(()=>"/v1/human/reviews","humanReviews"),humanReview:o(e=>`/v1/human/reviews/${e}`,"humanReview"),humanReviewSubmit:o(e=>`/v1/human/reviews/${e}/submit`,"humanReviewSubmit"),humanReviewCancel:o(e=>`/v1/human/reviews/${e}/cancel`,"humanReviewCancel"),humanReviewDocument:o(e=>`/v1/human/reviews/${e}/document`,"humanReviewDocument"),humanReviewComments:o(e=>`/v1/human/reviews/${e}/comments`,"humanReviewComments"),humanReviewCommentEvents:o(e=>`/v1/human/reviews/${e}/comment-events`,"humanReviewCommentEvents"),humanReviewCommentRanges:o(e=>`/v1/human/reviews/${e}/comment-ranges`,"humanReviewCommentRanges"),humanComment:o(e=>`/v1/human/comments/${e}`,"humanComment"),humanCommentEdit:o(e=>`/v1/human/comments/${e}/edit`,"humanCommentEdit"),humanCommentResolve:o(e=>`/v1/human/comments/${e}/resolve`,"humanCommentResolve"),humanCommentReopen:o(e=>`/v1/human/comments/${e}/reopen`,"humanCommentReopen"),humanCommentDelete:o(e=>`/v1/human/comments/${e}/delete`,"humanCommentDelete"),humanCommentFork:o(e=>`/v1/human/comments/${e}/fork`,"humanCommentFork"),humanInbox:o(()=>"/v1/human/inbox","humanInbox"),humanInboxTicket:o(e=>`/v1/human/inbox/${e}`,"humanInboxTicket"),humanInboxRespond:o(e=>`/v1/human/inbox/${e}/respond`,"humanInboxRespond"),humanInboxProgress:o(e=>`/v1/human/inbox/${e}/progress`,"humanInboxProgress"),humanInboxResponse:o(e=>`/v1/human/inbox/${e}/response`,"humanInboxResponse"),humanInboxCancel:o(e=>`/v1/human/inbox/${e}/cancel`,"humanInboxCancel"),humanInboxFeedbackResolve:o((e,n)=>`/v1/human/inbox/${e}/feedback-comments/${n}/resolve`,"humanInboxFeedbackResolve"),humanRequests:o(()=>"/v1/human/requests","humanRequests"),humanRequest:o(e=>`/v1/human/requests/${e}`,"humanRequest"),humanRequestReplace:o(e=>`/v1/human/requests/${e}/replace`,"humanRequestReplace"),humanRequestRespond:o(e=>`/v1/human/requests/${e}/respond`,"humanRequestRespond"),humanRequestDismiss:o(e=>`/v1/human/requests/${e}/dismiss`,"humanRequestDismiss"),humanRequestCancel:o(e=>`/v1/human/requests/${e}/cancel`,"humanRequestCancel"),profiles:o(()=>"/v1/profiles","profiles"),profile:o(e=>`/v1/profiles/${e}`,"profile"),profilePause:o(e=>`/v1/profiles/${e}/pause`,"profilePause"),profileResume:o(e=>`/v1/profiles/${e}/resume`,"profileResume"),profileMetadata:o(e=>`/v1/profiles/${e}/metadata`,"profileMetadata"),modelAuths:o(()=>"/v1/model-auth","modelAuths"),modelAuthReadiness:o(()=>"/v1/model-auth/readiness","modelAuthReadiness"),modelAuth:o(e=>`/v1/model-auth/${e}`,"modelAuth"),filePeek:o(()=>"/v1/files/peek","filePeek"),memoryResolve:o(()=>"/v1/memory/resolve","memoryResolve")};export{a as API_VERSION,t as routes};
1
+ var s=Object.defineProperty;var o=(e,n)=>s(e,"name",{value:n,configurable:!0});const a="v1",$="/v1",t={healthz:o(()=>"/healthz","healthz"),status:o(()=>"/v1/status","status"),daemonRestart:o(()=>"/v1/daemon/restart","daemonRestart"),daemonMigrate:o(()=>"/v1/daemon/migrate","daemonMigrate"),daemonAdmit:o(()=>"/v1/daemon/admit","daemonAdmit"),nodes:o(()=>"/v1/nodes","nodes"),reviveAll:o(()=>"/v1/nodes/revive-all","reviveAll"),node:o(e=>`/v1/nodes/${e}`,"node"),nodeOutcome:o(e=>`/v1/nodes/${e}/outcome`,"nodeOutcome"),nodeOutcomeDelivery:o(e=>`/v1/nodes/${e}/outcome-delivery`,"nodeOutcomeDelivery"),nodeSnapshot:o(e=>`/v1/nodes/${e}/snapshot`,"nodeSnapshot"),nodeSubject:o(e=>`/v1/nodes/${e}/subject`,"nodeSubject"),nodeSession:o(e=>`/v1/nodes/${e}/session`,"nodeSession"),nodeChatInventory:o(e=>`/v1/nodes/${e}/chat-inventory`,"nodeChatInventory"),prospectiveChatInventory:o(()=>"/v1/prospective-chat-inventory","prospectiveChatInventory"),nodeTranscript:o(e=>`/v1/nodes/${e}/transcript`,"nodeTranscript"),nodeContext:o(e=>`/v1/nodes/${e}/context`,"nodeContext"),nodeArtifacts:o(e=>`/v1/nodes/${e}/artifacts`,"nodeArtifacts"),nodeReports:o(e=>`/v1/nodes/${e}/reports`,"nodeReports"),nodeResult:o(e=>`/v1/nodes/${e}/result`,"nodeResult"),nodeJobs:o(e=>`/v1/nodes/${e}/jobs`,"nodeJobs"),nodeJob:o((e,n)=>`/v1/nodes/${e}/jobs/${n}`,"nodeJob"),nodeMessages:o(e=>`/v1/nodes/${e}/messages`,"nodeMessages"),nodeInterrupt:o(e=>`/v1/nodes/${e}/interrupt`,"nodeInterrupt"),nodeFork:o(e=>`/v1/nodes/${e}/fork`,"nodeFork"),nodeRevive:o(e=>`/v1/nodes/${e}/revive`,"nodeRevive"),nodeRelaunchRoot:o(e=>`/v1/nodes/${e}/relaunch-root`,"nodeRelaunchRoot"),nodeBrokerSessionBound:o(e=>`/v1/nodes/${e}/broker/session-bound`,"nodeBrokerSessionBound"),nodeBrokerSettle:o(e=>`/v1/nodes/${e}/broker/settle`,"nodeBrokerSettle"),nodeBrokerParkComplete:o(e=>`/v1/nodes/${e}/broker/park-complete`,"nodeBrokerParkComplete"),nodeBrokerParkActivity:o(e=>`/v1/nodes/${e}/broker/park-activity`,"nodeBrokerParkActivity"),nodeBrokerTelemetry:o(e=>`/v1/nodes/${e}/broker/telemetry`,"nodeBrokerTelemetry"),nodeMailClaim:o(e=>`/v1/nodes/${e}/mail/claim`,"nodeMailClaim"),nodeMailAcknowledge:o(e=>`/v1/nodes/${e}/mail/acknowledge`,"nodeMailAcknowledge"),nodeBrokerModel:o(e=>`/v1/nodes/${e}/broker/model`,"nodeBrokerModel"),nodeBrokerExtensionState:o(e=>`/v1/nodes/${e}/broker/extension-state`,"nodeBrokerExtensionState"),nodeBrokerGeneratedName:o(e=>`/v1/nodes/${e}/broker/generated-name`,"nodeBrokerGeneratedName"),nodeBrokerPersonaAck:o(e=>`/v1/nodes/${e}/broker/persona-ack`,"nodeBrokerPersonaAck"),brokerTurn:o(e=>`/v1/broker/${e}/turn`,"brokerTurn"),brokerProviderRetry:o(e=>`/v1/broker/${e}/provider-retry`,"brokerProviderRetry"),brokerFault:o(e=>`/v1/broker/${e}/fault`,"brokerFault"),brokerRecovery:o(e=>`/v1/broker/${e}/recovery`,"brokerRecovery"),nodeFault:o(e=>`/v1/nodes/${e}/fault`,"nodeFault"),nodeClose:o(e=>`/v1/nodes/${e}/close`,"nodeClose"),nodeRecycle:o(e=>`/v1/nodes/${e}/recycle`,"nodeRecycle"),nodeDemote:o(e=>`/v1/nodes/${e}/demote`,"nodeDemote"),nodePromote:o(e=>`/v1/nodes/${e}/promote`,"nodePromote"),nodeYield:o(e=>`/v1/nodes/${e}/yield`,"nodeYield"),nodeWait:o(e=>`/v1/nodes/${e}/wait`,"nodeWait"),nodeConfig:o(e=>`/v1/nodes/${e}/config`,"nodeConfig"),nodeWorktreeClose:o(e=>`/v1/nodes/${e}/worktree/close`,"nodeWorktreeClose"),nodeWorktreeAbandon:o(e=>`/v1/nodes/${e}/worktree/abandon`,"nodeWorktreeAbandon"),quarantinedWorktrees:o(()=>"/v1/worktrees/quarantined","quarantinedWorktrees"),nodeAttach:o(e=>`/v1/nodes/${e}/attach`,"nodeAttach"),focuses:o(()=>"/v1/focuses","focuses"),focusByNode:o(()=>"/v1/focuses/by-node","focusByNode"),focusByPane:o(()=>"/v1/focuses/by-pane","focusByPane"),focus:o(e=>`/v1/focuses/${e}`,"focus"),nodeSubscriptions:o(e=>`/v1/nodes/${e}/subscriptions`,"nodeSubscriptions"),nodeSubscription:o((e,n)=>`/v1/nodes/${e}/subscriptions/${n}`,"nodeSubscription"),crons:o(()=>"/v1/crons","crons"),cron:o(e=>`/v1/crons/${e}`,"cron"),cronPause:o(e=>`/v1/crons/${e}/pause`,"cronPause"),cronResume:o(e=>`/v1/crons/${e}/resume`,"cronResume"),cronRun:o(e=>`/v1/crons/${e}/run`,"cronRun"),cronsPoke:o(()=>"/v1/crons/poke","cronsPoke"),canvasAttention:o(()=>"/v1/canvas/attention","canvasAttention"),canvasAttentionCounts:o(()=>"/v1/canvas/attention/counts","canvasAttentionCounts"),canvasHistorySearch:o(()=>"/v1/canvas/history/search","canvasHistorySearch"),canvasHistoryGrep:o(()=>"/v1/canvas/history/grep","canvasHistoryGrep"),canvasHistoryRead:o(()=>"/v1/canvas/history/read","canvasHistoryRead"),canvasHistoryStats:o(()=>"/v1/canvas/history/stats","canvasHistoryStats"),canvasSnapshot:o(()=>"/v1/canvas/snapshot","canvasSnapshot"),canvasRoster:o(()=>"/v1/canvas/roster","canvasRoster"),canvasGraph:o(()=>"/v1/canvas/graph","canvasGraph"),canvasPrune:o(()=>"/v1/canvas/prune","canvasPrune"),humanReviews:o(()=>"/v1/human/reviews","humanReviews"),humanReview:o(e=>`/v1/human/reviews/${e}`,"humanReview"),humanReviewSubmit:o(e=>`/v1/human/reviews/${e}/submit`,"humanReviewSubmit"),humanReviewCancel:o(e=>`/v1/human/reviews/${e}/cancel`,"humanReviewCancel"),humanReviewDocument:o(e=>`/v1/human/reviews/${e}/document`,"humanReviewDocument"),humanReviewComments:o(e=>`/v1/human/reviews/${e}/comments`,"humanReviewComments"),humanReviewCommentEvents:o(e=>`/v1/human/reviews/${e}/comment-events`,"humanReviewCommentEvents"),humanReviewCommentRanges:o(e=>`/v1/human/reviews/${e}/comment-ranges`,"humanReviewCommentRanges"),humanComment:o(e=>`/v1/human/comments/${e}`,"humanComment"),humanCommentEdit:o(e=>`/v1/human/comments/${e}/edit`,"humanCommentEdit"),humanCommentResolve:o(e=>`/v1/human/comments/${e}/resolve`,"humanCommentResolve"),humanCommentReopen:o(e=>`/v1/human/comments/${e}/reopen`,"humanCommentReopen"),humanCommentDelete:o(e=>`/v1/human/comments/${e}/delete`,"humanCommentDelete"),humanCommentFork:o(e=>`/v1/human/comments/${e}/fork`,"humanCommentFork"),humanInbox:o(()=>"/v1/human/inbox","humanInbox"),humanInboxTicket:o(e=>`/v1/human/inbox/${e}`,"humanInboxTicket"),humanInboxRespond:o(e=>`/v1/human/inbox/${e}/respond`,"humanInboxRespond"),humanInboxProgress:o(e=>`/v1/human/inbox/${e}/progress`,"humanInboxProgress"),humanInboxResponse:o(e=>`/v1/human/inbox/${e}/response`,"humanInboxResponse"),humanInboxCancel:o(e=>`/v1/human/inbox/${e}/cancel`,"humanInboxCancel"),humanInboxFeedbackResolve:o((e,n)=>`/v1/human/inbox/${e}/feedback-comments/${n}/resolve`,"humanInboxFeedbackResolve"),humanRequests:o(()=>"/v1/human/requests","humanRequests"),humanRequest:o(e=>`/v1/human/requests/${e}`,"humanRequest"),humanRequestReplace:o(e=>`/v1/human/requests/${e}/replace`,"humanRequestReplace"),humanRequestRespond:o(e=>`/v1/human/requests/${e}/respond`,"humanRequestRespond"),humanRequestDismiss:o(e=>`/v1/human/requests/${e}/dismiss`,"humanRequestDismiss"),humanRequestCancel:o(e=>`/v1/human/requests/${e}/cancel`,"humanRequestCancel"),profiles:o(()=>"/v1/profiles","profiles"),profile:o(e=>`/v1/profiles/${e}`,"profile"),profilePause:o(e=>`/v1/profiles/${e}/pause`,"profilePause"),profileResume:o(e=>`/v1/profiles/${e}/resume`,"profileResume"),profileMetadata:o(e=>`/v1/profiles/${e}/metadata`,"profileMetadata"),modelAuths:o(()=>"/v1/model-auth","modelAuths"),modelAuthReadiness:o(()=>"/v1/model-auth/readiness","modelAuthReadiness"),modelAuth:o(e=>`/v1/model-auth/${e}`,"modelAuth"),filePeek:o(()=>"/v1/files/peek","filePeek"),memoryResolve:o(()=>"/v1/memory/resolve","memoryResolve")};export{a as API_VERSION,t as routes};
@@ -1 +1 @@
1
- var z=Object.defineProperty;var a=(s,i)=>z(s,"name",{value:i,configurable:!0});import{beginFrameTelem as Q,navLabel as B,nodeGlyph as U,truncate as X,tokensCell as Y,cycleBadge as Z,askBadge as j,activityCell as nn,fillWidth as I,RESET as m,DIM as tn,GREEN as en}from"../../../core/canvas/nav-render.js";const on=34,sn=40;import{RemoteCanvasSource as an}from"../../../core/canvas/remote-canvas-source.js";import{cronWaitSummary as cn}from"./cron-wait.js";import{bashJobsWaitSummary as rn}from"./bash-jobs.js";import{reviewWaitSummary as dn}from"./review-wait.js";const un=12,fn=6,N=22;function A(s,i){return s.length>i?`${s.slice(0,i-1)}\u2026`:s+" ".repeat(i-s.length)}a(A,"nameCell");function ln(s,i){return s.length>=i?s.slice(0,i):" ".repeat(i-s.length)+s}a(ln,"padStartVisible");async function yn(s,i,c,h,x=[],v=[],H=[]){const k=h instanceof an;Q();const b=new Map,_=new Map,M=new Map,l=a(n=>{const t=b.get(n);if(t!==void 0)return t;const e=h.getNode(n).catch(()=>null);return b.set(n,e),e},"node"),p=a(n=>{const t=_.get(n);if(t!==void 0)return t;const e=(async()=>{const o=await h.subscriptionsOf(n).catch(()=>[]),f=[];for(const d of o)(await l(d.node_id))?.kind!=="human"&&f.push(d.node_id);return f})();return _.set(n,e),e},"convoChildIds"),S=a(n=>{const t=M.get(n);if(t!==void 0)return t;const e=h.subscribersOf(n).then(o=>o[0]?.node_id).catch(()=>{});return M.set(n,e),e},"managerOf"),D=a(async n=>{const t=[];for(const e of await p(n)){const o=(await l(e))?.status;(o==="active"||o==="idle")&&t.push(e)}return t},"liveReports"),F=a(async n=>{let t=n;const e=new Set([t]);for(;;){const o=await S(t);if(o===void 0||e.has(o))break;e.add(o),t=o}return t},"climbRoot"),R=new Map,P=a(async n=>{const t=new Set,e=a(async o=>{const f=(await l(o))?.status==="active";if(t.has(o))return f?1:0;t.add(o);let d=0;for(const y of await p(o))d+=await e(y);return R.set(o,d),d+(f?1:0)},"visit");await e(n)},"computeActivity"),T=a(async n=>{if(n===null||n.mode!=="orchestrator")return"";const t=(await p(n.node_id)).length;return t>0?` ${tn}\u2933${t}${m}`:""},"childBadgeFor"),G=a(n=>{if(n===null||n.status==="active")return"";const t=R.get(n.node_id)??0;return t>0?` ${en}\u21E3${t}${m}`:""},"liveBelowBadgeFor"),$=c?.muted??(n=>n),K=c?.faint??(n=>n);await P(await F(s));const r=await S(s),w=await D(s),g=[...r!==void 0?[r]:[],...w],L=await Promise.all(g.map(n=>l(n))),V=g.length>0?Math.min(N,Math.max(...g.map((n,t)=>B(L[t]??null,n).length))):N,W=a(async(n,t)=>{const e=await l(n),o=A(B(e,n),V),f=K(A(e?.kind??"",un)),d=$(ln(Y(n,k),fn)),y=`${Z(e)}${await T(e)}${G(e)}${j(n,i)}${nn(n,e,k)}`,q=` ${t} ${U(e)} ${o} ${f} ${d}${y}`;return X(q)},"row"),J=[...r!==void 0?[r]:[],...w],u=[];r!==void 0&&u.push({key:`node:${r}`,kind:"node",nodeId:r,line:await W(r,"\u2191")});for(const n of w)u.push({key:`node:${n}`,kind:"node",nodeId:n,line:await W(n,"\u2193")});for(const n of H){const t=c?c.info("\u270E"):"\u270E",e=dn(n,Math.max(8,I()-sn));u.push({key:`review:${n.review_id}`,kind:"review",companionNodeId:n.companion_node_id,line:` ${t} ${$(`${e} \xB7 \u21B5 companion`)}${m}`})}const C=v.length===1?" \xB7 x stop":"",E=rn(v,Date.now(),I()-(on+C.length));if(E!==void 0){const n=c?c.info("\u2699"):"\u2699";u.push({key:"bash",kind:"bash",line:` ${n} ${$(`${E} \xB7 \u21B5 details${C}`)}${m}`})}const O=cn(x);if(O!==void 0){const n=c?c.info("\u25F7"):"\u25F7";u.push({key:"crons",kind:"crons",line:` ${n} ${$(`${O} \xB7 \u21B5 details`)}${m}`})}return{reports:u.map(n=>n.line),reportIds:J,items:u}}a(yn,"buildCanvasPanelLines");export{yn as buildCanvasPanelLines};
1
+ var z=Object.defineProperty;var i=(s,a)=>z(s,"name",{value:a,configurable:!0});import{navLabel as B,nodeGlyph as Q,truncate as U,tokensCell as X,cycleBadge as Y,askBadge as Z,activityCell as j,fillWidth as I,RESET as m,DIM as nn,GREEN as tn}from"../../../core/canvas/nav-render.js";const en=34,on=40;import{RemoteCanvasSource as sn}from"../../../core/canvas/remote-canvas-source.js";import{cronWaitSummary as an}from"./cron-wait.js";import{bashJobsWaitSummary as cn}from"./bash-jobs.js";import{reviewWaitSummary as rn}from"./review-wait.js";const dn=12,un=6,N=22;function A(s,a){return s.length>a?`${s.slice(0,a-1)}\u2026`:s+" ".repeat(a-s.length)}i(A,"nameCell");function fn(s,a){return s.length>=a?s.slice(0,a):" ".repeat(a-s.length)+s}i(fn,"padStartVisible");async function gn(s,a,c,h,x=[],v=[],H=[]){const k=h instanceof sn,_=new Map,b=new Map,M=new Map,l=i(n=>{const t=_.get(n);if(t!==void 0)return t;const e=h.getNode(n).catch(()=>null);return _.set(n,e),e},"node"),p=i(n=>{const t=b.get(n);if(t!==void 0)return t;const e=(async()=>{const o=await h.subscriptionsOf(n).catch(()=>[]),f=[];for(const d of o)(await l(d.node_id))?.kind!=="human"&&f.push(d.node_id);return f})();return b.set(n,e),e},"convoChildIds"),S=i(n=>{const t=M.get(n);if(t!==void 0)return t;const e=h.subscribersOf(n).then(o=>o[0]?.node_id).catch(()=>{});return M.set(n,e),e},"managerOf"),D=i(async n=>{const t=[];for(const e of await p(n)){const o=(await l(e))?.status;(o==="active"||o==="idle")&&t.push(e)}return t},"liveReports"),P=i(async n=>{let t=n;const e=new Set([t]);for(;;){const o=await S(t);if(o===void 0||e.has(o))break;e.add(o),t=o}return t},"climbRoot"),R=new Map,F=i(async n=>{const t=new Set,e=i(async o=>{const f=(await l(o))?.status==="active";if(t.has(o))return f?1:0;t.add(o);let d=0;for(const y of await p(o))d+=await e(y);return R.set(o,d),d+(f?1:0)},"visit");await e(n)},"computeActivity"),G=i(async n=>{if(n===null||n.mode!=="orchestrator")return"";const t=(await p(n.node_id)).length;return t>0?` ${nn}\u2933${t}${m}`:""},"childBadgeFor"),K=i(n=>{if(n===null||n.status==="active")return"";const t=R.get(n.node_id)??0;return t>0?` ${tn}\u21E3${t}${m}`:""},"liveBelowBadgeFor"),$=c?.muted??(n=>n),L=c?.faint??(n=>n);await F(await P(s));const r=await S(s),w=await D(s),g=[...r!==void 0?[r]:[],...w],T=await Promise.all(g.map(n=>l(n))),V=g.length>0?Math.min(N,Math.max(...g.map((n,t)=>B(T[t]??null,n).length))):N,W=i(async(n,t)=>{const e=await l(n),o=A(B(e,n),V),f=L(A(e?.kind??"",dn)),d=$(fn(X(e,k),un)),y=`${Y(e)}${await G(e)}${K(e)}${Z(n,a)}${j(e,k)}`,q=` ${t} ${Q(e)} ${o} ${f} ${d}${y}`;return U(q)},"row"),J=[...r!==void 0?[r]:[],...w],u=[];r!==void 0&&u.push({key:`node:${r}`,kind:"node",nodeId:r,line:await W(r,"\u2191")});for(const n of w)u.push({key:`node:${n}`,kind:"node",nodeId:n,line:await W(n,"\u2193")});for(const n of H){const t=c?c.info("\u270E"):"\u270E",e=rn(n,Math.max(8,I()-on));u.push({key:`review:${n.review_id}`,kind:"review",companionNodeId:n.companion_node_id,line:` ${t} ${$(`${e} \xB7 \u21B5 companion`)}${m}`})}const C=v.length===1?" \xB7 x stop":"",E=cn(v,Date.now(),I()-(en+C.length));if(E!==void 0){const n=c?c.info("\u2699"):"\u2699";u.push({key:"bash",kind:"bash",line:` ${n} ${$(`${E} \xB7 \u21B5 details${C}`)}${m}`})}const O=an(x);if(O!==void 0){const n=c?c.info("\u25F7"):"\u25F7";u.push({key:"crons",kind:"crons",line:` ${n} ${$(`${O} \xB7 \u21B5 details`)}${m}`})}return{reports:u.map(n=>n.line),reportIds:J,items:u}}i(gn,"buildCanvasPanelLines");export{gn as buildCanvasPanelLines};
@@ -33,11 +33,6 @@ export declare class GraphOverlay implements Component {
33
33
  * commands against a remote graph row. See the file header. */
34
34
  private readonly remote;
35
35
  constructor(tui: TUI, self: string, getAsks: () => Record<string, number>, palette: AttachPalette, bindings: BindingResolution<BindingId>, source: CanvasSource, role?: ClientRole, onRefreshFailure?: (cause?: unknown) => void, onNotice?: (message: string) => void);
36
- /** The tmux-focus set for `isAttached`, fetched via crtrd (was nav-model's
37
- * focusedNodeIds → listFocuses db read). Empty for a remote source (a remote
38
- * node id may collide with a local focus row); a failed API call degrades to
39
- * empty rather than throwing the whole snapshot. */
40
- private fetchFocused;
41
36
  setBindings(bindings: BindingResolution<BindingId>): void;
42
37
  private matches;
43
38
  private hint;
@@ -53,6 +48,12 @@ export declare class GraphOverlay implements Component {
53
48
  /** Repaint if shown (the low-rate ask poll calls this). */
54
49
  refresh(): void;
55
50
  invalidate(): void;
51
+ /** Local: ONE `/v1/canvas/graph` read supplies the display rows, both edge
52
+ * directions, and the focus set — no enriched node list, no roster call, no
53
+ * separate focus query. Remote: unchanged — a remote canvas exposes only the
54
+ * per-node `CanvasSource` reads, and its focus set stays empty (a remote node
55
+ * id may collide with a local focus row). */
56
+ private fetchInput;
56
57
  private buildSnapshot;
57
58
  /** Fold state is presentation-only. Reproject the visible DFS from the fully
58
59
  * fetched topology so h/l never cross the daemon boundary. The explicit stack
@@ -1 +1 @@
1
- var N=Object.defineProperty;var $=(S,t)=>N(S,"name",{value:t,configurable:!0});import{execFile as O}from"node:child_process";import{matchesKey as P,truncateToWidth as C}from"@earendil-works/pi-tui";import{formatBinding as H,matchesPiTuiInput as B}from"../../../core/keybindings/index.js";import{fullName as L}from"../../../core/canvas/labels.js";import{faultSummary as F}from"../../../core/canvas/status-glyph.js";import{RemoteCanvasSource as G}from"../../../core/canvas/remote-canvas-source.js";import{cliClient as K}from"../../../commands/api-client.js";import{statusRank as M}from"../../../core/canvas/node-order.js";import{beginFrameTelem as E,navLabel as W,nodeGlyph as j,tokensCell as Y,cycleBadge as D,askBadge as V,activityCell as U,shortId as A,visibleWidth as _,fillBar as k,fillWidth as q,truncate as X,isAttached as z,VIEWPORT_FALLBACK_ROWS as J,DIM as R,RESET as p,BOLD as T,YELLOW as Q,REVERSE as Z,BG_ATTACHED as tt,GREEN as et}from"../../../core/canvas/nav-render.js";const st=.72,it={anchor:"center",width:"72%",minWidth:48,maxHeight:"72%",margin:1},rt=[["crtr.graph.dismiss","dismiss"],["crtr.graph.focus","focus"],["crtr.graph.revive","revive"],["crtr.graph.close-subtree","close"],["crtr.graph.focus-manager","manager"]],nt=[["crtr.graph.dismiss","dismiss"]],ot=[["crtr.graph.down","down"],["crtr.graph.up","up"],["crtr.graph.first","first"],["crtr.graph.last","last"],["crtr.graph.collapse-or-manager","fold/manager"],["crtr.graph.expand-or-child","expand/child"]];class $t{static{$(this,"GraphOverlay")}tui;self;getAsks;palette;bindings;source;role;onRefreshFailure;onNotice;handle;userExpanded=new Set;userCollapsed=new Set;folds={userExpanded:this.userExpanded,userCollapsed:this.userCollapsed};cursorId;scrollTop=0;pendingConfirm;snapshot;snapshotSeq=0;remote;constructor(t,s,e,r,o,h,d="controller",l=()=>{},n=()=>{}){this.tui=t,this.self=s,this.getAsks=e,this.palette=r,this.bindings=o,this.source=h,this.role=d,this.onRefreshFailure=l,this.onNotice=n,this.remote=h instanceof G}async fetchFocused(){if(this.remote)return new Set;try{return new Set((await K().listFocuses()).map(t=>t.node_id))}catch{return new Set}}setBindings(t){this.bindings=t,this.handle!==void 0&&this.tui.requestRender()}matches(t,s){return B(this.bindings,t,s,(e,r)=>P(e,r))}hint(t){return t.flatMap(([s,e])=>this.bindings.gestures(s).length===0?[]:[`${H(this.bindings,s)} ${e}`])}fitHints(t,s){const r=[];let o=0;for(const h of this.hint(t)){const d=(r.length===0?0:3)+_(h);if(o+d>s)break;r.push(h),o+=d}return r.join(" \xB7 ")}isOpen(){return this.handle!==void 0}open(){this.handle===void 0&&(this.scrollTop=0,this.pendingConfirm=void 0,this.cursorId=this.self,this.handle=this.tui.showOverlay(this,it),this.refresh())}close(){this.handle!==void 0&&(this.pendingConfirm=void 0,this.handle.hide(),this.handle=void 0,this.tui.requestRender())}toggle(){this.handle===void 0?this.open():this.close()}refresh(){if(this.handle===void 0)return;const t=++this.snapshotSeq;this.buildSnapshot().then(s=>{t===this.snapshotSeq&&(this.snapshot=s,this.tui.requestRender())}).catch(s=>{this.onRefreshFailure(s),this.tui.requestRender()})}invalidate(){this.refresh()}async buildSnapshot(){E();const[t,s]=await Promise.all([this.source.listNodes().catch(()=>[]),this.fetchFocused()]),e=new Map(t.map(i=>[i.node_id,i])),r=new Map,o=new Map,h=new Map,d=new Map,l=$(async i=>{const a=r.get(i);if(a!==void 0)return a;let f;try{f=await this.source.subscriptionsOf(i)}catch{f=[]}const w=f.map(g=>g.node_id).filter(g=>e.get(g)?.kind!=="human");return r.set(i,w),w},"children"),n=$(async i=>{if(h.has(i))return h.get(i);let a;try{a=(await this.source.subscribersOf(i))[0]?.node_id}catch{a=void 0}return h.set(i,a),a},"manager"),c=$(async()=>{let i=this.self;const a=new Set([i]);for(;;){const f=await n(i);if(f===void 0||a.has(f))break;a.add(f),i=f}return i},"climbRoot"),u=$(async i=>{const a=o.get(i);if(a!==void 0)return a;const f=[...await l(i)];return f.sort((w,g)=>M(e.get(w)?.status)-M(e.get(g)?.status)),o.set(i,f),f},"sortedChildren"),v=new Set,m=new Set,x=$(async i=>{const a=e.get(i)?.status==="active";if(m.has(i))return{active:a?1:0,reveal:a||i===this.self};m.add(i);let f=0,w=!1;for(const g of await l(i)){const y=await x(g);f+=y.active,y.reveal&&(w=!0)}return d.set(i,f),w&&v.add(i),{active:f+(a?1:0),reveal:w||a||i===this.self}},"visitActivity"),I=await c();await x(I),await Promise.all([...r.keys()].map(i=>u(i)));const b={root:I,rows:[],autoExpanded:v,activeBelow:d,nodes:e,childIds:r,sortedChildIds:o,managerOf:h,focused:s};return b.rows=this.projectRows(b),b}projectRows(t){const s=[],e=new Set,r=[{id:t.root,prefix:"",isRoot:!0,isLast:!0}];for(;r.length>0;){const{id:o,prefix:h,isRoot:d,isLast:l}=r.pop(),n=d?"":l?"\u2514\u2500 ":"\u251C\u2500 ";if(e.has(o)){s.push({id:o,hasKids:!1,isSelf:o===this.self,branch:h+n,cycle:!0,collapsed:!1});continue}e.add(o);const c=t.sortedChildIds.get(o)??[],u=this.folds.userExpanded.has(o)?!1:this.folds.userCollapsed.has(o)?!0:!t.autoExpanded.has(o);if(s.push({id:o,hasKids:c.length>0,isSelf:o===this.self,branch:h+n,cycle:!1,collapsed:u}),u)continue;const v=d?"":h+(l?" ":"\u2502 ");for(let m=c.length-1;m>=0;m--)r.push({id:c[m],prefix:v,isRoot:!1,isLast:m===c.length-1})}return s}repaintFolds(){this.snapshot!==void 0&&(this.snapshot.rows=this.projectRows(this.snapshot)),this.tui.requestRender()}renderSnapshotRow(t,s,e,r){const o=$((g,y)=>e?k(g,q(),Z):y?k(g,q(),tt):X(g),"wrap");if(s.cycle){const g=`${s.branch} ${R}\u21BA ${A(s.id)}${p}`;return o(g,!1)}const h=t.nodes.get(s.id)??null,d=j(h),l=W(h,s.id),n=s.isSelf?`${T}${l}${p}`:l,c=`${R}${h?.kind??""}${p}`,u=`${R}${Y(s.id,this.remote)}${p}`,v=s.hasKids&&s.collapsed,m=!e&&v?`${R}\u25B8${p} `:" ",x=D(h),I=t.childIds.get(s.id)?.length??0,b=h!==null&&I>0?` ${R}\u2933${I}${p}`:"",i=h!==null&&h.status!=="active"&&(t.activeBelow.get(h.node_id)??0)>0?` ${et}\u21E3${t.activeBelow.get(h.node_id)??0}${p}`:"",a=h?.fault??null,f=a!==null?` \xB7 ${F(a)}`:"",w=`${s.branch}${m}${d} ${n} ${c} ${u}${x}${b}${i}${V(s.id,r)}${U(s.id,h,this.remote)}${f}`;return o(w,z(s.id,h,t.focused,this.remote))}render(t){E();const s=this.getAsks(),e=this.snapshot?.rows??[];let r=e.findIndex(i=>i.id===this.cursorId);r<0&&(r=e.findIndex(i=>i.id===this.self),r<0&&(r=0)),this.cursorId=e[r]?.id??this.self;const o=process.stdout.rows??J,h=Math.max(3,Math.min(Math.floor(o*st),o-2)),d=Math.max(2,Math.min(e.length,h-2));let l=d;for(let i=0;i<4;i++){r<this.scrollTop&&(this.scrollTop=r),r>=this.scrollTop+l&&(this.scrollTop=r-l+1),this.scrollTop=Math.max(0,Math.min(this.scrollTop,Math.max(0,e.length-l)));const a=d-(this.scrollTop>0?1:0)-(this.scrollTop+l<e.length?1:0);if(a===l)break;l=Math.max(1,a)}const n=Math.min(e.length,this.scrollTop+l),c=[];this.scrollTop>0&&c.push(`${R} \u2191 ${this.scrollTop} more${p}`);for(let i=this.scrollTop;i<n;i++){const a=this.snapshot;c.push(a!==void 0?this.renderSnapshotRow(a,e[i],i===r,s):"")}for(n<e.length&&c.push(`${R} \u2193 ${e.length-n} more${p}`);c.length<d;)c.push("");const u=e.length>0?`${T}\u2317 canvas graph${p} ${R}(${r+1}/${e.length})${p}`:`${T}\u2317 canvas graph${p} ${R}(loading)${p}`,v=this.pendingConfirm!==void 0?`${Q}${this.pendingConfirm.label} ${T}${this.hint([["crtr.graph.confirm.accept","accept"],["crtr.graph.confirm.cancel","cancel"]]).join(" \xB7 ")}${p}`:`${R}${this.fitHints([...this.remote||this.role!=="controller"?nt:rt,...ot],Math.max(1,t-5))}${p}`,m=this.palette.border,x=Math.max(1,t-4),I=c.map(i=>`${m("\u2502")} ${C(i,x,"",!0)} ${m("\u2502")}`),b=this.palette.surface;return[this.borderRow("\u256D","\u256E",u,t),...I,this.borderRow("\u2570","\u256F",v,t)].map(b)}borderRow(t,s,e,r){const o=this.palette.border,h=Math.max(1,r-5),d=C(e,h,"\u2026"),l=Math.max(0,r-5-_(d));return`${o(`${t}\u2500`)} ${d} ${o("\u2500".repeat(l)+s)}`}handleInput(t){try{this.dispatch(t)}catch{}}dispatch(t){if(this.pendingConfirm!==void 0){if(this.matches("crtr.graph.confirm.accept",t)){const n=this.pendingConfirm.action;this.pendingConfirm=void 0,n()}else this.pendingConfirm=void 0;this.tui.requestRender();return}if(this.matches("crtr.graph.dismiss",t)){this.close();return}const s=this.snapshot,e=s?.rows??[];let r=e.findIndex(n=>n.id===this.cursorId);r<0&&(r=Math.max(0,e.findIndex(n=>n.id===this.self)));const o=e[r],h=$(n=>n!==void 0&&!n.cycle,"isSelectable"),d=$((n,c)=>{for(let u=n+c;u>=0&&u<e.length;u+=c)if(h(e[u]))return u;return n},"step"),l=$(n=>{const c=n===1?0:e.length-1;for(let u=c;u>=0&&u<e.length;u+=n)if(h(e[u]))return u;return r},"edge");if(this.matches("crtr.graph.down",t)){r=d(r,1),this.cursorId=e[r]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.up",t)){r=d(r,-1),this.cursorId=e[r]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.first",t)){this.cursorId=e[l(1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.last",t)){this.cursorId=e[l(-1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.collapse-or-manager",t)){if(o!==void 0&&o.hasKids&&!o.collapsed)this.userCollapsed.add(o.id),this.userExpanded.delete(o.id),this.repaintFolds();else{const n=s?.managerOf.get(this.cursorId??this.self);n!==void 0&&e.some(c=>c.id===n)&&(this.cursorId=n),this.tui.requestRender()}return}if(this.matches("crtr.graph.expand-or-child",t)){if(o!==void 0&&o.collapsed&&o.hasKids)this.userExpanded.add(o.id),this.userCollapsed.delete(o.id),this.repaintFolds();else if(o!==void 0&&o.hasKids){const n=s?.sortedChildIds.get(o.id)?.[0];n!==void 0&&(this.cursorId=n),this.tui.requestRender()}return}if(this.matches("crtr.graph.focus",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}this.cursorId!==void 0&&this.focusTarget(this.cursorId),this.close();return}if(this.matches("crtr.graph.revive",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot revive nodes");return}const n=this.cursorId,c=n===void 0?null:s?.nodes.get(n)??null;n!==void 0&&c!==null&&c.status!=="active"&&c.status!=="idle"&&(this.reviveTarget(n),this.close());return}if(this.matches("crtr.graph.focus-manager",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}const n=s?.managerOf.get(this.self);n!==void 0&&(this.focusTarget(n),this.close());return}if(this.matches("crtr.graph.close-subtree",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot close nodes");return}const n=this.cursorId??this.self,c=s?.nodes.get(n)??null,u=c!==null?L(c):A(n);this.pendingConfirm={label:`kill ${u}?`,action:$(()=>this.shellCrtr(["node","lifecycle","close","--node",n]),"action")},this.tui.requestRender();return}}focusTarget(t){const s=["surface","node","focus",t],e=process.env.TMUX_PANE;e!==void 0&&e!==""&&s.push("--pane",e),this.shellCrtr(s)}reviveTarget(t){this.shellCrtr(["node","lifecycle","revive",t],()=>this.focusTarget(t))}shellCrtr(t,s){try{O("crtr",t,r=>{r==null&&s?.()}).stdin?.end()}catch{}}}export{$t as GraphOverlay};
1
+ var q=Object.defineProperty;var p=(m,e)=>q(m,"name",{value:e,configurable:!0});import{execFile as N}from"node:child_process";import{matchesKey as O,truncateToWidth as C}from"@earendil-works/pi-tui";import{formatBinding as P,matchesPiTuiInput as H}from"../../../core/keybindings/index.js";import{fullName as B}from"../../../core/canvas/labels.js";import{faultSummary as L}from"../../../core/canvas/status-glyph.js";import{RemoteCanvasSource as G}from"../../../core/canvas/remote-canvas-source.js";import{cliClient as F}from"../../../commands/api-client.js";import{statusRank as S}from"../../../core/canvas/node-order.js";import{navLabel as K,nodeGlyph as W,tokensCell as j,cycleBadge as Y,askBadge as D,activityCell as V,shortId as M,visibleWidth as E,fillBar as k,fillWidth as A,truncate as z,isAttached as U,VIEWPORT_FALLBACK_ROWS as X,DIM as v,RESET as g,BOLD as T,YELLOW as J,REVERSE as Q,BG_ATTACHED as Z,GREEN as tt}from"../../../core/canvas/nav-render.js";const et=.72,st={anchor:"center",width:"72%",minWidth:48,maxHeight:"72%",margin:1},it=[["crtr.graph.dismiss","dismiss"],["crtr.graph.focus","focus"],["crtr.graph.revive","revive"],["crtr.graph.close-subtree","close"],["crtr.graph.focus-manager","manager"]],nt=[["crtr.graph.dismiss","dismiss"]],rt=[["crtr.graph.down","down"],["crtr.graph.up","up"],["crtr.graph.first","first"],["crtr.graph.last","last"],["crtr.graph.collapse-or-manager","fold/manager"],["crtr.graph.expand-or-child","expand/child"]];function ot(m){return{node_id:m.node_id,name:m.name,kind:m.kind,description:m.description??void 0,cycles:m.cycles??void 0,status:m.status,frozen_at:m.frozen_at,pi_pid:m.pi_pid,telemetry_context_tokens:m.telemetry_context_tokens,telemetry_last_activity:m.telemetry_last_activity,fault:m.fault??null,streaming:m.streaming}}p(ot,"graphRow");class $t{static{p(this,"GraphOverlay")}tui;self;getAsks;palette;bindings;source;role;onRefreshFailure;onNotice;handle;userExpanded=new Set;userCollapsed=new Set;folds={userExpanded:this.userExpanded,userCollapsed:this.userCollapsed};cursorId;scrollTop=0;pendingConfirm;snapshot;snapshotSeq=0;remote;constructor(e,s,i,t,n,c,d="controller",l=()=>{},r=()=>{}){this.tui=e,this.self=s,this.getAsks=i,this.palette=t,this.bindings=n,this.source=c,this.role=d,this.onRefreshFailure=l,this.onNotice=r,this.remote=c instanceof G}setBindings(e){this.bindings=e,this.handle!==void 0&&this.tui.requestRender()}matches(e,s){return H(this.bindings,e,s,(i,t)=>O(i,t))}hint(e){return e.flatMap(([s,i])=>this.bindings.gestures(s).length===0?[]:[`${P(this.bindings,s)} ${i}`])}fitHints(e,s){const t=[];let n=0;for(const c of this.hint(e)){const d=(t.length===0?0:3)+E(c);if(n+d>s)break;t.push(c),n+=d}return t.join(" \xB7 ")}isOpen(){return this.handle!==void 0}open(){this.handle===void 0&&(this.scrollTop=0,this.pendingConfirm=void 0,this.cursorId=this.self,this.handle=this.tui.showOverlay(this,st),this.refresh())}close(){this.handle!==void 0&&(this.pendingConfirm=void 0,this.handle.hide(),this.handle=void 0,this.tui.requestRender())}toggle(){this.handle===void 0?this.open():this.close()}refresh(){if(this.handle===void 0)return;const e=++this.snapshotSeq;this.buildSnapshot().then(s=>{e===this.snapshotSeq&&(this.snapshot=s,this.tui.requestRender())}).catch(s=>{this.onRefreshFailure(s),this.tui.requestRender()})}invalidate(){this.refresh()}async fetchInput(){if(this.remote){const t=await this.source.listNodes().catch(()=>[]);return{nodes:new Map(t.map(n=>[n.node_id,n])),subscriptions:p(async n=>(await this.source.subscriptionsOf(n)).map(c=>c.node_id),"subscriptions"),subscribers:p(async n=>(await this.source.subscribersOf(n)).map(c=>c.node_id),"subscribers"),focused:new Set}}const e=await F().canvasGraph(),s=new Map,i=new Map;for(const t of e.edges){const n=s.get(t.from_id);n===void 0?s.set(t.from_id,[t.to_id]):n.push(t.to_id);const c=i.get(t.to_id);c===void 0?i.set(t.to_id,[t.from_id]):c.push(t.from_id)}return{nodes:new Map(e.nodes.map(t=>[t.node_id,ot(t)])),subscriptions:p(t=>Promise.resolve(s.get(t)??[]),"subscriptions"),subscribers:p(t=>Promise.resolve(i.get(t)??[]),"subscribers"),focused:new Set(e.focused_node_ids)}}async buildSnapshot(){const e=await this.fetchInput(),{nodes:s,focused:i}=e,t=new Map,n=new Map,c=new Map,d=new Map,l=p(async o=>{const a=t.get(o);if(a!==void 0)return a;let f;try{f=await e.subscriptions(o)}catch{f=[]}const b=f.filter(w=>s.get(w)?.kind!=="human");return t.set(o,b),b},"children"),r=p(async o=>{if(c.has(o))return c.get(o);let a;try{a=(await e.subscribers(o))[0]}catch{a=void 0}return c.set(o,a),a},"manager"),h=p(async()=>{let o=this.self;const a=new Set([o]);for(;;){const f=await r(o);if(f===void 0||a.has(f))break;a.add(f),o=f}return o},"climbRoot"),u=p(async o=>{const a=n.get(o);if(a!==void 0)return a;const f=[...await l(o)];return f.sort((b,w)=>S(s.get(b)?.status)-S(s.get(w)?.status)),n.set(o,f),f},"sortedChildren"),R=new Set,$=new Set,y=p(async o=>{const a=s.get(o)?.status==="active";if($.has(o))return{active:a?1:0,reveal:a||o===this.self};$.add(o);let f=0,b=!1;for(const w of await l(o)){const x=await y(w);f+=x.active,x.reveal&&(b=!0)}return d.set(o,f),b&&R.add(o),{active:f+(a?1:0),reveal:b||a||o===this.self}},"visitActivity"),I=await h();await y(I),await Promise.all([...t.keys()].map(o=>u(o)));const _={root:I,rows:[],autoExpanded:R,activeBelow:d,nodes:s,childIds:t,sortedChildIds:n,managerOf:c,focused:i};return _.rows=this.projectRows(_),_}projectRows(e){const s=[],i=new Set,t=[{id:e.root,prefix:"",isRoot:!0,isLast:!0}];for(;t.length>0;){const{id:n,prefix:c,isRoot:d,isLast:l}=t.pop(),r=d?"":l?"\u2514\u2500 ":"\u251C\u2500 ";if(i.has(n)){s.push({id:n,hasKids:!1,isSelf:n===this.self,branch:c+r,cycle:!0,collapsed:!1});continue}i.add(n);const h=e.sortedChildIds.get(n)??[],u=this.folds.userExpanded.has(n)?!1:this.folds.userCollapsed.has(n)?!0:!e.autoExpanded.has(n);if(s.push({id:n,hasKids:h.length>0,isSelf:n===this.self,branch:c+r,cycle:!1,collapsed:u}),u)continue;const R=d?"":c+(l?" ":"\u2502 ");for(let $=h.length-1;$>=0;$--)t.push({id:h[$],prefix:R,isRoot:!1,isLast:$===h.length-1})}return s}repaintFolds(){this.snapshot!==void 0&&(this.snapshot.rows=this.projectRows(this.snapshot)),this.tui.requestRender()}renderSnapshotRow(e,s,i,t){const n=p((w,x)=>i?k(w,A(),Q):x?k(w,A(),Z):z(w),"wrap");if(s.cycle){const w=`${s.branch} ${v}\u21BA ${M(s.id)}${g}`;return n(w,!1)}const c=e.nodes.get(s.id)??null,d=W(c),l=K(c,s.id),r=s.isSelf?`${T}${l}${g}`:l,h=`${v}${c?.kind??""}${g}`,u=`${v}${j(c,this.remote)}${g}`,R=s.hasKids&&s.collapsed,$=!i&&R?`${v}\u25B8${g} `:" ",y=Y(c),I=e.childIds.get(s.id)?.length??0,_=c!==null&&I>0?` ${v}\u2933${I}${g}`:"",o=c!==null&&c.status!=="active"&&(e.activeBelow.get(c.node_id)??0)>0?` ${tt}\u21E3${e.activeBelow.get(c.node_id)??0}${g}`:"",a=c?.fault??null,f=a!==null?` \xB7 ${L(a)}`:"",b=`${s.branch}${$}${d} ${r} ${h} ${u}${y}${_}${o}${D(s.id,t)}${V(c,this.remote)}${f}`;return n(b,U(s.id,c,e.focused,this.remote))}render(e){const s=this.getAsks(),i=this.snapshot?.rows??[];let t=i.findIndex(o=>o.id===this.cursorId);t<0&&(t=i.findIndex(o=>o.id===this.self),t<0&&(t=0)),this.cursorId=i[t]?.id??this.self;const n=process.stdout.rows??X,c=Math.max(3,Math.min(Math.floor(n*et),n-2)),d=Math.max(2,Math.min(i.length,c-2));let l=d;for(let o=0;o<4;o++){t<this.scrollTop&&(this.scrollTop=t),t>=this.scrollTop+l&&(this.scrollTop=t-l+1),this.scrollTop=Math.max(0,Math.min(this.scrollTop,Math.max(0,i.length-l)));const a=d-(this.scrollTop>0?1:0)-(this.scrollTop+l<i.length?1:0);if(a===l)break;l=Math.max(1,a)}const r=Math.min(i.length,this.scrollTop+l),h=[];this.scrollTop>0&&h.push(`${v} \u2191 ${this.scrollTop} more${g}`);for(let o=this.scrollTop;o<r;o++){const a=this.snapshot;h.push(a!==void 0?this.renderSnapshotRow(a,i[o],o===t,s):"")}for(r<i.length&&h.push(`${v} \u2193 ${i.length-r} more${g}`);h.length<d;)h.push("");const u=i.length>0?`${T}\u2317 canvas graph${g} ${v}(${t+1}/${i.length})${g}`:`${T}\u2317 canvas graph${g} ${v}(loading)${g}`,R=this.pendingConfirm!==void 0?`${J}${this.pendingConfirm.label} ${T}${this.hint([["crtr.graph.confirm.accept","accept"],["crtr.graph.confirm.cancel","cancel"]]).join(" \xB7 ")}${g}`:`${v}${this.fitHints([...this.remote||this.role!=="controller"?nt:it,...rt],Math.max(1,e-5))}${g}`,$=this.palette.border,y=Math.max(1,e-4),I=h.map(o=>`${$("\u2502")} ${C(o,y,"",!0)} ${$("\u2502")}`),_=this.palette.surface;return[this.borderRow("\u256D","\u256E",u,e),...I,this.borderRow("\u2570","\u256F",R,e)].map(_)}borderRow(e,s,i,t){const n=this.palette.border,c=Math.max(1,t-5),d=C(i,c,"\u2026"),l=Math.max(0,t-5-E(d));return`${n(`${e}\u2500`)} ${d} ${n("\u2500".repeat(l)+s)}`}handleInput(e){try{this.dispatch(e)}catch{}}dispatch(e){if(this.pendingConfirm!==void 0){if(this.matches("crtr.graph.confirm.accept",e)){const r=this.pendingConfirm.action;this.pendingConfirm=void 0,r()}else this.pendingConfirm=void 0;this.tui.requestRender();return}if(this.matches("crtr.graph.dismiss",e)){this.close();return}const s=this.snapshot,i=s?.rows??[];let t=i.findIndex(r=>r.id===this.cursorId);t<0&&(t=Math.max(0,i.findIndex(r=>r.id===this.self)));const n=i[t],c=p(r=>r!==void 0&&!r.cycle,"isSelectable"),d=p((r,h)=>{for(let u=r+h;u>=0&&u<i.length;u+=h)if(c(i[u]))return u;return r},"step"),l=p(r=>{const h=r===1?0:i.length-1;for(let u=h;u>=0&&u<i.length;u+=r)if(c(i[u]))return u;return t},"edge");if(this.matches("crtr.graph.down",e)){t=d(t,1),this.cursorId=i[t]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.up",e)){t=d(t,-1),this.cursorId=i[t]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.first",e)){this.cursorId=i[l(1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.last",e)){this.cursorId=i[l(-1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.collapse-or-manager",e)){if(n!==void 0&&n.hasKids&&!n.collapsed)this.userCollapsed.add(n.id),this.userExpanded.delete(n.id),this.repaintFolds();else{const r=s?.managerOf.get(this.cursorId??this.self);r!==void 0&&i.some(h=>h.id===r)&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.expand-or-child",e)){if(n!==void 0&&n.collapsed&&n.hasKids)this.userExpanded.add(n.id),this.userCollapsed.delete(n.id),this.repaintFolds();else if(n!==void 0&&n.hasKids){const r=s?.sortedChildIds.get(n.id)?.[0];r!==void 0&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.focus",e)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}this.cursorId!==void 0&&this.focusTarget(this.cursorId),this.close();return}if(this.matches("crtr.graph.revive",e)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot revive nodes");return}const r=this.cursorId,h=r===void 0?null:s?.nodes.get(r)??null;r!==void 0&&h!==null&&h.status!=="active"&&h.status!=="idle"&&(this.reviveTarget(r),this.close());return}if(this.matches("crtr.graph.focus-manager",e)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}const r=s?.managerOf.get(this.self);r!==void 0&&(this.focusTarget(r),this.close());return}if(this.matches("crtr.graph.close-subtree",e)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot close nodes");return}const r=this.cursorId??this.self,h=s?.nodes.get(r)??null,u=h!==null?B(h):M(r);this.pendingConfirm={label:`kill ${u}?`,action:p(()=>this.shellCrtr(["node","lifecycle","close","--node",r]),"action")},this.tui.requestRender();return}}focusTarget(e){const s=["surface","node","focus",e],i=process.env.TMUX_PANE;i!==void 0&&i!==""&&s.push("--pane",i),this.shellCrtr(s)}reviveTarget(e){this.shellCrtr(["node","lifecycle","revive",e],()=>this.focusTarget(e))}shellCrtr(e,s){try{N("crtr",e,t=>{t==null&&s?.()}).stdin?.end()}catch{}}}export{$t as GraphOverlay};