@north-light/crouter 0.3.321 → 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 (111) hide show
  1. package/bin/progress-painter.mjs +89 -0
  2. package/bin/runtime-selector.mjs +123 -4
  3. package/dist/api/client.d.ts +35 -18
  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/modelauth.d.ts +15 -0
  8. package/dist/api/dto/nodes.d.ts +8 -0
  9. package/dist/api/errors.d.ts +6 -3
  10. package/dist/api/errors.js +1 -1
  11. package/dist/api/index.d.ts +2 -2
  12. package/dist/api/index.js +1 -1
  13. package/dist/api/node-transport.d.ts +18 -0
  14. package/dist/api/node-transport.js +1 -0
  15. package/dist/api/routes.d.ts +3 -0
  16. package/dist/api/routes.js +1 -1
  17. package/dist/builtin-memory/crouter-sdk.md +86 -0
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +1 -1
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +1 -1
  20. package/dist/cli.js +8 -2
  21. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  22. package/dist/clients/attach/overlays/graph.d.ts +6 -5
  23. package/dist/clients/attach/overlays/graph.js +1 -1
  24. package/dist/clients/attach/render/chat-view.d.ts +5 -1
  25. package/dist/clients/attach/render/chat-view.js +1 -1
  26. package/dist/clients/attach/session/frames.d.ts +1 -0
  27. package/dist/clients/attach/session/frames.js +1 -1
  28. package/dist/clients/attach/viewer.js +576 -576
  29. package/dist/commands/api-client.js +3 -3
  30. package/dist/commands/memory/read.js +2 -2
  31. package/dist/commands/node/create.js +3 -3
  32. package/dist/commands/sys/branch.js +1 -1
  33. package/dist/commands/sys/connect.d.ts +1 -0
  34. package/dist/commands/sys/connect.js +3 -0
  35. package/dist/commands/sys/daemon.js +1 -1
  36. package/dist/commands/sys/panels/plugins-panel.js +1 -1
  37. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  38. package/dist/commands/sys/panels/provider-panel.js +1 -1
  39. package/dist/commands/sys/provider-login.d.ts +8 -0
  40. package/dist/commands/sys/provider-login.js +9 -0
  41. package/dist/commands/sys/setup-core.d.ts +4 -0
  42. package/dist/commands/sys/setup-core.js +7 -4
  43. package/dist/commands/sys/setup-wizard.d.ts +1 -1
  44. package/dist/commands/sys/setup-wizard.js +1 -1
  45. package/dist/commands/sys.js +1 -1
  46. package/dist/core/canvas/canvas.d.ts +24 -0
  47. package/dist/core/canvas/canvas.js +29 -15
  48. package/dist/core/canvas/migrations.js +35 -32
  49. package/dist/core/canvas/nav-model.d.ts +1 -1
  50. package/dist/core/canvas/nav-model.js +1 -1
  51. package/dist/core/canvas/nav-render.d.ts +31 -25
  52. package/dist/core/canvas/nav-render.js +1 -1
  53. package/dist/core/canvas/paths.d.ts +4 -4
  54. package/dist/core/canvas/render-source.d.ts +6 -16
  55. package/dist/core/canvas/render-source.js +9 -9
  56. package/dist/core/canvas/types.d.ts +16 -0
  57. package/dist/core/config.js +1 -1
  58. package/dist/core/provider-credential.d.ts +6 -0
  59. package/dist/core/provider-credential.js +1 -0
  60. package/dist/core/runtime/boot-root.d.ts +2 -0
  61. package/dist/core/runtime/boot-root.js +1 -1
  62. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -1
  63. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  64. package/dist/core/runtime/front-door-login.d.ts +2 -0
  65. package/dist/core/runtime/front-door-login.js +1 -0
  66. package/dist/core/runtime/front-door.js +7 -5
  67. package/dist/core/runtime/nerd-font.d.ts +19 -1
  68. package/dist/core/runtime/nerd-font.js +2 -2
  69. package/dist/core/runtime/progress-bar.d.ts +13 -0
  70. package/dist/core/runtime/progress-bar.js +2 -0
  71. package/dist/core/runtime/provider-credential-gate.d.ts +4 -0
  72. package/dist/core/runtime/provider-credential-gate.js +2 -0
  73. package/dist/core/runtime/spawn-env.d.ts +7 -0
  74. package/dist/core/runtime/spawn-env.js +1 -1
  75. package/dist/core/secrets.d.ts +3 -0
  76. package/dist/core/secrets.js +2 -2
  77. package/dist/core/subscription-state.d.ts +1 -1
  78. package/dist/core/subscription-state.js +3 -3
  79. package/dist/core/termrender/termrender.d.ts +3 -1
  80. package/dist/core/termrender/termrender.js +13 -13
  81. package/dist/core/user-settings.d.ts +4 -0
  82. package/dist/core/user-settings.js +1 -1
  83. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  84. package/dist/daemon/api/handlers/canvas.js +4 -4
  85. package/dist/daemon/api/handlers/health.d.ts +1 -1
  86. package/dist/daemon/api/handlers/health.js +3 -3
  87. package/dist/daemon/api/handlers/modelauth.js +1 -1
  88. package/dist/daemon/api/map.d.ts +15 -1
  89. package/dist/daemon/api/map.js +2 -2
  90. package/dist/daemon/api/server.d.ts +5 -1
  91. package/dist/daemon/api/server.js +4 -4
  92. package/dist/daemon/crtrd-cli.js +1 -1
  93. package/dist/daemon/fleet.js +1 -1
  94. package/dist/daemon/manage.d.ts +1 -0
  95. package/dist/daemon/manage.js +2 -2
  96. package/dist/pi-extensions/canvas-stophook.js +1 -1
  97. package/dist/types.d.ts +7 -0
  98. package/dist/types.js +1 -1
  99. package/docs/sdk/README.md +54 -0
  100. package/docs/sdk/client.md +92 -0
  101. package/docs/sdk/docker.md +63 -0
  102. package/docs/sdk/errors.md +85 -0
  103. package/docs/sdk/getting-started.md +160 -0
  104. package/docs/sdk/memory.md +107 -0
  105. package/docs/sdk/migration.md +108 -0
  106. package/docs/sdk/nodes.md +193 -0
  107. package/docs/sdk/resources.md +71 -0
  108. package/docs/sdk/streaming.md +124 -0
  109. package/package.json +1 -1
  110. package/runtime.lock.json +6 -6
  111. package/scripts/install-runtime.mjs +7 -3
@@ -1 +1 @@
1
- var R=Object.defineProperty;var o=(t,e)=>R(t,"name",{value:e,configurable:!0});import{getNode as $,subscribersOf as y,subscriptionsOf as I}from"./index.js";import{faultSummary as C}from"./status-glyph.js";import{statusRank as S}from"./node-order.js";import{nodeGlyph as T,navLabel as _,shortId as G,tokensCell as O,activityCell as D,cycleBadge as W,askBadge as L,liveBelowBadge as M,truncate as N,fillBar as w,fillWidth as k,isAttached as H,BOLD as K,DIM as g,RESET as m,REVERSE as P,BG_ATTACHED as V}from"./nav-render.js";import{PI_MAX_WIDGET_LINES as dt,VIEWPORT_FALLBACK_ROWS as ft,ESC as ht,RESET as pt,BOLD as $t,DIM as mt,REVERSE as vt,BG_ATTACHED as Et,GREEN as xt,RED as gt,YELLOW as Bt,CYAN as bt,GRAY as St,nodeGlyph as wt,visibleWidth as kt,truncate as At,fillWidth as Rt,fillBar as yt,readTelemetry as It,fmtTokens as Ct,tokensCell as Tt,activityCell as _t,cycleBadge as Gt,navLabel as Ot,shortId as Dt,askBadge as Wt,liveBelowBadge as Lt,isAttached as Mt,hasBrokerViewers as Nt,fetchAsksMap as Ht,graphWidgetBudget as Kt,GRAPH_HINT as Pt}from"./nav-render.js";function Y(t){try{return I(t)}catch{return[]}}o(Y,"subsOf");function F(t){try{return y(t)}catch{return[]}}o(F,"mgrsOf");function q(t){return F(t)[0]?.node_id}o(q,"managerOf");function X(t){return $(t)?.kind==="human"}o(X,"isHumanAsk");function v(t){return Y(t).map(e=>e.node_id).filter(e=>!X(e))}o(v,"convoChildIds");function rt(t){return v(t).filter(e=>{const s=$(e)?.status;return s==="active"||s==="idle"})}o(rt,"liveReports");function j(t){return v(t).length}o(j,"childCount");function z(t){let e=t;const s=new Set([e]);for(;;){const c=q(e);if(c===void 0||s.has(c))break;s.add(c),e=c}return e}o(z,"climbRoot");function ct(t){const e=[],s=new Set([t]),c=v(t);for(;c.length>0;){const l=c.shift();if(!s.has(l)){s.add(l),e.push(l);for(const i of v(l))s.has(i)||c.push(i)}}return e}o(ct,"subtreeIds");function J(t){if(t===null)return"";const e=j(t.node_id);return e>0?` ${g}\u2933${e}${m}`:""}o(J,"childBadge");function Q(t){return v(t).sort((e,s)=>S($(e)?.status)-S($(s)?.status))}o(Q,"sortedChildIds");function U(t,e){const s=new Set,c=new Map,l=new Set,i=o(n=>{const u=$(n)?.status==="active";if(l.has(n))return{active:u?1:0,reveal:u||n===e};l.add(n);let d=0,r=!1;for(const h of v(n)){const f=i(h);d+=f.active,f.reveal&&(r=!0)}return c.set(n,d),r&&s.add(n),{active:d+(u?1:0),reveal:r||u||n===e}},"visit");return i(t),{expand:s,activeBelow:c}}o(U,"computeSubtreeActivity");function Z(t,e){return U(t,e).expand}o(Z,"computeDefaultExpanded");function at(t,e,s){const c=z(t),l=s??Z(c,t),i=o(r=>e.userExpanded.has(r)?!1:e.userCollapsed.has(r)?!0:!l.has(r),"isFolded"),n=[],u=new Set,d=o((r,h,f,E)=>{if(u.has(r)){const a=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";n.push({id:r,hasKids:!1,isSelf:r===t,branch:h+a,cycle:!0,collapsed:!1});return}u.add(r);const p=Q(r),x=i(r),B=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";if(n.push({id:r,hasKids:p.length>0,isSelf:r===t,branch:h+B,cycle:!1,collapsed:x}),x)return;const b=f?"":h+(E?" ":"\u2502 ");for(let a=0;a<p.length;a++)d(p[a],b,!1,a===p.length-1)},"walk");return d(c,"",!0,!0),n}o(at,"buildGraphModel");function lt(t,e,s,c,l){const i=o((a,A)=>e?w(a,k(),P):A?w(a,k(),V):N(a),"wrap");if(t.cycle){const a=`${t.branch} ${g}\u21BA ${G(t.id)}${m}`;return i(a,!1)}const n=$(t.id),u=T(n),d=_(n,t.id),r=t.isSelf?`${K}${d}${m}`:d,h=`${g}${n?.kind??""}${m}`,f=`${g}${O(t.id)}${m}`,E=t.hasKids&&t.collapsed,p=!e&&E?`${g}\u25B8${m} `:" ",x=n?.fault??null,B=x!==null?` \xB7 ${C(x)}`:"",b=`${t.branch}${p}${u} ${r} ${h} ${f}${W(n)}${J(n)}${M(n,c)}${L(t.id,l)}${D(t.id,n)}${B}`;return i(b,H(t.id,n,s))}o(lt,"renderGraphRow");export{Et as BG_ATTACHED,$t as BOLD,bt as CYAN,mt as DIM,ht as ESC,Pt as GRAPH_HINT,St as GRAY,xt as GREEN,dt as PI_MAX_WIDGET_LINES,gt as RED,pt as RESET,vt as REVERSE,ft as VIEWPORT_FALLBACK_ROWS,Bt as YELLOW,_t as activityCell,Wt as askBadge,at as buildGraphModel,J as childBadge,j as childCount,z as climbRoot,Z as computeDefaultExpanded,U as computeSubtreeActivity,v as convoChildIds,Gt as cycleBadge,Ht as fetchAsksMap,yt as fillBar,Rt as fillWidth,Ct as fmtTokens,Kt as graphWidgetBudget,Nt as hasBrokerViewers,Mt as isAttached,X as isHumanAsk,Lt as liveBelowBadge,rt as liveReports,q as managerOf,Ot as navLabel,wt as nodeGlyph,It as readTelemetry,lt as renderGraphRow,Dt as shortId,Q as sortedChildIds,ct as subtreeIds,Tt as tokensCell,At as truncate,kt as visibleWidth};
1
+ var R=Object.defineProperty;var o=(t,e)=>R(t,"name",{value:e,configurable:!0});import{getNode as $,subscribersOf as y,subscriptionsOf as I}from"./index.js";import{faultSummary as C}from"./status-glyph.js";import{statusRank as S}from"./node-order.js";import{nodeGlyph as _,navLabel as G,shortId as O,tokensCell as T,activityCell as D,cycleBadge as W,askBadge as L,liveBelowBadge as M,truncate as N,fillBar as w,fillWidth as k,isAttached as H,BOLD as K,DIM as g,RESET as m,REVERSE as P,BG_ATTACHED as V}from"./nav-render.js";import{PI_MAX_WIDGET_LINES as dt,VIEWPORT_FALLBACK_ROWS as ft,ESC as ht,RESET as pt,BOLD as $t,DIM as mt,REVERSE as vt,BG_ATTACHED as Et,GREEN as xt,RED as gt,YELLOW as Bt,CYAN as bt,GRAY as St,nodeGlyph as wt,visibleWidth as kt,truncate as At,fillWidth as Rt,fillBar as yt,fmtTokens as It,tokensCell as Ct,activityCell as _t,cycleBadge as Gt,navLabel as Ot,shortId as Tt,askBadge as Dt,liveBelowBadge as Wt,isAttached as Lt,hasBrokerViewers as Mt,fetchAsksMap as Nt,graphWidgetBudget as Ht,GRAPH_HINT as Kt}from"./nav-render.js";function Y(t){try{return I(t)}catch{return[]}}o(Y,"subsOf");function F(t){try{return y(t)}catch{return[]}}o(F,"mgrsOf");function q(t){return F(t)[0]?.node_id}o(q,"managerOf");function X(t){return $(t)?.kind==="human"}o(X,"isHumanAsk");function v(t){return Y(t).map(e=>e.node_id).filter(e=>!X(e))}o(v,"convoChildIds");function rt(t){return v(t).filter(e=>{const s=$(e)?.status;return s==="active"||s==="idle"})}o(rt,"liveReports");function j(t){return v(t).length}o(j,"childCount");function z(t){let e=t;const s=new Set([e]);for(;;){const c=q(e);if(c===void 0||s.has(c))break;s.add(c),e=c}return e}o(z,"climbRoot");function ct(t){const e=[],s=new Set([t]),c=v(t);for(;c.length>0;){const l=c.shift();if(!s.has(l)){s.add(l),e.push(l);for(const u of v(l))s.has(u)||c.push(u)}}return e}o(ct,"subtreeIds");function J(t){if(t===null)return"";const e=j(t.node_id);return e>0?` ${g}\u2933${e}${m}`:""}o(J,"childBadge");function Q(t){return v(t).sort((e,s)=>S($(e)?.status)-S($(s)?.status))}o(Q,"sortedChildIds");function U(t,e){const s=new Set,c=new Map,l=new Set,u=o(n=>{const i=$(n)?.status==="active";if(l.has(n))return{active:i?1:0,reveal:i||n===e};l.add(n);let d=0,r=!1;for(const h of v(n)){const f=u(h);d+=f.active,f.reveal&&(r=!0)}return c.set(n,d),r&&s.add(n),{active:d+(i?1:0),reveal:r||i||n===e}},"visit");return u(t),{expand:s,activeBelow:c}}o(U,"computeSubtreeActivity");function Z(t,e){return U(t,e).expand}o(Z,"computeDefaultExpanded");function at(t,e,s){const c=z(t),l=s??Z(c,t),u=o(r=>e.userExpanded.has(r)?!1:e.userCollapsed.has(r)?!0:!l.has(r),"isFolded"),n=[],i=new Set,d=o((r,h,f,E)=>{if(i.has(r)){const a=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";n.push({id:r,hasKids:!1,isSelf:r===t,branch:h+a,cycle:!0,collapsed:!1});return}i.add(r);const p=Q(r),x=u(r),B=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";if(n.push({id:r,hasKids:p.length>0,isSelf:r===t,branch:h+B,cycle:!1,collapsed:x}),x)return;const b=f?"":h+(E?" ":"\u2502 ");for(let a=0;a<p.length;a++)d(p[a],b,!1,a===p.length-1)},"walk");return d(c,"",!0,!0),n}o(at,"buildGraphModel");function lt(t,e,s,c,l){const u=o((a,A)=>e?w(a,k(),P):A?w(a,k(),V):N(a),"wrap");if(t.cycle){const a=`${t.branch} ${g}\u21BA ${O(t.id)}${m}`;return u(a,!1)}const n=$(t.id),i=_(n),d=G(n,t.id),r=t.isSelf?`${K}${d}${m}`:d,h=`${g}${n?.kind??""}${m}`,f=`${g}${T(n)}${m}`,E=t.hasKids&&t.collapsed,p=!e&&E?`${g}\u25B8${m} `:" ",x=n?.fault??null,B=x!==null?` \xB7 ${C(x)}`:"",b=`${t.branch}${p}${i} ${r} ${h} ${f}${W(n)}${J(n)}${M(n,c)}${L(t.id,l)}${D(n)}${B}`;return u(b,H(t.id,n,s))}o(lt,"renderGraphRow");export{Et as BG_ATTACHED,$t as BOLD,bt as CYAN,mt as DIM,ht as ESC,Kt as GRAPH_HINT,St as GRAY,xt as GREEN,dt as PI_MAX_WIDGET_LINES,gt as RED,pt as RESET,vt as REVERSE,ft as VIEWPORT_FALLBACK_ROWS,Bt as YELLOW,_t as activityCell,Dt as askBadge,at as buildGraphModel,J as childBadge,j as childCount,z as climbRoot,Z as computeDefaultExpanded,U as computeSubtreeActivity,v as convoChildIds,Gt as cycleBadge,Nt as fetchAsksMap,yt as fillBar,Rt as fillWidth,It as fmtTokens,Ht as graphWidgetBudget,Mt as hasBrokerViewers,Lt as isAttached,X as isHumanAsk,Wt as liveBelowBadge,rt as liveReports,q as managerOf,Ot as navLabel,wt as nodeGlyph,lt as renderGraphRow,Tt as shortId,Q as sortedChildIds,ct as subtreeIds,Ct as tokensCell,At as truncate,kt as visibleWidth};
@@ -1,4 +1,23 @@
1
- import type { NodeMeta } from './types.js';
1
+ import type { Fault } from '../fault-classifier.js';
2
+ import type { NodeStatus } from './types.js';
3
+ /** The node fields these helpers display — satisfied by `NodeMeta`, by
4
+ * `NodeRow`, and by the lean `GET /v1/canvas/graph` row the attach graph reads.
5
+ * Declared narrow so a caller holding only the display projection needs no full
6
+ * node record. */
7
+ export interface NavNode {
8
+ node_id: string;
9
+ name: string;
10
+ kind: string;
11
+ description?: string;
12
+ cycles?: number;
13
+ status: NodeStatus;
14
+ frozen_at?: string | null;
15
+ pi_pid?: number | null;
16
+ streaming?: boolean;
17
+ telemetry_context_tokens?: number | null;
18
+ telemetry_last_activity?: string | null;
19
+ fault?: Fault | null;
20
+ }
2
21
  /** pi's InteractiveMode.MAX_WIDGET_LINES — the hard cap on lines in a string
3
22
  * array widget; anything beyond it pi truncates with its own "... (widget
4
23
  * truncated)". Our GRAPH viewport stays at/under this and scrolls internally. */
@@ -22,7 +41,7 @@ export declare const GRAY = "\u001B[90m";
22
41
  * outranks the base status glyph. Every input is a projected row field — the
23
42
  * owning daemon computed `fault`/`streaming` — so this holds for a remote node
24
43
  * too, with no local read keyed on a node id that may collide. */
25
- export declare function nodeGlyph(node: NodeMeta | null): string;
44
+ export declare function nodeGlyph(node: NavNode | null): string;
26
45
  /** Drop every SGR sequence, keeping the visible text. The selection bar uses
27
46
  * this: reverse-video INVERTS a coloured cell into a coloured block, so a row
28
47
  * built from tinted spans highlights as a patchwork of background swatches
@@ -50,52 +69,39 @@ export declare function fillWidth(): number;
50
69
  * bar; the visible width is padded out to `width`; the line closes with a real
51
70
  * RESET so the style never bleeds into the editor below. */
52
71
  export declare function fillBar(content: string, width: number, open: string): string;
53
- /** Clear the per-frame telemetry cache. Every render pass calls this first, so
54
- * one keystroke re-reads each node's telemetry exactly once. */
55
- export declare function beginFrameTelem(): void;
56
- export interface Telemetry {
57
- /** Live context-window size (pi's getContextUsage) — the figure pi's own footer
58
- * shows. This is the node's window fill, NOT a per-turn delta. */
59
- context_tokens?: number;
60
- /** One-line "what is it doing" cue (`tool: detail`), written on every tool start. */
61
- last_activity?: string;
62
- }
63
- export declare function readTelemetry(nodeId: string): Telemetry;
64
72
  export declare function fmtTokens(n: number): string;
65
73
  /** The context-window cell — live window fill rounded to the nearest 1k (the same
66
- * figure pi's footer shows), NOT a per-turn token delta. `remote` skips the local
67
- * `telemetry.json` read entirely and reports 0 (a remote node id may collide
68
- * with a local one). */
69
- export declare function tokensCell(id: string, remote?: boolean): string;
74
+ * figure pi's footer shows), NOT a per-turn delta. Remote canvases retain the
75
+ * existing safe 0 display rather than treating a local node id as remote state. */
76
+ export declare function tokensCell(node: NavNode | null, remote?: boolean): string;
70
77
  /** Dimmed live "what is it doing" cue for an ACTIVE node — the last tool it ran.
71
- * Empty for non-active rows (stale once a node parks) and when none is recorded.
72
- * `remote` skips the local `telemetry.json` read entirely and reports empty. */
73
- export declare function activityCell(id: string, node: NodeMeta | null, remote?: boolean): string;
78
+ * Empty for non-active rows and when none is recorded. */
79
+ export declare function activityCell(node: NavNode | null, remote?: boolean): string;
74
80
  /** Revive-count badge (meta.cycles). Hidden on the first cycle (0) to cut noise. */
75
- export declare function cycleBadge(node: NodeMeta | null): string;
81
+ export declare function cycleBadge(node: NavNode | null): string;
76
82
  /** Short on-screen label: the explicit handle when set, else the pi-generated
77
83
  * description, else the bare name. fullName joins BOTH (`handle description`);
78
84
  * the nav chrome shows just the first so rows stay compact. */
79
- export declare function navLabel(node: NodeMeta | null, id: string): string;
85
+ export declare function navLabel(node: NavNode | null, id: string): string;
80
86
  export declare function shortId(id: string): string;
81
87
  /** True when a human is watching `id` right now via the broker viewer count
82
88
  * (attach.json). The tmux-focus axis (a `focuses` row) is a canvas-db read and
83
89
  * stays in nav-model's `isAttached`, which ORs this signal with the focus set.
84
90
  * `remote` skips the local `attach.json` read entirely and reports false (a
85
91
  * remote node id may collide with a local one). */
86
- export declare function hasBrokerViewers(id: string, node: NodeMeta | null, remote?: boolean): boolean;
92
+ export declare function hasBrokerViewers(id: string, node: NavNode | null, remote?: boolean): boolean;
87
93
  /** True when a human is watching `id` right now (tmux focus or broker viewer).
88
94
  * `focused` is the tmux-focus set (a canvas-db read the caller supplies). The
89
95
  * broker-viewer half is a pure `attach.json` read. `remote` skips the local read
90
96
  * entirely and reports false (a remote node id may collide with a local one). */
91
- export declare function isAttached(id: string, node: NodeMeta | null, focused: ReadonlySet<string>, remote?: boolean): boolean;
97
+ export declare function isAttached(id: string, node: NavNode | null, focused: ReadonlySet<string>, remote?: boolean): boolean;
92
98
  /** ⚑K pending-asks badge for a node, read from the supplied per-node ask map. */
93
99
  export declare function askBadge(id: string, asks: Record<string, number>): string;
94
100
  /** "Live work below" badge — green ⇣N when this node is NOT itself active but has
95
101
  * N active descendants. The one signal that an idle/parked node isn't dead: real
96
102
  * work is still running beneath it. Count comes from the single subtree-activity
97
103
  * pass (no per-row walk). Suppressed on active rows (their own ● already says so). */
98
- export declare function liveBelowBadge(node: NodeMeta | null, activeBelow: ReadonlyMap<string, number>): string;
104
+ export declare function liveBelowBadge(node: NavNode | null, activeBelow: ReadonlyMap<string, number>): string;
99
105
  export declare function fetchAsksMap(rootId: string): Record<string, number>;
100
106
  export interface FlatRow {
101
107
  id: string;
@@ -1 +1 @@
1
- var v=Object.defineProperty;var n=(t,e)=>v(t,"name",{value:e,configurable:!0});import{execFileSync as y}from"node:child_process";import{existsSync as f,readFileSync as p}from"node:fs";import{join as m}from"node:path";import{jobDir as x}from"./paths.js";import{isFrozenRow as E,resolveNodeVisual as _}from"./status-glyph.js";const d=10,S=30,c="\x1B[",i=`${c}0m`,D=`${c}1m`,a=`${c}2m`,F=`${c}7m`,G=`${c}48;5;22m`,k=`${c}32m`,I=`${c}31m`,w=`${c}33m`,V=`${c}36m`,H=`${c}90m`;function A(t){return t.status!=="active"&&t.status!=="idle"?!1:t.streaming===!0}n(A,"streamingFor");function J(t){if(t===null)return"?";const e=_(t.status,{streaming:A(t),frozen:E(t),hanging:t.fault??null});return`${c}${e.color}m${e.glyph}${i}`}n(J,"nodeGlyph");const $=/\x1b\[[0-9;]*m/g;function P(t){return t.replace($,"")}n(P,"stripSgr");function h(t){return t.replace($,"").length}n(h,"visibleWidth");function R(t,e=b()){if(h(t)<=e)return t;let r="",o=0,s=0;for(;s<t.length&&o<e-1;){if(t[s]==="\x1B"){const u=/^\x1b\[[0-9;]*m/.exec(t.slice(s));if(u){r+=u[0],s+=u[0].length;continue}}r+=t[s],o++,s++}return`${r}\u2026${i}`}n(R,"truncate");function b(){return Math.max(20,Math.min((process.stdout.columns??80)-2,180))}n(b,"fillWidth");function Y(t,e,r){const o=R(t,e),s=o.replace(/\x1b\[0m/g,`${i}${r}`),u=Math.max(0,e-h(o));return`${r}${s}${" ".repeat(u)}${i}`}n(Y,"fillBar");const l=new Map;function z(){l.clear()}n(z,"beginFrameTelem");function g(t){const e=l.get(t);if(e!==void 0)return e;let r;try{const o=m(x(t),"telemetry.json");r=f(o)?JSON.parse(p(o,"utf8")):{}}catch{r={}}return l.set(t,r),r}n(g,"readTelemetry");function B(t){return t<1e3?`${t}`:`${Math.round(t/1e3)}k`}n(B,"fmtTokens");function K(t,e=!1){return B(e?0:g(t).context_tokens??0)}n(K,"tokensCell");function X(t,e,r=!1){if(r||e?.status!=="active")return"";const o=(g(t).last_activity??"").trim();return o===""?"":` ${a}\xB7 ${o}${i}`}n(X,"activityCell");function q(t){const e=t?.cycles??0;return e>0?` ${a}\u27F3${e}${i}`:""}n(q,"cycleBadge");function Q(t,e){if(t===null)return M(e);const r=t.name&&t.name!==t.kind?t.name:"";if(r!=="")return r;const o=(t.description??"").trim();return o!==""?o:t.name}n(Q,"navLabel");function M(t){return t.slice(0,8)}n(M,"shortId");function T(t,e,r=!1){if(r||e?.status!=="active")return!1;try{const o=m(x(t),"attach.json");if(!f(o))return!1;const s=JSON.parse(p(o,"utf8"));return typeof s.viewers=="number"&&s.viewers>0}catch{return!1}}n(T,"hasBrokerViewers");function U(t,e,r,o=!1){return o?!1:r.has(t)?!0:T(t,e,o)}n(U,"isAttached");function Z(t,e){const r=e[t]??0;return r>0?` ${w}\u2691${r}${i}`:""}n(Z,"askBadge");function tt(t,e){if(t===null||t.status==="active")return"";const r=e.get(t.node_id)??0;return r>0?` ${k}\u21E3${r}${i}`:""}n(tt,"liveBelowBadge");function et(t){try{const e=y("crtr",["canvas","attention","map","--view",t,"--json"],{timeout:2500,encoding:"utf8"});return JSON.parse(e.trim()).counts??{}}catch{return{}}}n(et,"fetchAsksMap");function rt(){const t=process.stdout.rows??S;return Math.max(4,Math.min(d,t-4))}n(rt,"graphWidgetBudget");const nt=`${a}jk move \xB7 hl fold \xB7 \u21B5 focus \xB7 e expand \xB7 x kill \xB7 m mgr \xB7 esc${i}`;export{G as BG_ATTACHED,D as BOLD,V as CYAN,a as DIM,c as ESC,nt as GRAPH_HINT,H as GRAY,k as GREEN,d as PI_MAX_WIDGET_LINES,I as RED,i as RESET,F as REVERSE,S as VIEWPORT_FALLBACK_ROWS,w as YELLOW,X as activityCell,Z as askBadge,z as beginFrameTelem,q as cycleBadge,et as fetchAsksMap,Y as fillBar,b as fillWidth,B as fmtTokens,rt as graphWidgetBudget,T as hasBrokerViewers,U as isAttached,tt as liveBelowBadge,Q as navLabel,J as nodeGlyph,g as readTelemetry,M as shortId,P as stripSgr,K as tokensCell,R as truncate,h as visibleWidth};
1
+ var p=Object.defineProperty;var n=(t,e)=>p(t,"name",{value:e,configurable:!0});import{execFileSync as m}from"node:child_process";import{existsSync as x,readFileSync as $}from"node:fs";import{join as h}from"node:path";import{jobDir as g}from"./paths.js";import{isFrozenRow as v,resolveNodeVisual as _}from"./status-glyph.js";const y=10,E=30,c="\x1B[",i=`${c}0m`,C=`${c}1m`,a=`${c}2m`,D=`${c}7m`,G=`${c}48;5;22m`,d=`${c}32m`,O=`${c}31m`,S=`${c}33m`,j=`${c}36m`,F=`${c}90m`;function k(t){return t.status!=="active"&&t.status!=="idle"?!1:t.streaming===!0}n(k,"streamingFor");function V(t){if(t===null)return"?";const e=_(t.status,{streaming:k(t),frozen:v(t),hanging:t.fault??null});return`${c}${e.color}m${e.glyph}${i}`}n(V,"nodeGlyph");const l=/\x1b\[[0-9;]*m/g;function H(t){return t.replace(l,"")}n(H,"stripSgr");function f(t){return t.replace(l,"").length}n(f,"visibleWidth");function A(t,e=R()){if(f(t)<=e)return t;let r="",o=0,s=0;for(;s<t.length&&o<e-1;){if(t[s]==="\x1B"){const u=/^\x1b\[[0-9;]*m/.exec(t.slice(s));if(u){r+=u[0],s+=u[0].length;continue}}r+=t[s],o++,s++}return`${r}\u2026${i}`}n(A,"truncate");function R(){return Math.max(20,Math.min((process.stdout.columns??80)-2,180))}n(R,"fillWidth");function P(t,e,r){const o=A(t,e),s=o.replace(/\x1b\[0m/g,`${i}${r}`),u=Math.max(0,e-f(o));return`${r}${s}${" ".repeat(u)}${i}`}n(P,"fillBar");function w(t){return t<1e3?`${t}`:`${Math.round(t/1e3)}k`}n(w,"fmtTokens");function Y(t,e=!1){return w(e?0:t?.telemetry_context_tokens??0)}n(Y,"tokensCell");function z(t,e=!1){if(e||t?.status!=="active")return"";const r=(t.telemetry_last_activity??"").trim();return r===""?"":` ${a}\xB7 ${r}${i}`}n(z,"activityCell");function J(t){const e=t?.cycles??0;return e>0?` ${a}\u27F3${e}${i}`:""}n(J,"cycleBadge");function K(t,e){if(t===null)return B(e);const r=t.name&&t.name!==t.kind?t.name:"";if(r!=="")return r;const o=(t.description??"").trim();return o!==""?o:t.name}n(K,"navLabel");function B(t){return t.slice(0,8)}n(B,"shortId");function b(t,e,r=!1){if(r||e?.status!=="active")return!1;try{const o=h(g(t),"attach.json");if(!x(o))return!1;const s=JSON.parse($(o,"utf8"));return typeof s.viewers=="number"&&s.viewers>0}catch{return!1}}n(b,"hasBrokerViewers");function X(t,e,r,o=!1){return o?!1:r.has(t)?!0:b(t,e,o)}n(X,"isAttached");function q(t,e){const r=e[t]??0;return r>0?` ${S}\u2691${r}${i}`:""}n(q,"askBadge");function Q(t,e){if(t===null||t.status==="active")return"";const r=e.get(t.node_id)??0;return r>0?` ${d}\u21E3${r}${i}`:""}n(Q,"liveBelowBadge");function U(t){try{const e=m("crtr",["canvas","attention","map","--view",t,"--json"],{timeout:2500,encoding:"utf8"});return JSON.parse(e.trim()).counts??{}}catch{return{}}}n(U,"fetchAsksMap");function Z(){const t=process.stdout.rows??E;return Math.max(4,Math.min(y,t-4))}n(Z,"graphWidgetBudget");const tt=`${a}jk move \xB7 hl fold \xB7 \u21B5 focus \xB7 e expand \xB7 x kill \xB7 m mgr \xB7 esc${i}`;export{G as BG_ATTACHED,C as BOLD,j as CYAN,a as DIM,c as ESC,tt as GRAPH_HINT,F as GRAY,d as GREEN,y as PI_MAX_WIDGET_LINES,O as RED,i as RESET,D as REVERSE,E as VIEWPORT_FALLBACK_ROWS,S as YELLOW,z as activityCell,q as askBadge,J as cycleBadge,U as fetchAsksMap,P as fillBar,R as fillWidth,w as fmtTokens,Z as graphWidgetBudget,b as hasBrokerViewers,X as isAttached,Q as liveBelowBadge,K as navLabel,V as nodeGlyph,B as shortId,H as stripSgr,Y as tokensCell,A as truncate,f as visibleWidth};
@@ -26,10 +26,10 @@ export declare function ensureReviewDir(reviewId: string): void;
26
26
  * `canvasDbPath()` under the canvas home (`~/.crouter/canvas/crtrd.sock` unless
27
27
  * `CRTR_HOME` is set). Pure path builder — no db reach — so both the daemon
28
28
  * (which binds it) and a CLI-side resolver can import it freely. `src/api`'s
29
- * `CrtrClient.forLocalSocket()` deliberately re-derives this same path from a
30
- * Node-builtin `join(crtrHome-equivalent, 'crtrd.sock')` rather than importing
31
- * here, to keep the exported `/api` contract dependency-light; the two must
32
- * agree. */
29
+ * `defaultSocketPath()` (in `api/node-transport.ts`) deliberately re-derives
30
+ * this same path from a Node-builtin `join(crtrHome-equivalent, 'crtrd.sock')`
31
+ * rather than importing here, to keep the exported `/api` contract
32
+ * dependency-light; the two must agree. */
33
33
  export declare function apiSocketPath(): string;
34
34
  /** Global, cwd-agnostic broker cache of per-session picker metadata, keyed by
35
35
  * absolute `.jsonl` path. Shared across every node's broker (paths are absolute)
@@ -2,10 +2,6 @@ import type { CanvasSource } from './source.js';
2
2
  import { type NodeRecap } from './node-recap.js';
3
3
  import type { Fault } from '../runtime/fault.js';
4
4
  import type { NodeStatus, Lifecycle, NodeRow, TerminalReason } from './types.js';
5
- export interface NodeTelemetry {
6
- tokens_in?: number;
7
- }
8
- export declare function readNodeTelemetry(nodeId: string): NodeTelemetry;
9
5
  /** Format a token count as `Nk` (rounded down to nearest 1 k). */
10
6
  export declare function fmtCtx(tokensIn: number | undefined): string;
11
7
  export declare function renderTreeFromSource(source: CanvasSource, rootId: string, snapshot?: readonly NodeRow[], ticketSnapshot?: Record<string, number>, ticketUnavailable?: string): Promise<string>;
@@ -43,14 +39,11 @@ export interface DashboardRow {
43
39
  * status alone cannot (see `isFinishedWork` in node-order.ts). Only populated
44
40
  * by dashboardRowsAll (the browser snapshot). */
45
41
  finalized?: boolean;
46
- /** "Most recent activity" sort key — epoch ms. The cheap boot stats the node's
47
- * job/telemetry.json (rewritten on every turn_end at a DETERMINISTIC path, so
48
- * no meta read), falling back to `created`'s epoch when a node never ran a turn.
42
+ /** "Most recent activity" sort key — epoch ms from the daemon's telemetry
43
+ * projection, falling back to `created` when a node never reported telemetry.
49
44
  * This is the cheap proxy for last-message recency the attention sort tie-breaks
50
45
  * on. Always set by dashboardRowsAll; optional only so synthetic test rows + the
51
- * scoped dashboardRows can omit it. (NB: the pi session-file mtime would be truer
52
- * but its path lives in meta.json at a non-deterministic location — reading it
53
- * per node would defeat the cheap boot, so telemetry mtime is used instead.) */
46
+ * scoped dashboardRows can omit it. */
54
47
  mtimeMs?: number;
55
48
  /** The node's spawn prompt (context/initial-prompt.md), trimmed + capped. Populated
56
49
  * LAZILY by loadPreview (selected-row preview) — NOT on the cheap boot path.
@@ -156,12 +149,9 @@ export declare function readTranscript(sessionFile: string | null | undefined):
156
149
  * — a tool-call-only turn (no final text) still counts. Drives reap-on-close/
157
150
  * detach. One file read with an early exit on the first substantive turn. */
158
151
  export declare function nodeHasAssistantMessage(sessionFile: string | null | undefined): boolean;
159
- /** "Most recent activity" sort key (epoch ms) read CHEAPLY: a `statSync` (no file
160
- * read, no parse) of the node's job/telemetry.json — rewritten on every turn_end at
161
- * a deterministic canvas-home path, so it tracks last-message recency without a meta
162
- * read. Falls back to `created`'s epoch when a node never ran a turn (no telemetry).
163
- * Never throws. */
164
- export declare function sessionMtime(nodeId: string, created: string, remote?: boolean): number;
152
+ /** "Most recent activity" sort key from the daemon's telemetry projection. It
153
+ * falls back to `created` when the broker has never reported telemetry. */
154
+ export declare function sessionMtime(created: string, telemetryUpdatedAt: string | null | undefined, remote?: boolean): number;
165
155
  /** Build one cheap-boot row from a raw db/source row. `fault`/`streaming` are
166
156
  * projected row fields, so they hold for a remote row too; `remote` suppresses the
167
157
  * LOCAL disk reads (telemetry-mtime/viewers) that are meaningless for a truly
@@ -1,10 +1,10 @@
1
- var W=Object.defineProperty;var u=(t,e)=>W(t,"name",{value:e,configurable:!0});import{existsSync as $,readFileSync as g,readdirSync as H,statSync as C,openSync as Z,readSync as q,closeSync as K}from"node:fs";import{join as S}from"node:path";import{RemoteCanvasSource as y}from"./remote-canvas-source.js";import{fullName as N}from"./labels.js";import{jobDir as A,contextDir as Q,reportsDir as j}from"./paths.js";import{readNodeRecap as X}from"./node-recap.js";import{parseFrontmatterGeneric as I}from"../frontmatter.js";import{isFrozenRow as P,resolveNodeVisual as L,faultSummary as M}from"./status-glyph.js";import{parseCard as z}from"../../shared/generated-context.js";function b(t){const e=S(A(t),"telemetry.json");if(!$(e))return{};try{return JSON.parse(g(e,"utf8"))}catch{return{}}}u(b,"readNodeTelemetry");function w(t){return t===void 0||t===0?"0k":`${Math.floor(t/1e3)}k`}u(w,"fmtCtx");function tt(t,e,n,r,a,f){if(t===void 0)return`${n}${r}? <missing meta: ${e}>`;const i=t.fault??null,s=L(t.status,{hanging:i,frozen:P(t)}).glyph,o=a?"0k":w(b(e).tokens_in),c=f[e]??0,d=c>0?` \u2691${c}`:"",p=i!==null?` \xB7 ${M(i)}`:"";return`${n}${r}${s} ${N(t)} [${t.kind}/${t.mode}] ctx ${o}${d}${p}`}u(tt,"nodeLineFromSource");async function E(t,e,n,r,a,f,i,s,o){if(f.has(n))return;f.add(n);const c=a?"\u2514\u2500 ":"\u251C\u2500 ";i.push(tt(e.get(n),n,r,c,s,o));const d=r+(a?" ":"\u2502 ");let p;try{p=await t.subscriptionsOf(n)}catch(l){i.push(`${d}\u26A0 children unavailable: ${l instanceof Error?l.message:String(l)}`);return}for(let l=0;l<p.length;l++){const h=p[l],k=l===p.length-1;if(f.has(h.node_id)){const O=k?"\u2514\u2500 ":"\u251C\u2500 ";i.push(`${d}${O}\u21BA <cycle: ${h.node_id}>`);continue}await E(t,e,h.node_id,d,k,f,i,s,o)}}u(E,"walkTreeFromSource");async function et(t,e,n,r,a){const f=t instanceof y,i=new Map((n??await t.listNodes()).map(m=>[m.node_id,m])),s=i.get(e);if(s===void 0)return`? <missing node: ${e}>`;let o=r,c=a??null;if(o===void 0)try{o=await t.ticketCountsForView(e)}catch(m){o={},c=m instanceof Error?m.message:String(m)}const d=f?"0k":w(b(e).tokens_in),p=o[e]??0,l=p>0?` \u2691${p}`:"",h=s.fault??null,k=L(s.status,{hanging:h,frozen:P(s)}).glyph,O=h!==null?` \xB7 ${M(h)}`:"",_=[];_.push(`${k} ${N(s)} [${s.kind}/${s.mode}] ctx ${d}${l}${O}`);const U=new Set([e]);let x;try{x=await t.subscriptionsOf(e)}catch(m){_.push(`\u26A0 children unavailable: ${m instanceof Error?m.message:String(m)}`),x=[]}for(let m=0;m<x.length;m++){const Y=x[m],B=m===x.length-1;await E(t,i,Y.node_id,"",B,U,_,f,o)}return c!==null&&_.push(`Tickets: unavailable (${c}).`),_.join(`
2
- `)}u(et,"renderTreeFromSource");async function bt(t,e,n,r){const a=e??await t.listNodes();if(a.length===0)return"(canvas is empty)";const f=a.filter(s=>s.parent===null&&(s.status==="active"||s.status==="idle"));if(f.length===0)return"(no live roots)";const i=[];for(const s of f)i.push(await et(t,s.node_id,a,n,r));return i.join(`
1
+ var Y=Object.defineProperty;var f=(t,e)=>Y(t,"name",{value:e,configurable:!0});import{existsSync as b,readFileSync as _,readdirSync as B,statSync as U,openSync as W,readSync as H,closeSync as Z}from"node:fs";import{join as T}from"node:path";import{RemoteCanvasSource as x}from"./remote-canvas-source.js";import{fullName as $}from"./labels.js";import{jobDir as q,contextDir as K,reportsDir as R}from"./paths.js";import{readNodeRecap as Q}from"./node-recap.js";import{parseFrontmatterGeneric as X}from"../frontmatter.js";import{isFrozenRow as v,resolveNodeVisual as C,faultSummary as P}from"./status-glyph.js";import{parseCard as L}from"../../shared/generated-context.js";function j(t){return t===void 0||t===0?"0k":`${Math.floor(t/1e3)}k`}f(j,"fmtCtx");function I(t,e,n,i,c,a){if(t===void 0)return`${n}${i}? <missing meta: ${e}>`;const s=t.fault??null,r=C(t.status,{hanging:s,frozen:v(t)}).glyph,o=c?"0k":j(t.telemetry_tokens_in??void 0),u=a[e]??0,m=u>0?` \u2691${u}`:"",d=s!==null?` \xB7 ${P(s)}`:"";return`${n}${i}${r} ${$(t)} [${t.kind}/${t.mode}] ctx ${o}${m}${d}`}f(I,"nodeLineFromSource");async function z(t,e,n,i,c,a,s,r,o){if(a.has(n))return;a.add(n);const u=c?"\u2514\u2500 ":"\u251C\u2500 ";s.push(I(e.get(n),n,i,u,r,o));const m=i+(c?" ":"\u2502 ");let d;try{d=await t.subscriptionsOf(n)}catch(l){s.push(`${m}\u26A0 children unavailable: ${l instanceof Error?l.message:String(l)}`);return}for(let l=0;l<d.length;l++){const h=d[l],S=l===d.length-1;if(a.has(h.node_id)){const N=S?"\u2514\u2500 ":"\u251C\u2500 ";s.push(`${m}${N}\u21BA <cycle: ${h.node_id}>`);continue}await z(t,e,h.node_id,m,S,a,s,r,o)}}f(z,"walkTreeFromSource");async function tt(t,e,n,i,c){const a=t instanceof x,s=new Map((n??await t.listNodes()).map(p=>[p.node_id,p])),r=s.get(e);if(r===void 0)return`? <missing node: ${e}>`;let o=i,u=c??null;if(o===void 0)try{o=await t.ticketCountsForView(e)}catch(p){o={},u=p instanceof Error?p.message:String(p)}const m=a?"0k":j(r.telemetry_tokens_in??void 0),d=o[e]??0,l=d>0?` \u2691${d}`:"",h=r.fault??null,S=C(r.status,{hanging:h,frozen:v(r)}).glyph,N=h!==null?` \xB7 ${P(h)}`:"",g=[];g.push(`${S} ${$(r)} [${r.kind}/${r.mode}] ctx ${m}${l}${N}`);const V=new Set([e]);let y;try{y=await t.subscriptionsOf(e)}catch(p){g.push(`\u26A0 children unavailable: ${p instanceof Error?p.message:String(p)}`),y=[]}for(let p=0;p<y.length;p++){const G=y[p],J=p===y.length-1;await z(t,s,G.node_id,"",J,V,g,a,o)}return u!==null&&g.push(`Tickets: unavailable (${u}).`),g.join(`
2
+ `)}f(tt,"renderTreeFromSource");async function Nt(t,e,n,i){const c=e??await t.listNodes();if(c.length===0)return"(canvas is empty)";const a=c.filter(r=>r.parent===null&&(r.status==="active"||r.status==="idle"));if(a.length===0)return"(no live roots)";const s=[];for(const r of a)s.push(await tt(t,r.node_id,c,n,i));return s.join(`
3
3
 
4
- `)}u(bt,"renderForestFromSource");const D=4096;function nt(t){try{const e=S(Q(t),"initial-prompt.md");if(!$(e))return;const n=g(e,"utf8").trim();return n===""?void 0:n.length>D?n.slice(0,D):n}catch{return}}u(nt,"readGoalText");const F=1024;function rt(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})?$/);if(e!==null)return`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}.${e[7]??"000"}Z`}u(rt,"reportStampToIso");function it(t){let e;try{for(const l of H(j(t)))l.endsWith(".md")&&(e===void 0||l>e)&&(e=l)}catch{return}if(e===void 0)return;let n;try{n=g(S(j(t),e),"utf8")}catch{return}const{data:r,body:a}=I(n),f=e.replace(/\.md$/,""),i=typeof r?.kind=="string"?r.kind:f.split("-").pop()??"report",s=typeof r?.ts=="string"?r.ts:rt(f.split("-")[0]??"")??"",o=a.split(`
5
- `);let c="",d=a;for(let l=0;l<o.length;l++){const h=(o[l]??"").trim();if(h!==""){c=h.startsWith("#")?h.replace(/^#+\s*/,"").trim():h,d=o.slice(l+1).join(`
6
- `);break}}const p=d.replace(/\s+/g," ").trim();return{kind:i,ts:s,heading:c,body:p.length>F?p.slice(0,F):p}}u(it,"readNewestReport");const st=1<<20,ot=1<<20,at=4<<20;function J(t,e,n){if(t==null||t==="")return null;try{if(!$(t))return null;const r=C(t).size;if(r<=e+n){const f=g(t,"utf8").split(`
7
- `);return{head:f,tail:f}}const a=Z(t,"r");try{const f=u((o,c)=>{if(c<=0)return[];const d=Buffer.allocUnsafe(c),p=q(a,d,0,c,o);return d.subarray(0,p).toString("utf8").split(`
8
- `)},"slice"),i=f(0,e),s=f(r-n,n);return i.length>0&&i.pop(),s.length>0&&s.shift(),{head:i,tail:s}}finally{K(a)}}catch{return null}}u(J,"readSessionWindow");const R=8192,T=2048;function ct(t){const e=J(t,st,ot);if(e===null)return{};const n=[];let r=0;for(const i of e.head){if(i===""||i.indexOf('"role":"user"')===-1&&i.indexOf('"role": "user"')===-1)continue;let s;try{s=JSON.parse(i)}catch{continue}if(s.type!=="message"||s.message?.role!=="user")continue;const o=v(s.message.content);if(o===""||z({role:"user",content:o})!==null)continue;const c=o.length>T?o.slice(0,T):o;if(n.push(c),r+=c.length+1,r>=R)break}let a;if(n.length>0){const i=n.join(`
9
- `);a=i.length>R?i.slice(0,R):i}let f;for(let i=e.tail.length-1;i>=0;i--){const s=e.tail[i];if(s===""||s.indexOf('"role":"assistant"')===-1&&s.indexOf('"role": "assistant"')===-1)continue;let o;try{o=JSON.parse(s)}catch{continue}if(o.type!=="message"||o.message?.role!=="assistant")continue;const c=v(o.message.content);if(c!==""){f=c.length>T?c.slice(0,T):c;break}}return{prompts:a,lastAssistant:f}}u(ct,"readSessionParts");const V=120,G=4096;function ft(t){const e=J(t,0,at);if(e===null)return[];const n=[];for(const r of e.tail){if(r==="")continue;const a=r.indexOf('"role":"user"')!==-1||r.indexOf('"role": "user"')!==-1,f=!a&&(r.indexOf('"role":"assistant"')!==-1||r.indexOf('"role": "assistant"')!==-1);if(!a&&!f)continue;let i;try{i=JSON.parse(r)}catch{continue}if(i.type!=="message")continue;const s=i.message?.role;if(s!=="user"&&s!=="assistant")continue;const o=v(i.message?.content);o!==""&&z({role:s,content:o})===null&&n.push({role:s,text:o.length>G?o.slice(0,G):o})}return n.length>V?n.slice(n.length-V):n}u(ft,"readTranscript");function Tt(t){if(t==null||t==="")return!1;let e;try{if(!$(t))return!1;e=g(t,"utf8").split(`
10
- `)}catch{return!1}for(const n of e){if(n===""||n.indexOf('"role":"assistant"')===-1&&n.indexOf('"role": "assistant"')===-1)continue;let r;try{r=JSON.parse(n)}catch{continue}if(!(r.type!=="message"||r.message?.role!=="assistant")&&ut(r.message.content))return!0}return!1}u(Tt,"nodeHasAssistantMessage");function ut(t){if(typeof t=="string")return t.trim()!=="";if(!Array.isArray(t))return!1;for(const e of t){if(e===null||typeof e!="object")continue;const n=e,r=(n.type??"").toLowerCase();if(r==="text"){if(typeof n.text=="string"&&n.text.trim()!=="")return!0}else if(r==="thinking"){if(typeof n.thinking=="string"&&n.thinking.trim()!=="")return!0}else return!0}return!1}u(ut,"assistantContentIsSubstantive");function v(t){if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";const e=[];for(const n of t)if(n!==null&&typeof n=="object"){const r=n;r.type==="text"&&typeof r.text=="string"&&e.push(r.text)}return e.join(" ").trim()}u(v,"extractUserText");function lt(t,e,n=!1){if(!n)try{const a=C(S(A(t),"telemetry.json"),{throwIfNoEntry:!1});if(a!==void 0)return a.mtimeMs}catch{}const r=Date.parse(e);return Number.isNaN(r)?0:r}u(lt,"sessionMtime");function dt(t){if(t.status!=="active")return!1;try{const e=JSON.parse(g(S(A(t.node_id),"attach.json"),"utf8"));return typeof e.viewers=="number"&&e.viewers>0}catch{return!1}}u(dt,"hasLiveBrokerViewer");function pt(t,e,n){const r=t.status==="active"||t.status==="idle",a=t.fault??null;return{node_id:t.node_id,name:N(t),handle:t.name,description:t.description,status:t.status,frozen_at:t.frozen_at??null,terminal_reason:t.terminal_reason??null,kind:t.kind,mode:t.mode,ctx_tokens:0,asks:0,cwd:t.cwd,profile_id:t.profile_id,created:t.created,lifecycle:t.lifecycle,finalized:t.final_report!=null,mtimeMs:lt(t.node_id,t.created,n),streaming:a===null&&r&&t.streaming===!0,hanging:a,viewed:n?!1:e.has(t.node_id)||dt(t),srcRow:t}}u(pt,"dashboardRowFromNodeRow");async function Ot(t,e,n,r){const a=t instanceof y,f=r??await t.ticketCountsForView(e).catch(()=>({})),i=new Map((n??await t.listNodes()).map(o=>[o.node_id,o]));return[e,...await t.view(e)].flatMap(o=>{const c=i.get(o);if(c===void 0)return[];const d=a?{}:b(o);return[{node_id:o,name:N(c),handle:c.name,description:c.description,status:c.status,frozen_at:c.frozen_at??null,terminal_reason:c.terminal_reason??null,kind:c.kind,mode:c.mode,ctx_tokens:d.tokens_in??0,asks:f[o]??0,cwd:c.cwd,profile_id:c.profile_id,created:c.created}]})}u(Ot,"dashboardRowsFromSource");async function At(t,e=new Set,n=!1,r){const a=t instanceof y,f=a?new Set:e;return(r??await t.listNodes(n?{status:["active","idle"]}:void 0)).map(s=>pt(s,f,a))}u(At,"dashboardRowsAllFromSource");async function Rt(t,e,n){const r=e.filter(i=>i.enriched!==!0);if(r.length===0)return;const a=t instanceof y,f=n??{};for(const i of r)i.ctx_tokens=a?0:b(i.node_id).tokens_in??0,i.asks=f[i.node_id]??0,i.enriched=!0}u(Rt,"enrichRowsFromSource");async function vt(t,e){if(e.previewLoaded===!0)return e;const n=t instanceof y;if(e.goal=n?void 0:nt(e.node_id),!n){const r=await t.getNode(e.node_id),{prompts:a,lastAssistant:f}=ct(r?.pi_session_file);e.prompts=a,e.lastAssistant=f,e.recap=X(e.node_id),e.report=it(e.node_id)}return e.previewLoaded=!0,e}u(vt,"loadPreviewFromSource");async function Ct(t,e){if(e.transcriptLoaded===!0)return e;if(t instanceof y)return e.transcript=[],e.transcriptLoaded=!0,e;const n=await t.getNode(e.node_id);return e.transcript=ft(n?.pi_session_file),e.transcriptLoaded=!0,e}u(Ct,"loadTranscriptFromSource");export{pt as dashboardRowFromNodeRow,At as dashboardRowsAllFromSource,Ot as dashboardRowsFromSource,Rt as enrichRowsFromSource,w as fmtCtx,vt as loadPreviewFromSource,Ct as loadTranscriptFromSource,Tt as nodeHasAssistantMessage,nt as readGoalText,it as readNewestReport,b as readNodeTelemetry,ct as readSessionParts,ft as readTranscript,bt as renderForestFromSource,et as renderTreeFromSource,lt as sessionMtime};
4
+ `)}f(Nt,"renderForestFromSource");const M=4096;function et(t){try{const e=T(K(t),"initial-prompt.md");if(!b(e))return;const n=_(e,"utf8").trim();return n===""?void 0:n.length>M?n.slice(0,M):n}catch{return}}f(et,"readGoalText");const E=1024;function nt(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})?$/);if(e!==null)return`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}.${e[7]??"000"}Z`}f(nt,"reportStampToIso");function it(t){let e;try{for(const l of B(R(t)))l.endsWith(".md")&&(e===void 0||l>e)&&(e=l)}catch{return}if(e===void 0)return;let n;try{n=_(T(R(t),e),"utf8")}catch{return}const{data:i,body:c}=X(n),a=e.replace(/\.md$/,""),s=typeof i?.kind=="string"?i.kind:a.split("-").pop()??"report",r=typeof i?.ts=="string"?i.ts:nt(a.split("-")[0]??"")??"",o=c.split(`
5
+ `);let u="",m=c;for(let l=0;l<o.length;l++){const h=(o[l]??"").trim();if(h!==""){u=h.startsWith("#")?h.replace(/^#+\s*/,"").trim():h,m=o.slice(l+1).join(`
6
+ `);break}}const d=m.replace(/\s+/g," ").trim();return{kind:s,ts:r,heading:u,body:d.length>E?d.slice(0,E):d}}f(it,"readNewestReport");const rt=1<<20,st=1<<20,ot=4<<20;function w(t,e,n){if(t==null||t==="")return null;try{if(!b(t))return null;const i=U(t).size;if(i<=e+n){const a=_(t,"utf8").split(`
7
+ `);return{head:a,tail:a}}const c=W(t,"r");try{const a=f((o,u)=>{if(u<=0)return[];const m=Buffer.allocUnsafe(u),d=H(c,m,0,u,o);return m.subarray(0,d).toString("utf8").split(`
8
+ `)},"slice"),s=a(0,e),r=a(i-n,n);return s.length>0&&s.pop(),r.length>0&&r.shift(),{head:s,tail:r}}finally{Z(c)}}catch{return null}}f(w,"readSessionWindow");const O=8192,k=2048;function at(t){const e=w(t,rt,st);if(e===null)return{};const n=[];let i=0;for(const s of e.head){if(s===""||s.indexOf('"role":"user"')===-1&&s.indexOf('"role": "user"')===-1)continue;let r;try{r=JSON.parse(s)}catch{continue}if(r.type!=="message"||r.message?.role!=="user")continue;const o=A(r.message.content);if(o===""||L({role:"user",content:o})!==null)continue;const u=o.length>k?o.slice(0,k):o;if(n.push(u),i+=u.length+1,i>=O)break}let c;if(n.length>0){const s=n.join(`
9
+ `);c=s.length>O?s.slice(0,O):s}let a;for(let s=e.tail.length-1;s>=0;s--){const r=e.tail[s];if(r===""||r.indexOf('"role":"assistant"')===-1&&r.indexOf('"role": "assistant"')===-1)continue;let o;try{o=JSON.parse(r)}catch{continue}if(o.type!=="message"||o.message?.role!=="assistant")continue;const u=A(o.message.content);if(u!==""){a=u.length>k?u.slice(0,k):u;break}}return{prompts:c,lastAssistant:a}}f(at,"readSessionParts");const D=120,F=4096;function ct(t){const e=w(t,0,ot);if(e===null)return[];const n=[];for(const i of e.tail){if(i==="")continue;const c=i.indexOf('"role":"user"')!==-1||i.indexOf('"role": "user"')!==-1,a=!c&&(i.indexOf('"role":"assistant"')!==-1||i.indexOf('"role": "assistant"')!==-1);if(!c&&!a)continue;let s;try{s=JSON.parse(i)}catch{continue}if(s.type!=="message")continue;const r=s.message?.role;if(r!=="user"&&r!=="assistant")continue;const o=A(s.message?.content);o!==""&&L({role:r,content:o})===null&&n.push({role:r,text:o.length>F?o.slice(0,F):o})}return n.length>D?n.slice(n.length-D):n}f(ct,"readTranscript");function bt(t){if(t==null||t==="")return!1;let e;try{if(!b(t))return!1;e=_(t,"utf8").split(`
10
+ `)}catch{return!1}for(const n of e){if(n===""||n.indexOf('"role":"assistant"')===-1&&n.indexOf('"role": "assistant"')===-1)continue;let i;try{i=JSON.parse(n)}catch{continue}if(!(i.type!=="message"||i.message?.role!=="assistant")&&ut(i.message.content))return!0}return!1}f(bt,"nodeHasAssistantMessage");function ut(t){if(typeof t=="string")return t.trim()!=="";if(!Array.isArray(t))return!1;for(const e of t){if(e===null||typeof e!="object")continue;const n=e,i=(n.type??"").toLowerCase();if(i==="text"){if(typeof n.text=="string"&&n.text.trim()!=="")return!0}else if(i==="thinking"){if(typeof n.thinking=="string"&&n.thinking.trim()!=="")return!0}else return!0}return!1}f(ut,"assistantContentIsSubstantive");function A(t){if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";const e=[];for(const n of t)if(n!==null&&typeof n=="object"){const i=n;i.type==="text"&&typeof i.text=="string"&&e.push(i.text)}return e.join(" ").trim()}f(A,"extractUserText");function ft(t,e,n=!1){if(!n&&e!==null&&e!==void 0){const c=Date.parse(e);if(!Number.isNaN(c))return c}const i=Date.parse(t);return Number.isNaN(i)?0:i}f(ft,"sessionMtime");function lt(t){if(t.status!=="active")return!1;try{const e=JSON.parse(_(T(q(t.node_id),"attach.json"),"utf8"));return typeof e.viewers=="number"&&e.viewers>0}catch{return!1}}f(lt,"hasLiveBrokerViewer");function dt(t,e,n){const i=t.status==="active"||t.status==="idle",c=t.fault??null;return{node_id:t.node_id,name:$(t),handle:t.name,description:t.description,status:t.status,frozen_at:t.frozen_at??null,terminal_reason:t.terminal_reason??null,kind:t.kind,mode:t.mode,ctx_tokens:n?0:t.telemetry_tokens_in??0,asks:0,cwd:t.cwd,profile_id:t.profile_id,created:t.created,lifecycle:t.lifecycle,finalized:t.final_report!=null,mtimeMs:ft(t.created,t.telemetry_updated_at,n),streaming:c===null&&i&&t.streaming===!0,hanging:c,viewed:n?!1:e.has(t.node_id)||lt(t),srcRow:t}}f(dt,"dashboardRowFromNodeRow");async function Tt(t,e,n,i){const c=t instanceof x,a=i??await t.ticketCountsForView(e).catch(()=>({})),s=new Map((n??await t.listNodes()).map(o=>[o.node_id,o]));return[e,...await t.view(e)].flatMap(o=>{const u=s.get(o);return u===void 0?[]:[{node_id:o,name:$(u),handle:u.name,description:u.description,status:u.status,frozen_at:u.frozen_at??null,terminal_reason:u.terminal_reason??null,kind:u.kind,mode:u.mode,ctx_tokens:c?0:u.telemetry_tokens_in??0,asks:a[o]??0,cwd:u.cwd,profile_id:u.profile_id,created:u.created}]})}f(Tt,"dashboardRowsFromSource");async function Ot(t,e=new Set,n=!1,i){const c=t instanceof x,a=c?new Set:e;return(i??await t.listNodes(n?{status:["active","idle"]}:void 0)).map(r=>dt(r,a,c))}f(Ot,"dashboardRowsAllFromSource");async function At(t,e,n){const i=e.filter(a=>a.enriched!==!0);if(i.length===0)return;const c=n??{};for(const a of i)a.asks=c[a.node_id]??0,a.enriched=!0}f(At,"enrichRowsFromSource");async function Rt(t,e){if(e.previewLoaded===!0)return e;const n=t instanceof x;if(e.goal=n?void 0:et(e.node_id),!n){const i=await t.getNode(e.node_id),{prompts:c,lastAssistant:a}=at(i?.pi_session_file);e.prompts=c,e.lastAssistant=a,e.recap=Q(e.node_id),e.report=it(e.node_id)}return e.previewLoaded=!0,e}f(Rt,"loadPreviewFromSource");async function vt(t,e){if(e.transcriptLoaded===!0)return e;if(t instanceof x)return e.transcript=[],e.transcriptLoaded=!0,e;const n=await t.getNode(e.node_id);return e.transcript=ct(n?.pi_session_file),e.transcriptLoaded=!0,e}f(vt,"loadTranscriptFromSource");export{dt as dashboardRowFromNodeRow,Ot as dashboardRowsAllFromSource,Tt as dashboardRowsFromSource,At as enrichRowsFromSource,j as fmtCtx,Rt as loadPreviewFromSource,vt as loadTranscriptFromSource,bt as nodeHasAssistantMessage,et as readGoalText,it as readNewestReport,at as readSessionParts,ct as readTranscript,Nt as renderForestFromSource,tt as renderTreeFromSource,ft as sessionMtime};
@@ -294,6 +294,14 @@ export interface NodeRuntime {
294
294
  outcome_detail_json?: string | null;
295
295
  /** Absolute wall-clock spawn deadline, or null when unbounded. */
296
296
  deadline_at?: string | null;
297
+ /** Cumulative input tokens reported by the broker telemetry producer. */
298
+ telemetry_tokens_in?: number | null;
299
+ /** Latest live context-window token gauge reported by the broker. */
300
+ telemetry_context_tokens?: number | null;
301
+ /** Latest tool summary reported by the broker. */
302
+ telemetry_last_activity?: string | null;
303
+ /** Timestamp of the latest broker telemetry update. */
304
+ telemetry_updated_at?: string | null;
297
305
  /** OS pid of the live broker process, recorded on boot (stophook session_start).
298
306
  * The daemon's authoritative liveness signal — every node is a detached broker,
299
307
  * so `isPidAlive(pi_pid)` is the sole liveness check. Cleared to null by
@@ -381,6 +389,14 @@ export interface NodeRow {
381
389
  outcome_revision?: number;
382
390
  outcome_detail_json?: string | null;
383
391
  deadline_at?: string | null;
392
+ /** Cumulative input tokens reported by the broker telemetry producer. */
393
+ telemetry_tokens_in?: number | null;
394
+ /** Latest live context-window token gauge reported by the broker. */
395
+ telemetry_context_tokens?: number | null;
396
+ /** Latest tool summary reported by the broker. */
397
+ telemetry_last_activity?: string | null;
398
+ /** Timestamp of the latest broker telemetry update. */
399
+ telemetry_updated_at?: string | null;
384
400
  pi_pid: number | null;
385
401
  /** See `NodeRuntime.pi_pid_identity`. */
386
402
  pi_pid_identity: string | null;
@@ -1 +1 @@
1
- var Te=Object.defineProperty;var s=(e,n)=>Te(e,"name",{value:n,configurable:!0});import{envProfileId as $e}from"../shared/env.js";import{basename as Ce,dirname as Me,join as H}from"node:path";import{isDeepStrictEqual as Le}from"node:util";import{CONFIG_FILE as Ne,STATE_FILE as Fe,CONDENSED_HISTORY_MODES as ze,MOUSE_MODE_DEFAULTS as De,WHIP_MESSAGE_MODES as Ue,DEFAULT_WHIP_MESSAGES as J,defaultScopeConfig as b,defaultScopeState as Ke,defaultModelLaddersConfig as qe,defaultKindsConfig as Ge,defaultRemoteCanvasConfig as Be}from"../types.js";import{BINDING_CATALOG as He,BINDING_IDS as Je,isAttachPaneBinding as We}from"./keybindings/catalog.js";import{notFound as Ze,usage as Ye}from"./errors.js";import{emitEvent as Ve}from"./events/emit.js";import{atomicWriteJson as W,readJsonIfExists as M,ensureDir as Z}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as _,findProjectScopeRoots as Qe,userScopeRoot as L}from"./scope.js";import{listInstalledPluginsInRoot as Y}from"./installed-plugins.js";import{profileRoot as N,listProfiles as V}from"./profiles/manifest.js";import{canonicalRoot as F,projectStore as Xe,userStore as Q}from"./scoped-state/paths.js";import{convertLegacyScopedStore as en,initializeFreshScopedStore as nn}from"./scoped-state/migrate.js";import{mutateRawSettings as on,readBookkeeping as tn,readRawSettings as rn,readRawSettingsWithRevision as sn,replaceRawSettings as dn,writeBookkeeping as cn,writeRawSettings as un}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as ln}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as fn}from"./user-settings.js";import{normalizeWorkingGerunds as an}from"../shared/working-activity.js";import{mergePageComponentLayers as mn,normalizePageComponents as X}from"./human/page-catalog.js";function h(e){return H(e,Ne)}s(h,"configPathFor");function ee(e,n){return Z(Me(e)),ln(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ee,"withConfigPathLock");function pn(e){return H(e,Fe)}s(pn,"statePathFor");function co(e){const n=y(e);return n?h(n):null}s(co,"configPath");function uo(e){const n=y(e);return n?pn(n):null}s(uo,"statePath");function g(e){const n=F(e),t=F(L());if(n===t)return{store:Q(t),key:"user",kind:"user",root:t};if(Ce(n)===".crouter")return en({kind:"project",root:n}),{store:Xe(n),key:"project",kind:"project",root:n};for(const o of V()){const r=F(N(o.profileId));if(n===r)return{store:Q(t),key:`profile:${o.profileId}`,kind:"profile",root:r,profileId:o.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function j(e){const n=g(e);return n.kind==="project"?M(h(n.root)):rn(n)}s(j,"readRawAtRoot");function z(e,n){const t=g(e);if(t.kind==="project"){ee(h(t.root),o=>W(o,n));return}un(t,n)}s(z,"writeRawAtRoot");function v(e,n){const t=g(e);return t.kind==="project"?ee(h(t.root),o=>{const r=n(M(o)??{});return W(o,r.next),r.value}):on(t,o=>n(o))}s(v,"mutateRawAtRoot");function gn(e){const n=y(e);return n?yn(n):b()}s(gn,"readConfig");function yn(e){const n=j(e);return n?T(n):b()}s(yn,"readConfigAtRoot");function hn(e){const n=y(e);return n?tn(g(n)):Ke()}s(hn,"readState");class bn extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function ne(e){if(e.scope==="user")return g(L());if(!V().some(n=>n.profileId===e.profileId))throw Ze(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(N(e.profileId))}s(ne,"rawSettingsOwnerForTarget");function lo(e){return sn(ne(e))}s(lo,"readRawSettingsForTarget");function fo(e,n,t){return dn(ne(e),n,t,o=>{try{T(o)}catch(r){throw new bn(r)}})}s(fo,"replaceRawSettingsForTarget");function ao(e,n){const t=_(e);return v(t,o=>{const r=n(o);return{value:r,next:r}})}s(ao,"updateRawConfigAtomically");function mo(e,n){z(_(e),n)}s(mo,"writeConfig");function po(e,n){z(_(e),n)}s(po,"writeRawConfig");function _n(e,n){const t=_(e);cn(g(t),n)}s(_n,"writeState");function go(e,n){Z(n);const t=g(e==="user"?L():n);if(nn({kind:t.kind==="user"?"user":"project",root:t.store.root}),t.kind==="project"&&M(h(t.root))===null){const{modelLadders:o,keybindings:r,tmux_passthrough:i,brokerThresholds:d,lifecycle:c,...u}=b();z(t.root,u)}}s(go,"ensureScopeInitialized");function vn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))Array.isArray(o)&&o.every(r=>typeof r=="string")&&(n[t]=[...o]);return n}s(vn,"normalizeKeybindings");const kn=new Set(He.filter(We).map(e=>e.id));function wn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&Je.has(n)&&kn.has(n)))]:[]}s(wn,"normalizeTmuxPassthrough");function S(e,n=qe()){const t=n;if(e===null||typeof e!="object")return t;const o=e,r={anthropic:{...t.anthropic},openai:{...t.openai},...t.defaultProvider!==void 0?{defaultProvider:t.defaultProvider}:{}};(o.defaultProvider==="anthropic"||o.defaultProvider==="openai")&&(r.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"]){const d=o[i];if(!(d===null||typeof d!="object"))for(const[c,u]of Object.entries(d))(c==="ultra"||c==="strong"||c==="medium"||c==="light")&&typeof u=="string"&&(r[i][c]=u)}return r}s(S,"mergeModelLadders");function oe(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(oe,"validStrength");const D=["ultra","strong","medium","light"];function U(){return Object.create(null)}s(U,"routeRecord");function k(e,n,t){Object.defineProperty(e,n,{value:t,writable:!0,enumerable:!0,configurable:!0})}s(k,"setRouteRecord");function te(e){const n=U();for(const[t,o]of Object.entries(e??{}))k(n,t,o);return n}s(te,"copyRouteRecord");function w(e,n){Ve({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(w,"routeInvalid");function x(e,n={}){const t=te(n);if(e===null||typeof e!="object"||Array.isArray(e))return t;for(const[o,r]of Object.entries(e)){if(o.trim()===""){w(o,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){w(o,"route must be an object");continue}const i=r,d=t[o],c={...d};let u;for(const f of["family","credentialSource","providerId"]){const l=i[f];if(l!==void 0){if(typeof l!="string"||l.trim()===""){u=`${f} must be a non-empty string`;break}c[f]=l}}if(u===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))u="models must be an object";else{const f={...d?.models};for(const[l,a]of Object.entries(i.models)){if(!oe(l)){u=`models.${l} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){u=`models.${l} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){u=`models.${l} must be provider/id`;break}f[l]=a}c.models=f}if(u===void 0&&c.models!==void 0&&c.providerId!==void 0){for(const[f,l]of Object.entries(c.models))if(l.slice(0,l.indexOf("/"))!==c.providerId){u=`models.${f} provider prefix must equal providerId`;break}}if(u!==void 0){w(o,u);continue}k(t,o,c)}return t}s(x,"mergeModelRoutePatches");function re(e){const n=U(),t=U();for(const[o,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){w(o,"route must include family, credentialSource, providerId, and models");continue}const i=D.filter(d=>r.models[d]===void 0);if(i.length>0){w(o,`incomplete route; missing strengths: ${i.join(", ")}`),k(t,o,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}k(n,o,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:t}}s(re,"resolveModelRoutes");function An(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const o of["family","credentialSource","providerId"])if(typeof n[o]!="string"||n[o].trim()==="")throw new Error(`model route "${e}" ${o} must be a non-empty string`);const t=D.filter(o=>n.models?.[o]===void 0);if(t.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${t.join(", ")}`);for(const o of D){const r=n.models[o];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${o} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${o} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${o} provider prefix must equal providerId`)}}s(An,"assertCompleteModelRoute");function O(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const t=e,o=s(i=>Array.isArray(i)&&i.every(d=>typeof d=="string"&&d.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(t.strengthFallback)&&t.strengthFallback.every(i=>oe(i))?[...t.strengthFallback]:void 0;return{...o(t.credentialSourceOrder)!==void 0?{credentialSourceOrder:o(t.credentialSourceOrder)}:{},...o(t.familyOrder)!==void 0?{familyOrder:o(t.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(O,"mergeModelRouting");function Rn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Rn,"isInheritAllGlob");function E(e,n=[]){const t=e,o=Array.isArray(t?.allow)?t.allow.filter(r=>typeof r=="string"):[];for(const r of o)if(Rn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...o])]}}s(E,"mergeSpawnEnv");function I(e,n={}){const t={};for(const[o,r]of Object.entries(n))t[o]={...r};if(e!==null&&typeof e=="object")for(const[o,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...t[o]},d=r.fastMode;typeof d=="boolean"&&(i.fastMode=d),t[o]=i}return t}s(I,"mergeProviderOptions");const ie=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,jn=new Set(["crtr","crtrd"]);function P(e,n){if(n==="bin"&&jn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!ie.test(e))return`${n}.${e} is not a safe bare command name (expected ${ie.source})`}s(P,"bareCommandNameIssue");function Sn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[t,o]of Object.entries(e)){const r=P(t,"bin");r!==void 0&&n.push({name:t,message:r}),(typeof o!="string"||o.trim()==="")&&n.push({name:t,message:`bin.${t} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Sn,"binDeclarationIssues");function xn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))P(t,"bin")===void 0&&(typeof o!="string"||o.trim()===""||(n[t]=o));return n}s(xn,"normalizeBin");const se=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function On(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[t,o]of Object.entries(e)){const r=[];if(se.test(t)||r.push(`action name must match ${se.source}`),o===null||typeof o!="object"||Array.isArray(o))r.push("action must be an object with argv and cwd");else{const i=o,d=Object.keys(i).filter(c=>c!=="argv"&&c!=="cwd");d.length>0&&r.push(`action has unsupported field${d.length===1?"":"s"}: ${d.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(c=>typeof c=="string"&&c.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:t,reason:r.join("; ")})}return n}s(On,"humanActionDeclarationIssues");function En(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(On(e).map(o=>o.name)),t={};for(const[o,r]of Object.entries(e)){if(n.has(o))continue;const i=r;t[o]={argv:[...i.argv],cwd:i.cwd}}return t}s(En,"normalizeHumanActions");function yo(e){return Sn(e).map(n=>n.message)}s(yo,"invalidPluginBinReasons");function ho(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))P(t,"requires")===void 0&&(typeof o!="string"||o.trim()===""||/[\r\n]/.test(o)||(n[t]=o));return n}s(ho,"normalizeRequires");function bo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[t,o]of Object.entries(e)){const r=P(t,"requires");r!==void 0&&n.push(r),typeof o!="string"||o.trim()===""?n.push(`requires.${t} must be a non-empty one-line install hint`):/[\r\n]/.test(o)&&n.push(`requires.${t} must be a one-line install hint`)}return n}s(bo,"invalidPluginRequiresReasons");function de(e){if(e===null||typeof e!="object")return null;const n=e,t={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(t.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(t.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(t.orchestratorModel=n.orchestratorModel);const o=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return o(n.tools)&&(t.tools=n.tools),o(n.extensions)&&(t.extensions=n.extensions),o(n.availableTo)&&(t.availableTo=n.availableTo),Object.keys(t).length>0?t:null}s(de,"normalizeKindFields");function A(e,n=Ge()){const t={...n};if(e!==null&&typeof e=="object")for(const[o,r]of Object.entries(e)){const i=de(r);if(i===null)continue;const d=t[o];d!==void 0?t[o]={...d,...i}:i.whenToUse!==void 0&&(t[o]=i)}return t}s(A,"mergeKinds");function ce(e,n,t){if(n===null)return t;const o=Y(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,d)=>i.name.localeCompare(d.name));let r=t;for(const i of o)r=A(i.manifest.kinds,r);return r}s(ce,"layerPluginKinds");function _o(){const e=[{origin:"config.json",components:gn("user").page_components}],n=y("user");if(n!==null){const t=Y("user",n).filter(o=>o.enabled&&o.manifest.page_components!==void 0).sort((o,r)=>o.name.localeCompare(r.name));for(const o of t){const r=`plugin "${o.name}" page_components`;e.push({origin:`plugin "${o.name}"`,components:X(o.manifest.page_components,r)})}}return mn(e)}s(_o,"resolvePageComponents");const K=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function vo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],t=s(o=>Array.isArray(o)&&o.every(r=>typeof r=="string"),"isStringArray");for(const[o,r]of Object.entries(e)){if(o.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${o} must be a JSON object`);continue}const i=r;for(const d of Object.keys(i))K.has(d)||n.push(`kinds.${o}.${d} is not a KindConfig field (expected one of: ${[...K].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${o}.whenToUse must be a non-empty string`);for(const d of["model","orchestratorModel"])i[d]!==void 0&&(typeof i[d]!="string"||i[d].trim()==="")&&n.push(`kinds.${o}.${d} must be a non-empty string`);for(const d of["tools","extensions","availableTo"])i[d]!==void 0&&!t(i[d])&&n.push(`kinds.${o}.${d} must be an array of strings`);de(r)===null&&n.push(`kinds.${o} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...K].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(vo,"invalidPluginKindsReasons");function In(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const t={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(t.cpOrigin=n.cpOrigin),t}s(In,"normalizeRemoteCanvasTarget");function Pn(e,n=Be()){const t={...n.targets};if(e!==null&&typeof e=="object"){const o=e;if(o.targets!==null&&typeof o.targets=="object")for(const[r,i]of Object.entries(o.targets)){const d=In(i);d!==null&&(t[r]=d)}}return{targets:t}}s(Pn,"mergeRemoteCanvas");function ue(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(ue,"normalizeMode");function R(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(R,"normalizePositiveInteger");function Tn(e,n){const t=e!==null&&typeof e=="object"?e:{},o=R(t.warning,n.warning),r=R(t.automaticReviveCap,n.automaticReviveCap);return o<=r?{warning:o,automaticReviveCap:r}:{...n}}s(Tn,"mergeBrokerThresholds");function $n(e,n){return{unattendedParkMs:R((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s($n,"mergeLifecycle");function Cn(e){if(!Array.isArray(e))return[...J];const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:[...J]}s(Cn,"normalizeWhipMessages");function T(e){const n=b(),t=n.schema_version,o=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,d=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,c=d!==void 0&&Number.isFinite(d)&&d>=0?d:n.auto_update.interval_hours,u={crtr:ue(i?.crtr,n.auto_update.crtr),content:ue(i?.content,n.auto_update.content),interval_hours:c},f=e.max_panes_per_window,l=R(f,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=Tn(e.brokerThresholds,n.brokerThresholds),$=$n(e.lifecycle,n.lifecycle),p=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,le=e.working_gerunds===void 0?[...n.working_gerunds]:an(e.working_gerunds),fe=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,ae=X(e.page_components),me=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,pe=Cn(e.whip_messages),ge=Ue.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,ye=De.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,he=R(e.live_cycles,n.live_cycles),be=ze.includes(e.condensed_history)?e.condensed_history:n.condensed_history,_e=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,ve=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,ke=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,we=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Ae=vn(e.keybindings),Re=wn(e.tmux_passthrough),je=S(e.modelLadders),Se=I(e.providerOptions,n.providerOptions),C=re(x(e.modelRoutes)),G=C.complete,B=O(e.modelRouting,void 0),xe=A(e.kinds),Oe=Pn(e.remoteCanvas),Ee=E(e.spawnEnv,n.spawnEnv?.allow),Ie=xn(e.bin),Pe=En(e.humanActions);return{bin:Ie,humanActions:Pe,schema_version:t,marketplaces:o,plugins:r,auto_update:u,max_panes_per_window:l,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:$,completion_bell:p,working_gerunds:le,whip_mode:fe,page_components:ae,page_surface:me,whip_messages:pe,whip_message_mode:ge,mouse_mode_default:ye,live_cycles:he,condensed_history:be,bash_tool_purpose:_e,fold_finished_tools:ve,summarize_tool_calls:ke,detailed_tool_recaps:we,keybindings:Ae,tmux_passthrough:Re,modelLadders:je,providerOptions:Se,...Object.keys(G).length>0?{modelRoutes:G}:{},...Object.keys(C.legacy).length>0?{legacyModelRoutes:C.legacy}:{},...B!==void 0?{modelRouting:B}:{},kinds:xe,remoteCanvas:Oe,spawnEnv:Ee}}s(T,"mergeConfig");function Mn(e){return j(e)}s(Mn,"readRawConfigAtRoot");function Ln(e){const n=y(e);return n?Mn(n):null}s(Ln,"readRawScopeConfig");function Nn(e){if(e===null||e==="")return null;try{return j(N(e))}catch{return null}}s(Nn,"readRawProfileConfig");function Fn(e,n){return[...Qe(e,n)].reverse().map(r=>({root:r,raw:j(r)}))}s(Fn,"readRawProjectScopeConfigs");function q(e=process.cwd(),n=$e()||null){const t=b(),o=Ln("user"),r=Nn(n),i=Fn(e,n);let d=A(o?.kinds,ce("user",y("user"),t.kinds)),c=S(o?.modelLadders,t.modelLadders),u=I(o?.providerOptions,t.providerOptions),f=x(o?.modelRoutes),l=O(o?.modelRouting,void 0),a=E(o?.spawnEnv,t.spawnEnv?.allow);r!==null&&(d=A(r.kinds,d),c=S(r.modelLadders,c),u=I(r.providerOptions,u),f=x(r.modelRoutes,f),l=O(r.modelRouting,l),a=E(r.spawnEnv,a.allow));for(const{root:$,raw:p}of i)d=A(p?.kinds,ce("project",$,d)),p!==null&&(c=S(p.modelLadders,c),u=I(p.providerOptions,u),f=x(p.modelRoutes,f),l=O(p.modelRouting,l),a=E(p.spawnEnv,a.allow));const m=re(f);return{kinds:d,modelLadders:c,providerOptions:u,...Object.keys(m.complete).length>0?{modelRoutes:m.complete}:{},...Object.keys(m.legacy).length>0?{legacyModelRoutes:m.legacy}:{},...l!==void 0?{modelRouting:l}:{},spawnEnv:a}}s(q,"readMergedLaunchConfig");function ko(e){return q().kinds[e]}s(ko,"resolveKindConfig");function wo(e){const n=Object.keys(q().kinds).sort();if(!n.includes(e))throw Ye(`unknown kind: ${e}`,{received:e,field:"kind",next:`Valid kinds: ${n.join(", ")}.`})}s(wo,"assertInstalledKind");function Ao(e){const n=q().kinds,t=[];for(const[o,r]of Object.entries(n)){const i=o.indexOf("/");if(i===-1)continue;const d=o.slice(0,i),c=r.availableTo??[d];(c.includes("*")||c.includes(e))&&t.push({kind:o,whenToUse:r.whenToUse})}return t.sort((o,r)=>o.kind.localeCompare(r.kind))}s(Ao,"subKindsAvailableTo");function zn(e,n,t){const o={...e??{}};o.anthropic!==void 0&&(o.anthropic={...o.anthropic}),o.openai!==void 0&&(o.openai={...o.openai}),t.defaultProvider!==n.defaultProvider&&t.defaultProvider!==void 0&&(o.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"])for(const d of["ultra","strong","medium","light"])t[i][d]!==n[i][d]&&(o[i]={...o[i]??{},[d]:t[i][d]});return o.defaultProvider!==void 0||o.anthropic!==void 0||o.openai!==void 0?o:void 0}s(zn,"sparseModelLaddersToPersist");function Dn(e,n){return v(e,t=>{const o=T(t),r=T(t);n(r);const i={...t};for(const c of fn)c!=="modelLadders"&&!Le(r[c],o[c])&&(i[c]=r[c]);const d=zn(t.modelLadders,o.modelLadders,r.modelLadders);return d!==void 0?i.modelLadders=d:delete i.modelLadders,{value:r,next:i}})}s(Dn,"mutateConfigAtRoot");function Ro(e,n){v(e,t=>{const o=t.modelLadders??{},r={...o};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...o[i]??{},...n[i]});return{value:void 0,next:{...t,modelLadders:r}}})}s(Ro,"persistModelLadders");function jo(e,n,t){if(t!==void 0)An(n,t);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");v(e,o=>{const r=te(o.modelRoutes??{});t===void 0?delete r[n]:k(r,n,{...t,models:{...t.models}});const i={...o};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(jo,"persistModelRoute");function Un(e,n){return Dn(e,n)}s(Un,"updateConfigAtRoot");function So(e,n){return Un(_(e),n)}s(So,"updateConfig");function xo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return v(e.root,t=>{const o={...t.kinds??{},[e.kind]:{...(t.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...t,kinds:o}}}),{path:h(e.root),field:n}}s(xo,"persistDefaultKindModel");function Oo(e,n){const t=hn(e);return n(t),_n(e,t),t}s(Oo,"updateState");export{bn as InvalidRawSettingsError,wo as assertInstalledKind,Sn as binDeclarationIssues,co as configPath,go as ensureScopeInitialized,On as humanActionDeclarationIssues,yo as invalidPluginBinReasons,vo as invalidPluginKindsReasons,bo as invalidPluginRequiresReasons,xn as normalizeBin,En as normalizeHumanActions,ho as normalizeRequires,wn as normalizeTmuxPassthrough,xo as persistDefaultKindModel,Ro as persistModelLadders,jo as persistModelRoute,gn as readConfig,yn as readConfigAtRoot,q as readMergedLaunchConfig,Mn as readRawConfigAtRoot,Ln as readRawScopeConfig,lo as readRawSettingsForTarget,hn as readState,fo as replaceRawSettingsForTarget,ko as resolveKindConfig,_o as resolvePageComponents,uo as statePath,Ao as subKindsAvailableTo,So as updateConfig,Un as updateConfigAtRoot,ao as updateRawConfigAtomically,Oo as updateState,mo as writeConfig,po as writeRawConfig,_n as writeState};
1
+ var $e=Object.defineProperty;var s=(e,n)=>$e(e,"name",{value:n,configurable:!0});import{envProfileId as Ce}from"../shared/env.js";import{basename as Me,dirname as Le,join as H}from"node:path";import{isDeepStrictEqual as Ne}from"node:util";import{CONFIG_FILE as Fe,STATE_FILE as ze,CONDENSED_HISTORY_MODES as De,MOUSE_MODE_DEFAULTS as Ue,WHIP_MESSAGE_MODES as Ke,DEFAULT_WHIP_MESSAGES as J,defaultScopeConfig as b,defaultScopeState as qe,defaultModelLaddersConfig as Ge,defaultKindsConfig as Be,defaultRemoteCanvasConfig as He}from"../types.js";import{BINDING_CATALOG as Je,BINDING_IDS as We,isAttachPaneBinding as Ze}from"./keybindings/catalog.js";import{notFound as Ye,usage as Ve}from"./errors.js";import{emitEvent as Qe}from"./events/emit.js";import{atomicWriteJson as W,readJsonIfExists as M,ensureDir as Z}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as _,findProjectScopeRoots as Xe,userScopeRoot as L}from"./scope.js";import{listInstalledPluginsInRoot as Y}from"./installed-plugins.js";import{profileRoot as N,listProfiles as V}from"./profiles/manifest.js";import{canonicalRoot as F,projectStore as en,userStore as Q}from"./scoped-state/paths.js";import{convertLegacyScopedStore as nn,initializeFreshScopedStore as on}from"./scoped-state/migrate.js";import{mutateRawSettings as tn,readBookkeeping as rn,readRawSettings as sn,readRawSettingsWithRevision as cn,replaceRawSettings as dn,writeBookkeeping as un,writeRawSettings as ln}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as fn}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as an}from"./user-settings.js";import{normalizeWorkingGerunds as mn}from"../shared/working-activity.js";import{mergePageComponentLayers as pn,normalizePageComponents as X}from"./human/page-catalog.js";function h(e){return H(e,Fe)}s(h,"configPathFor");function ee(e,n){return Z(Le(e)),fn(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ee,"withConfigPathLock");function gn(e){return H(e,ze)}s(gn,"statePathFor");function lo(e){const n=y(e);return n?h(n):null}s(lo,"configPath");function fo(e){const n=y(e);return n?gn(n):null}s(fo,"statePath");function g(e){const n=F(e),t=F(L());if(n===t)return{store:Q(t),key:"user",kind:"user",root:t};if(Me(n)===".crouter")return nn({kind:"project",root:n}),{store:en(n),key:"project",kind:"project",root:n};for(const o of V()){const r=F(N(o.profileId));if(n===r)return{store:Q(t),key:`profile:${o.profileId}`,kind:"profile",root:r,profileId:o.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function R(e){const n=g(e);return n.kind==="project"?M(h(n.root)):sn(n)}s(R,"readRawAtRoot");function z(e,n){const t=g(e);if(t.kind==="project"){ee(h(t.root),o=>W(o,n));return}ln(t,n)}s(z,"writeRawAtRoot");function v(e,n){const t=g(e);return t.kind==="project"?ee(h(t.root),o=>{const r=n(M(o)??{});return W(o,r.next),r.value}):tn(t,o=>n(o))}s(v,"mutateRawAtRoot");function yn(e){const n=y(e);return n?hn(n):b()}s(yn,"readConfig");function hn(e){const n=R(e);return n?T(n):b()}s(hn,"readConfigAtRoot");function bn(e){const n=y(e);return n?rn(g(n)):qe()}s(bn,"readState");class _n extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function ne(e){if(e.scope==="user")return g(L());if(!V().some(n=>n.profileId===e.profileId))throw Ye(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(N(e.profileId))}s(ne,"rawSettingsOwnerForTarget");function ao(e){return cn(ne(e))}s(ao,"readRawSettingsForTarget");function mo(e,n,t){return dn(ne(e),n,t,o=>{try{T(o)}catch(r){throw new _n(r)}})}s(mo,"replaceRawSettingsForTarget");function po(e,n){const t=_(e);return v(t,o=>{const r=n(o);return{value:r,next:r}})}s(po,"updateRawConfigAtomically");function go(e,n){z(_(e),n)}s(go,"writeConfig");function yo(e,n){z(_(e),n)}s(yo,"writeRawConfig");function vn(e,n){const t=_(e);un(g(t),n)}s(vn,"writeState");function ho(e,n){Z(n);const t=g(e==="user"?L():n);if(on({kind:t.kind==="user"?"user":"project",root:t.store.root}),t.kind==="project"&&M(h(t.root))===null){const{modelLadders:o,keybindings:r,tmux_passthrough:i,brokerThresholds:c,lifecycle:d,api:u,...f}=b();z(t.root,f)}}s(ho,"ensureScopeInitialized");function kn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))Array.isArray(o)&&o.every(r=>typeof r=="string")&&(n[t]=[...o]);return n}s(kn,"normalizeKeybindings");const An=new Set(Je.filter(Ze).map(e=>e.id));function wn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&We.has(n)&&An.has(n)))]:[]}s(wn,"normalizeTmuxPassthrough");function S(e,n=Ge()){const t=n;if(e===null||typeof e!="object")return t;const o=e,r={anthropic:{...t.anthropic},openai:{...t.openai},...t.defaultProvider!==void 0?{defaultProvider:t.defaultProvider}:{}};(o.defaultProvider==="anthropic"||o.defaultProvider==="openai")&&(r.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"]){const c=o[i];if(!(c===null||typeof c!="object"))for(const[d,u]of Object.entries(c))(d==="ultra"||d==="strong"||d==="medium"||d==="light")&&typeof u=="string"&&(r[i][d]=u)}return r}s(S,"mergeModelLadders");function oe(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(oe,"validStrength");const D=["ultra","strong","medium","light"];function U(){return Object.create(null)}s(U,"routeRecord");function k(e,n,t){Object.defineProperty(e,n,{value:t,writable:!0,enumerable:!0,configurable:!0})}s(k,"setRouteRecord");function te(e){const n=U();for(const[t,o]of Object.entries(e??{}))k(n,t,o);return n}s(te,"copyRouteRecord");function A(e,n){Qe({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(A,"routeInvalid");function x(e,n={}){const t=te(n);if(e===null||typeof e!="object"||Array.isArray(e))return t;for(const[o,r]of Object.entries(e)){if(o.trim()===""){A(o,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){A(o,"route must be an object");continue}const i=r,c=t[o],d={...c};let u;for(const f of["family","credentialSource","providerId"]){const l=i[f];if(l!==void 0){if(typeof l!="string"||l.trim()===""){u=`${f} must be a non-empty string`;break}d[f]=l}}if(u===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))u="models must be an object";else{const f={...c?.models};for(const[l,a]of Object.entries(i.models)){if(!oe(l)){u=`models.${l} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){u=`models.${l} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){u=`models.${l} must be provider/id`;break}f[l]=a}d.models=f}if(u===void 0&&d.models!==void 0&&d.providerId!==void 0){for(const[f,l]of Object.entries(d.models))if(l.slice(0,l.indexOf("/"))!==d.providerId){u=`models.${f} provider prefix must equal providerId`;break}}if(u!==void 0){A(o,u);continue}k(t,o,d)}return t}s(x,"mergeModelRoutePatches");function re(e){const n=U(),t=U();for(const[o,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){A(o,"route must include family, credentialSource, providerId, and models");continue}const i=D.filter(c=>r.models[c]===void 0);if(i.length>0){A(o,`incomplete route; missing strengths: ${i.join(", ")}`),k(t,o,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}k(n,o,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:t}}s(re,"resolveModelRoutes");function jn(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const o of["family","credentialSource","providerId"])if(typeof n[o]!="string"||n[o].trim()==="")throw new Error(`model route "${e}" ${o} must be a non-empty string`);const t=D.filter(o=>n.models?.[o]===void 0);if(t.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${t.join(", ")}`);for(const o of D){const r=n.models[o];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${o} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${o} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${o} provider prefix must equal providerId`)}}s(jn,"assertCompleteModelRoute");function O(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const t=e,o=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(t.strengthFallback)&&t.strengthFallback.every(i=>oe(i))?[...t.strengthFallback]:void 0;return{...o(t.credentialSourceOrder)!==void 0?{credentialSourceOrder:o(t.credentialSourceOrder)}:{},...o(t.familyOrder)!==void 0?{familyOrder:o(t.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(O,"mergeModelRouting");function Rn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Rn,"isInheritAllGlob");function E(e,n=[]){const t=e,o=Array.isArray(t?.allow)?t.allow.filter(r=>typeof r=="string"):[];for(const r of o)if(Rn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...o])]}}s(E,"mergeSpawnEnv");function I(e,n={}){const t={};for(const[o,r]of Object.entries(n))t[o]={...r};if(e!==null&&typeof e=="object")for(const[o,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...t[o]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),t[o]=i}return t}s(I,"mergeProviderOptions");const ie=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Sn=new Set(["crtr","crtrd"]);function P(e,n){if(n==="bin"&&Sn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!ie.test(e))return`${n}.${e} is not a safe bare command name (expected ${ie.source})`}s(P,"bareCommandNameIssue");function xn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[t,o]of Object.entries(e)){const r=P(t,"bin");r!==void 0&&n.push({name:t,message:r}),(typeof o!="string"||o.trim()==="")&&n.push({name:t,message:`bin.${t} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(xn,"binDeclarationIssues");function On(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))P(t,"bin")===void 0&&(typeof o!="string"||o.trim()===""||(n[t]=o));return n}s(On,"normalizeBin");const se=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function En(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[t,o]of Object.entries(e)){const r=[];if(se.test(t)||r.push(`action name must match ${se.source}`),o===null||typeof o!="object"||Array.isArray(o))r.push("action must be an object with argv and cwd");else{const i=o,c=Object.keys(i).filter(d=>d!=="argv"&&d!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(d=>typeof d=="string"&&d.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:t,reason:r.join("; ")})}return n}s(En,"humanActionDeclarationIssues");function In(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(En(e).map(o=>o.name)),t={};for(const[o,r]of Object.entries(e)){if(n.has(o))continue;const i=r;t[o]={argv:[...i.argv],cwd:i.cwd}}return t}s(In,"normalizeHumanActions");function bo(e){return xn(e).map(n=>n.message)}s(bo,"invalidPluginBinReasons");function _o(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,o]of Object.entries(e))P(t,"requires")===void 0&&(typeof o!="string"||o.trim()===""||/[\r\n]/.test(o)||(n[t]=o));return n}s(_o,"normalizeRequires");function vo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[t,o]of Object.entries(e)){const r=P(t,"requires");r!==void 0&&n.push(r),typeof o!="string"||o.trim()===""?n.push(`requires.${t} must be a non-empty one-line install hint`):/[\r\n]/.test(o)&&n.push(`requires.${t} must be a one-line install hint`)}return n}s(vo,"invalidPluginRequiresReasons");function ce(e){if(e===null||typeof e!="object")return null;const n=e,t={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(t.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(t.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(t.orchestratorModel=n.orchestratorModel);const o=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return o(n.tools)&&(t.tools=n.tools),o(n.extensions)&&(t.extensions=n.extensions),o(n.availableTo)&&(t.availableTo=n.availableTo),Object.keys(t).length>0?t:null}s(ce,"normalizeKindFields");function w(e,n=Be()){const t={...n};if(e!==null&&typeof e=="object")for(const[o,r]of Object.entries(e)){const i=ce(r);if(i===null)continue;const c=t[o];c!==void 0?t[o]={...c,...i}:i.whenToUse!==void 0&&(t[o]=i)}return t}s(w,"mergeKinds");function de(e,n,t){if(n===null)return t;const o=Y(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=t;for(const i of o)r=w(i.manifest.kinds,r);return r}s(de,"layerPluginKinds");function ko(){const e=[{origin:"config.json",components:yn("user").page_components}],n=y("user");if(n!==null){const t=Y("user",n).filter(o=>o.enabled&&o.manifest.page_components!==void 0).sort((o,r)=>o.name.localeCompare(r.name));for(const o of t){const r=`plugin "${o.name}" page_components`;e.push({origin:`plugin "${o.name}"`,components:X(o.manifest.page_components,r)})}}return pn(e)}s(ko,"resolvePageComponents");const K=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Ao(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],t=s(o=>Array.isArray(o)&&o.every(r=>typeof r=="string"),"isStringArray");for(const[o,r]of Object.entries(e)){if(o.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${o} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))K.has(c)||n.push(`kinds.${o}.${c} is not a KindConfig field (expected one of: ${[...K].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${o}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${o}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!t(i[c])&&n.push(`kinds.${o}.${c} must be an array of strings`);ce(r)===null&&n.push(`kinds.${o} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...K].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Ao,"invalidPluginKindsReasons");function Pn(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const t={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(t.cpOrigin=n.cpOrigin),t}s(Pn,"normalizeRemoteCanvasTarget");function Tn(e,n=He()){const t={...n.targets};if(e!==null&&typeof e=="object"){const o=e;if(o.targets!==null&&typeof o.targets=="object")for(const[r,i]of Object.entries(o.targets)){const c=Pn(i);c!==null&&(t[r]=c)}}return{targets:t}}s(Tn,"mergeRemoteCanvas");function ue(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(ue,"normalizeMode");function j(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(j,"normalizePositiveInteger");function $n(e,n){const t=e!==null&&typeof e=="object"?e:{},o=j(t.warning,n.warning),r=j(t.automaticReviveCap,n.automaticReviveCap);return o<=r?{warning:o,automaticReviveCap:r}:{...n}}s($n,"mergeBrokerThresholds");function Cn(e,n){return{unattendedParkMs:j((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Cn,"mergeLifecycle");function Mn(e){if(!Array.isArray(e))return[...J];const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:[...J]}s(Mn,"normalizeWhipMessages");function Ln(e,n){if(e===null||typeof e!="object")return{...n};const t=e.tcp;return{tcp:typeof t=="string"?t:n.tcp}}s(Ln,"mergeApi");function T(e){const n=b(),t=n.schema_version,o=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,d=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,u={crtr:ue(i?.crtr,n.auto_update.crtr),content:ue(i?.content,n.auto_update.content),interval_hours:d},f=e.max_panes_per_window,l=j(f,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=$n(e.brokerThresholds,n.brokerThresholds),$=Cn(e.lifecycle,n.lifecycle),p=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,le=e.working_gerunds===void 0?[...n.working_gerunds]:mn(e.working_gerunds),fe=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,ae=X(e.page_components),me=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,pe=Mn(e.whip_messages),ge=Ke.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,ye=Ue.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,he=j(e.live_cycles,n.live_cycles),be=De.includes(e.condensed_history)?e.condensed_history:n.condensed_history,_e=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,ve=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,ke=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ae=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,we=kn(e.keybindings),je=wn(e.tmux_passthrough),Re=S(e.modelLadders),Se=I(e.providerOptions,n.providerOptions),C=re(x(e.modelRoutes)),G=C.complete,B=O(e.modelRouting,void 0),xe=w(e.kinds),Oe=Tn(e.remoteCanvas),Ee=Ln(e.api,n.api),Ie=E(e.spawnEnv,n.spawnEnv?.allow),Pe=On(e.bin),Te=In(e.humanActions);return{bin:Pe,humanActions:Te,schema_version:t,marketplaces:o,plugins:r,auto_update:u,max_panes_per_window:l,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:$,completion_bell:p,working_gerunds:le,whip_mode:fe,page_components:ae,page_surface:me,whip_messages:pe,whip_message_mode:ge,mouse_mode_default:ye,live_cycles:he,condensed_history:be,bash_tool_purpose:_e,fold_finished_tools:ve,summarize_tool_calls:ke,detailed_tool_recaps:Ae,keybindings:we,tmux_passthrough:je,modelLadders:Re,providerOptions:Se,...Object.keys(G).length>0?{modelRoutes:G}:{},...Object.keys(C.legacy).length>0?{legacyModelRoutes:C.legacy}:{},...B!==void 0?{modelRouting:B}:{},kinds:xe,remoteCanvas:Oe,api:Ee,spawnEnv:Ie}}s(T,"mergeConfig");function Nn(e){return R(e)}s(Nn,"readRawConfigAtRoot");function Fn(e){const n=y(e);return n?Nn(n):null}s(Fn,"readRawScopeConfig");function zn(e){if(e===null||e==="")return null;try{return R(N(e))}catch{return null}}s(zn,"readRawProfileConfig");function Dn(e,n){return[...Xe(e,n)].reverse().map(r=>({root:r,raw:R(r)}))}s(Dn,"readRawProjectScopeConfigs");function q(e=process.cwd(),n=Ce()||null){const t=b(),o=Fn("user"),r=zn(n),i=Dn(e,n);let c=w(o?.kinds,de("user",y("user"),t.kinds)),d=S(o?.modelLadders,t.modelLadders),u=I(o?.providerOptions,t.providerOptions),f=x(o?.modelRoutes),l=O(o?.modelRouting,void 0),a=E(o?.spawnEnv,t.spawnEnv?.allow);r!==null&&(c=w(r.kinds,c),d=S(r.modelLadders,d),u=I(r.providerOptions,u),f=x(r.modelRoutes,f),l=O(r.modelRouting,l),a=E(r.spawnEnv,a.allow));for(const{root:$,raw:p}of i)c=w(p?.kinds,de("project",$,c)),p!==null&&(d=S(p.modelLadders,d),u=I(p.providerOptions,u),f=x(p.modelRoutes,f),l=O(p.modelRouting,l),a=E(p.spawnEnv,a.allow));const m=re(f);return{kinds:c,modelLadders:d,providerOptions:u,...Object.keys(m.complete).length>0?{modelRoutes:m.complete}:{},...Object.keys(m.legacy).length>0?{legacyModelRoutes:m.legacy}:{},...l!==void 0?{modelRouting:l}:{},spawnEnv:a}}s(q,"readMergedLaunchConfig");function wo(e){return q().kinds[e]}s(wo,"resolveKindConfig");function jo(e){const n=Object.keys(q().kinds).sort();if(!n.includes(e))throw Ve(`unknown kind: ${e}`,{received:e,field:"kind",next:`Valid kinds: ${n.join(", ")}.`})}s(jo,"assertInstalledKind");function Ro(e){const n=q().kinds,t=[];for(const[o,r]of Object.entries(n)){const i=o.indexOf("/");if(i===-1)continue;const c=o.slice(0,i),d=r.availableTo??[c];(d.includes("*")||d.includes(e))&&t.push({kind:o,whenToUse:r.whenToUse})}return t.sort((o,r)=>o.kind.localeCompare(r.kind))}s(Ro,"subKindsAvailableTo");function Un(e,n,t){const o={...e??{}};o.anthropic!==void 0&&(o.anthropic={...o.anthropic}),o.openai!==void 0&&(o.openai={...o.openai}),t.defaultProvider!==n.defaultProvider&&t.defaultProvider!==void 0&&(o.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])t[i][c]!==n[i][c]&&(o[i]={...o[i]??{},[c]:t[i][c]});return o.defaultProvider!==void 0||o.anthropic!==void 0||o.openai!==void 0?o:void 0}s(Un,"sparseModelLaddersToPersist");function Kn(e,n){return v(e,t=>{const o=T(t),r=T(t);n(r);const i={...t};for(const d of an)d!=="modelLadders"&&!Ne(r[d],o[d])&&(i[d]=r[d]);const c=Un(t.modelLadders,o.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Kn,"mutateConfigAtRoot");function So(e,n){v(e,t=>{const o=t.modelLadders??{},r={...o};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...o[i]??{},...n[i]});return{value:void 0,next:{...t,modelLadders:r}}})}s(So,"persistModelLadders");function xo(e,n,t){if(t!==void 0)jn(n,t);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");v(e,o=>{const r=te(o.modelRoutes??{});t===void 0?delete r[n]:k(r,n,{...t,models:{...t.models}});const i={...o};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(xo,"persistModelRoute");function qn(e,n){return Kn(e,n)}s(qn,"updateConfigAtRoot");function Oo(e,n){return qn(_(e),n)}s(Oo,"updateConfig");function Eo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return v(e.root,t=>{const o={...t.kinds??{},[e.kind]:{...(t.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...t,kinds:o}}}),{path:h(e.root),field:n}}s(Eo,"persistDefaultKindModel");function Io(e,n){const t=bn(e);return n(t),vn(e,t),t}s(Io,"updateState");export{_n as InvalidRawSettingsError,jo as assertInstalledKind,xn as binDeclarationIssues,lo as configPath,ho as ensureScopeInitialized,En as humanActionDeclarationIssues,bo as invalidPluginBinReasons,Ao as invalidPluginKindsReasons,vo as invalidPluginRequiresReasons,On as normalizeBin,In as normalizeHumanActions,_o as normalizeRequires,wn as normalizeTmuxPassthrough,Eo as persistDefaultKindModel,So as persistModelLadders,xo as persistModelRoute,yn as readConfig,hn as readConfigAtRoot,q as readMergedLaunchConfig,Nn as readRawConfigAtRoot,Fn as readRawScopeConfig,ao as readRawSettingsForTarget,bn as readState,mo as replaceRawSettingsForTarget,wo as resolveKindConfig,ko as resolvePageComponents,fo as statePath,Ro as subKindsAvailableTo,Oo as updateConfig,qn as updateConfigAtRoot,po as updateRawConfigAtomically,Io as updateState,go as writeConfig,yo as writeRawConfig,vn as writeState};
@@ -0,0 +1,6 @@
1
+ import type { ModelRegistry, ModelRuntime } from '@earendil-works/pi-coding-agent';
2
+ /** Whether the provider has a credential crouter can use. This is the same
3
+ * configured predicate shown by the setup Providers panel. */
4
+ export declare function isProviderCredentialConfigured(providerId: string, registry: ModelRegistry): boolean;
5
+ /** Whether any provider in the setup catalog has a usable configured credential. */
6
+ export declare function hasProviderCredential(runtime: ModelRuntime, registry: ModelRegistry): boolean;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var t=(e,r)=>i(e,"name",{value:r,configurable:!0});import{isManagedProvider as n,readSubscriptionPool as d}from"./subscription-state.js";function a(e,r){return r.getProviderAuthStatus(e).configured||n(e)&&d(e).length>0}t(a,"isProviderCredentialConfigured");function g(e,r){return[...new Set([...e.getProviders().map(o=>o.id),...r.getAll().map(o=>o.provider)])].some(o=>a(o,r))}t(g,"hasProviderCredential");export{g as hasProviderCredential,a as isProviderCredentialConfigured};
@@ -11,6 +11,8 @@ export interface BootRootOpts {
11
11
  * spawner to inherit from, so this is the front door's only source of profile
12
12
  * identity. */
13
13
  profile?: string | null;
14
+ /** Profile already selected by the front door before its credential gate. */
15
+ selectedProfileId?: string;
14
16
  /** `crtr --pick-profile`: force the startup profile chooser to open even when
15
17
  * a per-cwd default is pinned, so the user can re-pin or unpin it. Without
16
18
  * this a pinned default auto-picks silently (that is what "default" means). */
@@ -1 +1 @@
1
- var l=Object.defineProperty;var c=(e,o)=>l(e,"name",{value:o,configurable:!0});import{spawn as p}from"node:child_process";import{inTmux as u,currentTmux as _,viewerSplitEnv as T}from"./placement-tmux.js";import{selectProfileForCwd as h}from"../profiles/select.js";import{cliClient as s}from"../../commands/api-client.js";import{mark as t}from"../timing.js";async function k(e){if(!u())throw new Error("crtr must be started from inside a tmux session \u2014 start tmux first (e.g. `tmux new -s work`), then run `crtr` there.");const o=e.kind;t("boot_root.start");const m=await h(e.cwd,e.profile,e.pickProfile??!1);t("boot_root.profile_resolved");const n=(await s().createNode({...o!==void 0?{kind:o}:{},mode:"base",prompt:e.prompt,profile:m,cwd:e.cwd,...e.name!==void 0?{name:e.name}:o!==void 0?{name:o}:{},root:!0,prefer_warm:!0})).node_id;t("boot_root.node_created",{node:n});const r=_();if(r!==null)try{await s().registerFocus({node_id:n,pane:r.pane,session:r.session,window:r.window})}catch{}const i={...process.env,...T(),CRTR_ATTACH_WAIT_MS:"30000",...e.prompt!==void 0&&e.prompt!==""?{CRTR_ATTACH_INITIAL_WHIP:"1"}:{}};r!==null&&(i.CRTR_ATTACH_BORROWED_PANE=r.pane),t("boot_root.viewer_spawn");const a=p("crtr",["surface","attach","to",n],{stdio:"inherit",env:i}),f=await new Promise(d=>{a.once("exit",w=>d(w??0)),a.once("error",()=>d(1))});process.exit(f)}c(k,"bootRoot");export{k as bootRoot};
1
+ var l=Object.defineProperty;var c=(e,o)=>l(e,"name",{value:o,configurable:!0});import{spawn as u}from"node:child_process";import{inTmux as _,currentTmux as p,viewerSplitEnv as T}from"./placement-tmux.js";import{selectProfileForCwd as h}from"../profiles/select.js";import{cliClient as s}from"../../commands/api-client.js";import{mark as t}from"../timing.js";async function P(e){if(!_())throw new Error("crtr must be started from inside a tmux session \u2014 start tmux first (e.g. `tmux new -s work`), then run `crtr` there.");const o=e.kind;t("boot_root.start");const m=e.selectedProfileId??await h(e.cwd,e.profile,e.pickProfile??!1);t("boot_root.profile_resolved");const n=(await s().createNode({...o!==void 0?{kind:o}:{},mode:"base",prompt:e.prompt,profile:m,cwd:e.cwd,...e.name!==void 0?{name:e.name}:o!==void 0?{name:o}:{},root:!0,prefer_warm:!0})).node_id;t("boot_root.node_created",{node:n});const r=p();if(r!==null)try{await s().registerFocus({node_id:n,pane:r.pane,session:r.session,window:r.window})}catch{}const i={...process.env,...T(),CRTR_ATTACH_WAIT_MS:"30000",...e.prompt!==void 0&&e.prompt!==""?{CRTR_ATTACH_INITIAL_WHIP:"1"}:{}};r!==null&&(i.CRTR_ATTACH_BORROWED_PANE=r.pane),t("boot_root.viewer_spawn");const a=u("crtr",["surface","attach","to",n],{stdio:"inherit",env:i}),f=await new Promise(d=>{a.once("exit",w=>d(w??0)),a.once("error",()=>d(1))});process.exit(f)}c(P,"bootRoot");export{P as bootRoot};
@@ -1,4 +1,4 @@
1
- import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from '../../../api/dto/broker-ops.js';
1
+ import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest, BrokerTelemetryRequest } from '../../../api/dto/broker-ops.js';
2
2
  import type { AcknowledgeMailResultDTO, ClaimMailResultDTO, MailReceiptDTO } from '../../../api/dto/mail.js';
3
3
  import type { BrokerFaultInputDTO, BrokerFaultRequest, BrokerFaultResultDTO, BrokerProviderRetryRequest, BrokerProviderRetryResultDTO, BrokerTurnRequest, BrokerTurnResultDTO, RecoveryStateDTO } from '../../../api/dto/recovery.js';
4
4
  import type { RelaunchRootResultDTO } from '../../../api/dto/lifecycle.js';
@@ -9,6 +9,7 @@ type BrokerInput<T> = T extends unknown ? Omit<T, 'expected_execution_id'> : nev
9
9
  export declare function settleBroker(nodeId: string, request: BrokerInput<BrokerSettleRequest>): Promise<BrokerSettleDirective>;
10
10
  export declare function completeBrokerPark(nodeId: string, request: BrokerInput<BrokerParkCompleteRequest>): Promise<BrokerSettleDirective>;
11
11
  export declare function recordBrokerParkActivity(nodeId: string): Promise<BrokerParkActivityResultDTO>;
12
+ export declare function recordBrokerTelemetry(nodeId: string, request: Omit<BrokerTelemetryRequest, 'expected_execution_id'>): Promise<void>;
12
13
  export declare function claimBrokerMail(nodeId: string, channel: 'wake' | 'passive'): Promise<ClaimMailResultDTO>;
13
14
  export declare function acknowledgeBrokerMail(nodeId: string, deliveries: MailReceiptDTO[]): Promise<AcknowledgeMailResultDTO>;
14
15
  export declare function recordBrokerTurn(nodeId: string, request: Omit<BrokerTurnRequest, 'expected_execution_id'>): Promise<BrokerTurnResultDTO>;
@@ -1 +1 @@
1
- var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{CrtrClient as u}from"../../../api/client.js";import{ApiError as d}from"../../../api/errors.js";import{envExecutionId as a}from"../../../shared/env.js";function t(){return u.forLocalSocket({autostart:!1})}o(t,"daemonClient");function n(){const e=a();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}o(n,"brokerExecutionId");function f(e,r){return t().bindBrokerSession(e,{...r,executionId:n()})}o(f,"bindBrokerSession");function m(e,r){return t().settleBroker(e,{...r,expected_execution_id:n()})}o(m,"settleBroker");function B(e,r){return t().completeBrokerPark(e,{...r,expected_execution_id:n()})}o(B,"completeBrokerPark");function _(e){return t().recordBrokerParkActivity(e,{expected_execution_id:n()})}o(_,"recordBrokerParkActivity");function s(e,r){return t().claimNodeMail(e,{execution_id:n(),channel:r})}o(s,"claimBrokerMail");function v(e,r){return t().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}o(v,"acknowledgeBrokerMail");function E(e,r){return t().recordBrokerTurn(e,{...r,expected_execution_id:n()})}o(E,"recordBrokerTurn");function R(e,r){return t().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}o(R,"mutateBrokerProviderRetry");function h(e,r){return t().mutateBrokerFault(e,{...r,expected_execution_id:n()})}o(h,"mutateBrokerFault");function y(e){return t().getBrokerRecovery(e,n())}o(y,"brokerRecovery");function N(e,r){return t().recordNodeFault(e,r)}o(N,"recordNodeFault");function b(e,r={}){return t().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}o(b,"clearNodeFault");function P(e,r){return t().commitBrokerModel(e,{...r,expected_execution_id:n()})}o(P,"commitBrokerModel");function w(e){return t().brokerExtensionState(e)}o(w,"brokerExtensionState");function F(e,r){return t().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}o(F,"commitBrokerGeneratedName");function M(e,r){return t().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}o(M,"commitBrokerPersonaAck");async function A(e,r){try{await t().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof d&&i.code==="already_finalized")return;throw i}}o(A,"publishBrokerReport");function C(e){return t().relaunchRoot(e)}o(C,"relaunchBrokerRoot");export{v as acknowledgeBrokerMail,f as bindBrokerSession,n as brokerExecutionId,w as brokerExtensionState,y as brokerRecovery,s as claimBrokerMail,b as clearNodeFault,F as commitBrokerGeneratedName,P as commitBrokerModel,M as commitBrokerPersonaAck,B as completeBrokerPark,h as mutateBrokerFault,R as mutateBrokerProviderRetry,A as publishBrokerReport,_ as recordBrokerParkActivity,E as recordBrokerTurn,N as recordNodeFault,C as relaunchBrokerRoot,m as settleBroker};
1
+ var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{localClient as u}from"../../../api/node-transport.js";import{ApiError as d}from"../../../api/errors.js";import{envExecutionId as a}from"../../../shared/env.js";function t(){return u({autostart:!1})}o(t,"daemonClient");function n(){const e=a();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}o(n,"brokerExecutionId");function f(e,r){return t().bindBrokerSession(e,{...r,executionId:n()})}o(f,"bindBrokerSession");function m(e,r){return t().settleBroker(e,{...r,expected_execution_id:n()})}o(m,"settleBroker");function B(e,r){return t().completeBrokerPark(e,{...r,expected_execution_id:n()})}o(B,"completeBrokerPark");function _(e){return t().recordBrokerParkActivity(e,{expected_execution_id:n()})}o(_,"recordBrokerParkActivity");function s(e,r){return t().recordBrokerTelemetry(e,{...r,expected_execution_id:n()})}o(s,"recordBrokerTelemetry");function y(e,r){return t().claimNodeMail(e,{execution_id:n(),channel:r})}o(y,"claimBrokerMail");function v(e,r){return t().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}o(v,"acknowledgeBrokerMail");function E(e,r){return t().recordBrokerTurn(e,{...r,expected_execution_id:n()})}o(E,"recordBrokerTurn");function R(e,r){return t().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}o(R,"mutateBrokerProviderRetry");function h(e,r){return t().mutateBrokerFault(e,{...r,expected_execution_id:n()})}o(h,"mutateBrokerFault");function N(e){return t().getBrokerRecovery(e,n())}o(N,"brokerRecovery");function b(e,r){return t().recordNodeFault(e,r)}o(b,"recordNodeFault");function P(e,r={}){return t().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}o(P,"clearNodeFault");function w(e,r){return t().commitBrokerModel(e,{...r,expected_execution_id:n()})}o(w,"commitBrokerModel");function F(e){return t().brokerExtensionState(e)}o(F,"brokerExtensionState");function M(e,r){return t().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}o(M,"commitBrokerGeneratedName");function T(e,r){return t().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}o(T,"commitBrokerPersonaAck");async function A(e,r){try{await t().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof d&&i.code==="already_finalized")return;throw i}}o(A,"publishBrokerReport");function I(e){return t().relaunchRoot(e)}o(I,"relaunchBrokerRoot");export{v as acknowledgeBrokerMail,f as bindBrokerSession,n as brokerExecutionId,F as brokerExtensionState,N as brokerRecovery,y as claimBrokerMail,P as clearNodeFault,M as commitBrokerGeneratedName,w as commitBrokerModel,T as commitBrokerPersonaAck,B as completeBrokerPark,h as mutateBrokerFault,R as mutateBrokerProviderRetry,A as publishBrokerReport,_ as recordBrokerParkActivity,s as recordBrokerTelemetry,E as recordBrokerTurn,b as recordNodeFault,I as relaunchBrokerRoot,m as settleBroker};
@@ -0,0 +1,2 @@
1
+ /** Open pi's provider picker and LoginDialogComponent before a root broker starts. */
2
+ export declare function runFrontDoorLogin(): Promise<boolean>;
@@ -0,0 +1 @@
1
+ var m=Object.defineProperty;var r=(a,t)=>m(a,"name",{value:t,configurable:!0});import{CredentialSynchronizationError as d,LoginDialogComponent as l,OAuthSelectorComponent as p}from"@earendil-works/pi-coding-agent";import{execFile as f}from"node:child_process";import{join as g}from"node:path";import{setAuthCredential as w}from"../auth-file.js";import{dialogAuthInteraction as y}from"../auth-interaction.js";import{commitManagedLogin as I,isManagedProvider as L,readSubscriptionPool as b}from"../subscription-state.js";import{runSetupSettingsProcess as A}from"../../commands/sys/setup-settings-runner.js";import{buildProviderCatalog as P}from"../../commands/sys/panels/provider-panel.js";function x(a){const t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",i=process.platform==="win32"?["/c","start","",a]:[a];f(t,i,{timeout:5e3},()=>{})}r(x,"openBrowser");class C{static{r(this,"FrontDoorLogin")}tui;runtime;agentDir;finish;component;dialog;settled=!1;constructor(t,i,s,o,c){this.tui=t,this.runtime=i,this.agentDir=s,this.finish=c,this.component=new p("login",o,n=>this.startLogin(o.find(u=>u.id===n)),()=>this.complete(!1))}get focused(){return this.component.focused}set focused(t){this.component.focused=t}handleInput(t){this.component.handleInput?.(t)}invalidate(){this.tui.requestRender()}render(t){return this.component.render(t)}dispose(){this.settled||this.dialog?.handleInput("\x1B")}complete(t){this.settled||(this.settled=!0,this.finish(t))}startLogin(t){if(!t){this.complete(!1);return}const i=new l(this.tui,t.id,e=>this.complete(e),t.name);this.dialog=i,this.component=i,this.tui.setFocus(this),this.tui.requestRender();const s=y(i,{openBrowser:x,onChange:r(()=>this.tui.requestRender(),"onChange"),isActive:r(()=>!this.settled&&!i.signal.aborted,"isActive")}),o=r(()=>{i.signal.aborted||this.complete(!1)},"fail");if(t.authType==="api_key"){i.showPrompt(`Enter API key for ${t.name}:`,"sk-...").then(async e=>{if(!e.trim()||this.settled){this.complete(!1);return}await w(t.id,{type:"api_key",key:e.trim()},g(this.agentDir,"auth.json")),this.complete(!0)}).catch(o);return}const c=this.runtime.getProvider(t.id)?.auth.oauth;if(!c){this.complete(!1);return}const n=t.id;if(!L(n)){this.runtime.login(n,"oauth",s).then(()=>this.complete(!0)).catch(e=>{if(e instanceof d){this.complete(!0);return}o()});return}const u=Math.max(0,...b(n).map(e=>e.lastRateLimitedAt));c.login(s).then(async e=>{if(this.settled||i.signal.aborted)return;const h=typeof e.accountId=="string"&&e.accountId.trim()?e.accountId.trim():void 0;await I(n,void 0,{access:e.access,refresh:e.refresh,expires:e.expires,...h?{accountId:h}:{},lastRateLimitedAt:u,autoLabel:!0}),this.complete(!0)}).catch(o)}}async function E(){return await A(({tui:t,agentDir:i,runtime:s,registry:o},c)=>new C(t,s,i,P(s,o).map(({providerId:n,name:u,authType:e})=>({id:n,name:u,authType:e})),c.submit))===!0}r(E,"runFrontDoorLogin");export{E as runFrontDoorLogin};