@north-light/crouter 0.3.322 → 0.3.324

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/bin/progress-painter.mjs +89 -0
  2. package/bin/runtime-selector.mjs +79 -9
  3. package/dist/api/client.d.ts +6 -2
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/broker-ops.d.ts +9 -0
  6. package/dist/api/dto/canvas.d.ts +23 -1
  7. package/dist/api/dto/nodes.d.ts +8 -0
  8. package/dist/api/node-transport.js +1 -1
  9. package/dist/api/routes.d.ts +2 -0
  10. package/dist/api/routes.js +1 -1
  11. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  12. package/dist/clients/attach/overlays/graph.d.ts +6 -5
  13. package/dist/clients/attach/overlays/graph.js +1 -1
  14. package/dist/clients/attach/viewer.js +536 -536
  15. package/dist/commands/node/create.js +3 -3
  16. package/dist/commands/sys/panels/plugins-panel.js +1 -1
  17. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  18. package/dist/commands/sys/panels/provider-panel.js +1 -1
  19. package/dist/commands/sys/setup-core.js +7 -4
  20. package/dist/commands/sys/setup-wizard.d.ts +1 -1
  21. package/dist/commands/sys/setup-wizard.js +1 -1
  22. package/dist/core/canvas/canvas.d.ts +24 -0
  23. package/dist/core/canvas/canvas.js +29 -15
  24. package/dist/core/canvas/migrations.js +35 -32
  25. package/dist/core/canvas/nav-model.d.ts +1 -1
  26. package/dist/core/canvas/nav-model.js +1 -1
  27. package/dist/core/canvas/nav-render.d.ts +31 -25
  28. package/dist/core/canvas/nav-render.js +1 -1
  29. package/dist/core/canvas/render-source.d.ts +6 -16
  30. package/dist/core/canvas/render-source.js +9 -9
  31. package/dist/core/canvas/types.d.ts +16 -0
  32. package/dist/core/provider-credential.d.ts +6 -0
  33. package/dist/core/provider-credential.js +1 -0
  34. package/dist/core/runtime/boot-root.d.ts +2 -0
  35. package/dist/core/runtime/boot-root.js +5 -1
  36. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -1
  37. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  38. package/dist/core/runtime/front-door-login.d.ts +2 -0
  39. package/dist/core/runtime/front-door-login.js +1 -0
  40. package/dist/core/runtime/front-door.js +7 -5
  41. package/dist/core/runtime/nerd-font.d.ts +19 -1
  42. package/dist/core/runtime/nerd-font.js +2 -2
  43. package/dist/core/runtime/progress-bar.d.ts +13 -0
  44. package/dist/core/runtime/progress-bar.js +2 -0
  45. package/dist/core/runtime/provider-credential-gate.d.ts +4 -0
  46. package/dist/core/runtime/provider-credential-gate.js +2 -0
  47. package/dist/core/runtime/spawn-env.d.ts +7 -0
  48. package/dist/core/runtime/spawn-env.js +1 -1
  49. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  50. package/dist/daemon/api/handlers/canvas.js +4 -4
  51. package/dist/daemon/api/map.d.ts +15 -1
  52. package/dist/daemon/api/map.js +2 -2
  53. package/dist/daemon/fleet.js +1 -1
  54. package/dist/pi-extensions/canvas-stophook.js +1 -1
  55. package/package.json +1 -1
  56. package/runtime.lock.json +5 -5
  57. package/scripts/install-runtime.mjs +7 -3
@@ -1,3 +1,3 @@
1
- var L=Object.defineProperty;var o=(e,t)=>L(e,"name",{value:t,configurable:!0});import{envNodeId as z}from"../../shared/env.js";import{defineLeaf as H}from"../../core/command.js";import{InputError as r}from"../../core/io.js";import{mark as x}from"../../core/timing.js";import{OUTPUT_SCHEMA_CONSTRAINTS as B,OUTPUT_SCHEMA_TRANSPORT as J,parseOutputSchemaValue as W}from"../../core/runtime/structured-output.js";import{MODEL_SPEC_FORMS as K,MODEL_SPEC_NEXT as Y}from"../../core/runtime/model-selection.js";import{readMergedLaunchConfig as M}from"../../core/config.js";import{parseDurationMs as G}from"../../core/wake.js";import{profilesStateBlock as V}from"../../core/profiles/state-block.js";import{resolveProfileOperand as X}from"../../core/profiles/manifest.js";import{stateBlock as Q}from"../../core/help.js";import{cliClient as Z,getNodeOrNull as ee,rethrowAsCliError as te}from"../api-client.js";import{inTmux as R}from"../../core/runtime/placement-tmux.js";import{openSpawnViewer as ne}from"../surface/node/placement.js";import{resolve as oe}from"node:path";const re=1e5,$='--output-schema writes the accepted result to the node\u2019s context/result.json and pushes it as the node\u2019s final report; a node that cannot honestly satisfy the schema declines with `crtr push result --decline "<reason>" --code <token>`, which finishes it with a failure outcome (reason `declined`) whose `declined` field carries { reason, code, retryable } and no result. Name the code tokens you accept in the prompt; crouter carries the code verbatim and you validate it.',q="Do not wait, poll, or duplicate this child's assignment in your own context \u2014 there is no result to await, stopping will not strand you, and duplicated work wastes the delegated context. You're auto-subscribed, so its finish wakes you on its own. Two moves only: do other independent work right now, or stop and end your turn \u2014 the wake brings you back.";async function ie(e){if(e===void 0||e==="")return q;const t=await ee(e);if(t===null||t.mode!=="orchestrator")return q;const n=t.context_tokens??null;return n===null||n<re?q:`Child spawned \u2014 you're auto-subscribed, so its finish wakes you on its own; never wait, poll, or duplicate the child's assignment in your own context. But you're an orchestrator already carrying ~${Math.round(n/1e3)}k of context: rather than hold this window open for the result, checkpoint context/roadmap.md and \`crtr node yield\` now. Yielding ends this turn, and the child's completion then revives you fresh against your roadmap \u2014 let that clean revive absorb the result instead of this bloated context.`}o(ie,"childFollowUp");function Se(e){const t=Object.keys(M().kinds).sort();if(!t.includes(e))throw new r({error:"unknown_kind",message:`unknown kind: ${e}`,field:"kind",next:`Valid kinds: ${t.join(", ")}.`})}o(Se,"assertKind");function ae(){const e=M().kinds,t=Object.keys(e).filter(i=>{const s=i.indexOf("/");return s===-1?!0:(e[i]?.availableTo??[i.slice(0,s)]).includes("*")}).sort(),n=t.map(i=>{const s=e[i]?.whenToUse??"";return s?`${i} \u2014 ${s}`:i}).join(`
2
- `);return Q("kinds",{count:t.length},n)}o(ae,"kindsStateBlock");function se(){return[{kind:"stdin",name:"prompt",required:!1,constraint:"First user message."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. Defaults to the profile's default kind; `general` when the profile has none. The <kinds> list below names every top-level installable kind."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,default:"base",constraint:"Persona mode. base for one hands-on unit; orchestrator when the unit itself needs decomposition across children. When you hold several parallel units of one kind, spawn ONE orchestrator child of that kind to own the fan-out rather than spawning the units yourself \u2014 unless you are already an orchestrator of that kind, whose job is exactly that fan-out."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Pin the node to this directory. Defaults to the spawner\u2019s directory for a managed child, and to the directory this command runs in for a root."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Display name."},{kind:"flag",name:"parent",type:"string",required:!1,constraint:"Parent node id. Defaults to the calling node."},{kind:"flag",name:"node-id",type:"string",required:!1,constraint:"Exact id for the new node; lowercase letters, digits, and hyphens only, at most 128 characters. Rejected if already present."},{kind:"flag",name:"root",type:"bool",required:!1,constraint:"Spawn an independent root with no parent or subscription. Mutually exclusive with --worktree."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"Birth the node as resident: it parks and stays wakeable without being forced to submit a final. Pass it ONLY when the user will open this node\u2019s viewer pane and work with it back and forth; a child that only other nodes message stays terminal. Applies to managed children and roots; roots default to resident."},{kind:"flag",name:"terminal",type:"bool",required:!1,constraint:"Birth the node as terminal: it finalizes when its work is done and leaves nothing wakeable behind. Only meaningful with --root, whose default is resident; managed children are already terminal. Pass it for bounded programmatic work no one will open a viewer on. Mutually exclusive with --resident."},{kind:"flag",name:"worktree",type:"string",required:!1,constraint:"Local base branch for a crouter-managed worktree for this child. Mutually exclusive with --root."},{kind:"flag",name:"fork-from",type:"string",required:!1,constraint:"Fork the new node from an existing node id, absolute session path, or partial pi session uuid."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model override. Omit unless the task or governing guidance requires a specific model.",focusedHelp:{whenToUse:"Use only when the user, task, or governing agent guidance already requires a specific provider, model, capability tier, or family. Omit it for routine delegation: the selected persona kind and profile own normal model selection, and review personas may enforce a quality floor.",value:`Accepted forms: ${K}. Concrete provider/id requests must be registered. Portable provider/tier, bare-tier, and family-alias requests resolve through the configured model ladders.`,effects:["The resolved concrete override is stored on the node and in its launch recipe, so every launch and revive uses that exact provider/model.","Portable tiers and aliases resolve through the configured ladders; a persona quality floor may raise a weaker request before its resolved model is stored."]}},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile override. Use only when the task needs different project purview, memory, or environment; otherwise omit for normal inheritance or selection.",focusedHelp:{whenToUse:"Use only when the work must run under a different profile because it needs that profile\u2019s project purview, memory store, stored environment, or defaults. Do not use it merely to change the working directory, persona kind, model, or graph ownership; those have separate parameters.",value:"Pass a profile id or name from the <profiles> list below; a close-enough name resolves to the nearest profile and the choice is reported on stderr. Omit it inside a node to inherit the caller\u2019s profile; outside a node, omission runs normal cwd-based profile selection.",effects:["The selected profile id is stored on the node and supplies its profile-scoped config, memory, environment, and injected bearings.","It does not change the parent or subscription; --cwd separately pins the working directory."],dynamicState:o(()=>V(),"dynamicState")}},{kind:"flag",name:"situational-context",type:"string",required:!1,constraint:"Hidden ambient context appended to injected bearings, never visible chat."},{kind:"flag",name:"no-kickoff",type:"bool",required:!1,hidden:!0,constraint:"With --root, start the broker and session idle without a first message or model turn. Mutually exclusive with a prompt and --mode orchestrator."},{kind:"flag",name:"deadline",type:"string",required:!1,constraint:"Positive, representable wall-clock duration from spawn. Grammar: one or more positive integer-unit parts; units: s, m, h, d; adjacent parts are summed. Omit for no deadline."},{kind:"flag",name:"outcome-action",type:"string",required:!1,constraint:"Declared human-action name that receives the node outcome. Grammar: 1\u2013128 ASCII letters, digits, dots, underscores, or hyphens; starts with a letter or digit. Omit when no external delivery target is needed."},{kind:"flag",name:"outcome-payload",type:"string",required:!1,constraint:"JSON value, serialized at most 64 KiB, frozen and echoed to --outcome-action. Requires --outcome-action."},{kind:"flag",name:"output-schema",type:"string",required:!1,constraint:"Replace prose completion with a schema-constrained final result. Use only when its consumer requires fixed fields.",focusedHelp:{whenToUse:"Use only when the node\u2019s consumer needs a machine-checkable final object with fixed fields. Omit it for ordinary delegation or when a prose report is enough; structured output replaces the completion protocol, and an over-constrained schema can force retries.",value:`Pass the JSON Schema the result must satisfy. ${J} ${B}`,effects:["The node must answer with `crtr push result` and cannot finish until the result is accepted; a plain `crtr push final` is blocked while the request is pending.",$,"The managed parent wakes through its existing subscription when the final report arrives; an independent root has no subscriber to wake.","An accepted result, or a decline, removes the request and terminates the node."]}}]}o(se,"nodeNewParams");function de(){return[{name:"node_id",type:"string",required:!0,constraint:"New node id."},{name:"name",type:"string",required:!0,constraint:"Display name."},{name:"frozen_at",type:"string",required:!1,constraint:"Present when a managed child exists but capacity deferred its broker start."},...R()?[{name:"window",type:"string",required:!1,constraint:"tmux window id when a viewer opens."},{name:"session",type:"string",required:!1,constraint:"tmux session when a viewer opens."}]:[],{name:"follow_up",type:"string",required:!0,constraint:"Managed child: continue unrelated work or stop; its final report wakes you. Root: hand it off; no report wakes you."}]}o(de,"nodeNewOutput");function le(){return["Creates nodes/<id>/ in the canvas home, indexes the node in canvas.db, and starts its detached broker engine.","A managed child creates an active parent subscription; its pushes wake the parent. --root creates an independent node with spawned_by provenance and no parent subscription.","--worktree creates a managed worktree at ~/.crouter/canvas/worktrees/<node-id>/ on a new crtr/<node-id> branch.",$,"--deadline persists a wall-clock deadline from spawn; expiry cancels the node and records a failure outcome with reason deadline_exceeded.","--outcome-action registers one resolved local human-action target. When the node settles, crouter retries delivery of its outcome document until the target accepts it or permanently rejects it; --outcome-payload is frozen and echoed in that document.",...R()?["--root opens a viewer for the new node in the current tmux session."]:[]]}o(le,"nodeNewEffects");async function ce(e){const t=e.prompt??"",n=e.noKickoff===!0;if(!n&&t.trim()==="")throw new r({error:"empty_prompt",message:"a prompt is required (stdin or positional)",next:"Pipe a task on stdin or pass it as an argument, or pass --no-kickoff to spawn an idle node with none."});if(n&&t.trim()!=="")throw new r({error:"no_kickoff_with_prompt",message:"--no-kickoff cannot be combined with a prompt",field:"no-kickoff",next:"Drop --no-kickoff, or drop the prompt."});const i=e.kind,s=e.mode??"base",c=e.cwd?.trim(),h=c!==void 0&&c!==""?oe(c):void 0,O=e.name,I=e.parent,a=e.root===!0,N=e.resident===!0,P=e.terminal===!0;if(N&&P)throw new r({error:"lifecycle_conflict",message:"--resident and --terminal cannot both be passed",field:"terminal",next:"Pass the one birth lifecycle you want, or neither to take the default (resident for --root, terminal for a managed child)."});const f=e.worktree;if(f!==void 0&&f.trim()==="")throw new r({error:"worktree_base_required",message:"--worktree requires a base branch",field:"worktree",next:"Pass an existing local branch that landing can fast-forward."});const m=f?.trim(),S=e.forkFrom,p=e.model?.trim();if(p==="")throw new r({error:"empty_spec",message:"a model spec is required",field:"model",next:`Run \`crtr node new --model -h\` and read the focused contract. ${Y}`});const T=e.profile,D=T===void 0?void 0:X(T).profileId,w=e.situationalContext?.trim(),C=w!==void 0&&w!==""?w:void 0,E=W(e.outputSchema),U=E!==null?JSON.stringify(E):null,u=e.deadline;if(u!==void 0){const l=G(u),F=l===null?Number.NaN:new Date(Date.now()+l).getTime();if(l===null||!Number.isFinite(l)||l<=0||!Number.isFinite(F))throw new r({error:"invalid_deadline",message:"--deadline must be a positive representable duration",field:"deadline",next:"Pass positive integer-unit parts using s, m, h, or d."})}const k=e.outcomeAction,y=e.outcomePayload;if(y!==void 0&&k===void 0)throw new r({error:"outcome_payload_requires_action",message:"--outcome-payload requires --outcome-action",field:"outcome-payload",next:"Pass the declared delivery action with --outcome-action."});let g;if(y!==void 0)try{g=JSON.parse(y)}catch{throw new r({error:"invalid_outcome_payload",message:"--outcome-payload must be valid JSON",field:"outcome-payload",next:"Pass one valid JSON value."})}const b=e.nodeId?.trim();if(a&&m!==void 0)throw new r({error:"worktree_root_conflict",message:"--worktree is mutually exclusive with --root",field:"worktree",next:"Drop either --root or --worktree."});if(n&&!a)throw new r({error:"no_kickoff_requires_root",message:"--no-kickoff is only valid with --root",field:"no-kickoff",next:"Add --root, or drop --no-kickoff and provide a prompt."});if(n&&s==="orchestrator")throw new r({error:"no_kickoff_orchestrator_unsupported",message:"--no-kickoff cannot be combined with --mode orchestrator",field:"no-kickoff",next:"Drop --no-kickoff and provide a prompt, or spawn in base mode."});const v=z(),j=I??v;x("node_new.create_start",{root:a});const d=await Z().createNode({...i!==void 0?{kind:i}:{},mode:s,cwd:process.cwd(),...h!==void 0&&h!==""?{pin_cwd:h}:{},...O!==void 0?{name:O}:{},prompt:t,...a?{root:!0}:{parent:j??null},...v!==void 0?{creator:v}:{},...N?{root_lifecycle:"resident"}:{},...P?{root_lifecycle:"terminal"}:{},...m!==void 0?{worktree:m}:{},...S!==void 0?{fork_from:S}:{},...p!==void 0?{model:p}:{},...D!==void 0?{profile:D}:{},...C!==void 0?{situational_context:C}:{},...n?{no_kickoff:!0}:{},...U!==null?{output_schema:U}:{},...u!==void 0?{deadline:u}:{},...k!==void 0?{outcome_delivery:{action:k,...g===void 0?{}:{payload:g}}}:{},...b!==void 0&&b!==""?{node_id:b}:{},...a?{prefer_warm:!0}:{}}).catch(te);x("node_new.node_created",{node:d.node_id});let _={};a&&(_=ne(d.node_id,d.cwd,d.name)),a&&x("node_new.viewer_window_opened");const A=!a&&d.frozen_at!==null;return{node_id:d.node_id,name:d.name,...A?{frozen_at:d.frozen_at}:{},window:_.window,session:_.session,follow_up:a?n?"Independent root spawned idle. No kickoff turn ran; hand it off or attach and prompt it. No report wakes you.":"Independent root spawned. You are not subscribed, so its finish does not wake you; hand it off and move on.":A?"Child row exists, but no broker started because capacity is full. It is frozen and will launch when a broker slot frees; its final report wakes you then.":await ie(j)}}o(ce,"runNodeCreation");const Te=H({name:"new",description:"create and start a node immediately",whenToUse:"a unit of work is genuinely separable from what you are doing: a bounded subtask you would otherwise grind out inline, several independent units worth running in parallel (usually via one orchestrator child of the matching kind rather than a flat fan-out from you), a scouting pass over unfamiliar code, a change that wants its own git worktree, or an answer you need in a fixed shape rather than as prose",tier:"important",help:{name:"node new",summary:"create a node immediately and start its detached broker",guide:"The prompt is the child\u2019s entire brief: it wakes with this prompt, its persona, and ambient bearings \u2014 none of your conversation carries over. State the outcome and constraints. Pass an implementation plan only when it is already settled or necessary to preserve an approved decision; otherwise, let the child investigate and choose how. Give the reason along with the request: the larger goal this serves and what the child's output enables, so the child resolves ambiguity toward your intent instead of guessing. Name by absolute path every artifact the task depends on (a spec, an explore report, an earlier child's findings); the child inherits only the files the prompt names. When the report must carry something specific\u2014findings inline, or paths to artifacts it wrote\u2014say so in the prompt.",params:se(),output:de(),dynamicState:o(()=>ae(),"dynamicState"),outputKind:"object",effects:le()},run:o(e=>ce(e),"run"),render:o(e=>{const t=e.window?` in window ${e.window}`:"",n=[`Spawned "${e.name}" (${e.node_id})${t}.`];return e.session&&n.push(`- session: ${e.session}`),n.push("",String(e.follow_up)),n.join(`
3
- `)},"render")});export{Se as assertKind,ie as childFollowUp,ae as kindsStateBlock,Te as nodeNew};
1
+ var J=Object.defineProperty;var o=(e,t)=>J(e,"name",{value:t,configurable:!0});import{envNodeId as W,envProfileId as K}from"../../shared/env.js";import{defineLeaf as Y}from"../../core/command.js";import{InputError as r}from"../../core/io.js";import{mark as O}from"../../core/timing.js";import{OUTPUT_SCHEMA_CONSTRAINTS as G,OUTPUT_SCHEMA_TRANSPORT as V,parseOutputSchemaValue as X}from"../../core/runtime/structured-output.js";import{MODEL_SPEC_FORMS as Q,MODEL_SPEC_NEXT as Z}from"../../core/runtime/model-selection.js";import{readMergedLaunchConfig as R}from"../../core/config.js";import{parseDurationMs as ee}from"../../core/wake.js";import{profilesStateBlock as te}from"../../core/profiles/state-block.js";import{resolveProfileOperand as ne}from"../../core/profiles/manifest.js";import{stateBlock as oe}from"../../core/help.js";import{cliClient as re,getNodeOrNull as I,rethrowAsCliError as ie}from"../api-client.js";import{inTmux as $}from"../../core/runtime/placement-tmux.js";import{openSpawnViewer as ae}from"../surface/node/placement.js";import{resolve as se}from"node:path";const de=1e5,F='--output-schema writes the accepted result to the node\u2019s context/result.json and pushes it as the node\u2019s final report; a node that cannot honestly satisfy the schema declines with `crtr push result --decline "<reason>" --code <token>`, which finishes it with a failure outcome (reason `declined`) whose `declined` field carries { reason, code, retryable } and no result. Name the code tokens you accept in the prompt; crouter carries the code verbatim and you validate it.',N="Do not wait, poll, or duplicate this child's assignment in your own context \u2014 there is no result to await, stopping will not strand you, and duplicated work wastes the delegated context. You're auto-subscribed, so its finish wakes you on its own. Two moves only: do other independent work right now, or stop and end your turn \u2014 the wake brings you back.";async function le(e){if(e===void 0||e==="")return N;const t=await I(e);if(t===null||t.mode!=="orchestrator")return N;const n=t.context_tokens??null;return n===null||n<de?N:`Child spawned \u2014 you're auto-subscribed, so its finish wakes you on its own; never wait, poll, or duplicate the child's assignment in your own context. But you're an orchestrator already carrying ~${Math.round(n/1e3)}k of context: rather than hold this window open for the result, checkpoint context/roadmap.md and \`crtr node yield\` now. Yielding ends this turn, and the child's completion then revives you fresh against your roadmap \u2014 let that clean revive absorb the result instead of this bloated context.`}o(le,"childFollowUp");function Ee(e){const t=Object.keys(R().kinds).sort();if(!t.includes(e))throw new r({error:"unknown_kind",message:`unknown kind: ${e}`,field:"kind",next:`Valid kinds: ${t.join(", ")}.`})}o(Ee,"assertKind");function ce(){const e=R().kinds,t=Object.keys(e).filter(i=>{const s=i.indexOf("/");return s===-1?!0:(e[i]?.availableTo??[i.slice(0,s)]).includes("*")}).sort(),n=t.map(i=>{const s=e[i]?.whenToUse??"";return s?`${i} \u2014 ${s}`:i}).join(`
2
+ `);return oe("kinds",{count:t.length},n)}o(ce,"kindsStateBlock");function ue(){return[{kind:"stdin",name:"prompt",required:!1,constraint:"First user message."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. Defaults to the profile's default kind; `general` when the profile has none. The <kinds> list below names every top-level installable kind."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,default:"base",constraint:"Persona mode. base for one hands-on unit; orchestrator when the unit itself needs decomposition across children. When you hold several parallel units of one kind, spawn ONE orchestrator child of that kind to own the fan-out rather than spawning the units yourself \u2014 unless you are already an orchestrator of that kind, whose job is exactly that fan-out."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Pin the node to this directory. Defaults to the spawner\u2019s directory for a managed child, and to the directory this command runs in for a root."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Display name."},{kind:"flag",name:"parent",type:"string",required:!1,constraint:"Parent node id. Defaults to the calling node."},{kind:"flag",name:"node-id",type:"string",required:!1,constraint:"Exact id for the new node; lowercase letters, digits, and hyphens only, at most 128 characters. Rejected if already present."},{kind:"flag",name:"root",type:"bool",required:!1,constraint:"Spawn an independent root with no parent or subscription. Mutually exclusive with --worktree."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"Birth the node as resident: it parks and stays wakeable without being forced to submit a final. Pass it ONLY when the user will open this node\u2019s viewer pane and work with it back and forth; a child that only other nodes message stays terminal. Applies to managed children and roots; roots default to resident."},{kind:"flag",name:"terminal",type:"bool",required:!1,constraint:"Birth the node as terminal: it finalizes when its work is done and leaves nothing wakeable behind. Only meaningful with --root, whose default is resident; managed children are already terminal. Pass it for bounded programmatic work no one will open a viewer on. Mutually exclusive with --resident."},{kind:"flag",name:"worktree",type:"string",required:!1,constraint:"Local base branch for a crouter-managed worktree for this child. Mutually exclusive with --root."},{kind:"flag",name:"fork-from",type:"string",required:!1,constraint:"Fork the new node from an existing node id, absolute session path, or partial pi session uuid."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model override. Omit unless the task or governing guidance requires a specific model.",focusedHelp:{whenToUse:"Use only when the user, task, or governing agent guidance already requires a specific provider, model, capability tier, or family. Omit it for routine delegation: the selected persona kind and profile own normal model selection, and review personas may enforce a quality floor.",value:`Accepted forms: ${Q}. Concrete provider/id requests must be registered. Portable provider/tier, bare-tier, and family-alias requests resolve through the configured model ladders.`,effects:["The resolved concrete override is stored on the node and in its launch recipe, so every launch and revive uses that exact provider/model.","Portable tiers and aliases resolve through the configured ladders; a persona quality floor may raise a weaker request before its resolved model is stored."]}},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile override. Use only when the task needs different project purview, memory, or environment; otherwise omit for normal inheritance or selection.",focusedHelp:{whenToUse:"Use only when the work must run under a different profile because it needs that profile\u2019s project purview, memory store, stored environment, or defaults. Do not use it merely to change the working directory, persona kind, model, or graph ownership; those have separate parameters.",value:"Pass a profile id or name from the <profiles> list below; a close-enough name resolves to the nearest profile and the choice is reported on stderr. Omit it inside a node to inherit the caller\u2019s profile; outside a node, omission runs normal cwd-based profile selection.",effects:["The selected profile id is stored on the node and supplies its profile-scoped config, memory, environment, and injected bearings.","It does not change the parent or subscription; --cwd separately pins the working directory."],dynamicState:o(()=>te(),"dynamicState")}},{kind:"flag",name:"situational-context",type:"string",required:!1,constraint:"Hidden ambient context appended to injected bearings, never visible chat."},{kind:"flag",name:"no-kickoff",type:"bool",required:!1,hidden:!0,constraint:"With --root, start the broker and session idle without a first message or model turn. Mutually exclusive with a prompt and --mode orchestrator."},{kind:"flag",name:"deadline",type:"string",required:!1,constraint:"Positive, representable wall-clock duration from spawn. Grammar: one or more positive integer-unit parts; units: s, m, h, d; adjacent parts are summed. Omit for no deadline."},{kind:"flag",name:"outcome-action",type:"string",required:!1,constraint:"Declared human-action name that receives the node outcome. Grammar: 1\u2013128 ASCII letters, digits, dots, underscores, or hyphens; starts with a letter or digit. Omit when no external delivery target is needed."},{kind:"flag",name:"outcome-payload",type:"string",required:!1,constraint:"JSON value, serialized at most 64 KiB, frozen and echoed to --outcome-action. Requires --outcome-action."},{kind:"flag",name:"output-schema",type:"string",required:!1,constraint:"Replace prose completion with a schema-constrained final result. Use only when its consumer requires fixed fields.",focusedHelp:{whenToUse:"Use only when the node\u2019s consumer needs a machine-checkable final object with fixed fields. Omit it for ordinary delegation or when a prose report is enough; structured output replaces the completion protocol, and an over-constrained schema can force retries.",value:`Pass the JSON Schema the result must satisfy. ${V} ${G}`,effects:["The node must answer with `crtr push result` and cannot finish until the result is accepted; a plain `crtr push final` is blocked while the request is pending.",F,"The managed parent wakes through its existing subscription when the final report arrives; an independent root has no subscriber to wake.","An accepted result, or a decline, removes the request and terminates the node."]}}]}o(ue,"nodeNewParams");function fe(){return[{name:"node_id",type:"string",required:!0,constraint:"New node id."},{name:"name",type:"string",required:!0,constraint:"Display name."},{name:"frozen_at",type:"string",required:!1,constraint:"Present when a managed child exists but capacity deferred its broker start."},...$()?[{name:"window",type:"string",required:!1,constraint:"tmux window id when a viewer opens."},{name:"session",type:"string",required:!1,constraint:"tmux session when a viewer opens."}]:[],{name:"follow_up",type:"string",required:!0,constraint:"Managed child: continue unrelated work or stop; its final report wakes you. Root: hand it off; no report wakes you."}]}o(fe,"nodeNewOutput");function he(){return["Creates nodes/<id>/ in the canvas home, indexes the node in canvas.db, and starts its detached broker engine.","A managed child creates an active parent subscription; its pushes wake the parent. --root creates an independent node with spawned_by provenance and no parent subscription.","--worktree creates a managed worktree at ~/.crouter/canvas/worktrees/<node-id>/ on a new crtr/<node-id> branch.",F,"--deadline persists a wall-clock deadline from spawn; expiry cancels the node and records a failure outcome with reason deadline_exceeded.","--outcome-action registers one resolved local human-action target. When the node settles, crouter retries delivery of its outcome document until the target accepts it or permanently rejects it; --outcome-payload is frozen and echoed in that document.",...$()?["--root opens a viewer for the new node in the current tmux session."]:[]]}o(he,"nodeNewEffects");async function me(e){const t=e.prompt??"",n=e.noKickoff===!0;if(!n&&t.trim()==="")throw new r({error:"empty_prompt",message:"a prompt is required (stdin or positional)",next:"Pipe a task on stdin or pass it as an argument, or pass --no-kickoff to spawn an idle node with none."});if(n&&t.trim()!=="")throw new r({error:"no_kickoff_with_prompt",message:"--no-kickoff cannot be combined with a prompt",field:"no-kickoff",next:"Drop --no-kickoff, or drop the prompt."});const i=e.kind,s=e.mode??"base",f=e.cwd?.trim(),m=f!==void 0&&f!==""?se(f):void 0,S=e.name,L=e.parent,a=e.root===!0,T=e.resident===!0,C=e.terminal===!0;if(T&&C)throw new r({error:"lifecycle_conflict",message:"--resident and --terminal cannot both be passed",field:"terminal",next:"Pass the one birth lifecycle you want, or neither to take the default (resident for --root, terminal for a managed child)."});const p=e.worktree;if(p!==void 0&&p.trim()==="")throw new r({error:"worktree_base_required",message:"--worktree requires a base branch",field:"worktree",next:"Pass an existing local branch that landing can fast-forward."});const w=p?.trim(),D=e.forkFrom,y=e.model?.trim();if(y==="")throw new r({error:"empty_spec",message:"a model spec is required",field:"model",next:`Run \`crtr node new --model -h\` and read the focused contract. ${Z}`});const E=e.profile,k=E===void 0?void 0:ne(E).profileId,g=e.situationalContext?.trim(),U=g!==void 0&&g!==""?g:void 0,j=X(e.outputSchema),M=j!==null?JSON.stringify(j):null,h=e.deadline;if(h!==void 0){const l=ee(h),B=l===null?Number.NaN:new Date(Date.now()+l).getTime();if(l===null||!Number.isFinite(l)||l<=0||!Number.isFinite(B))throw new r({error:"invalid_deadline",message:"--deadline must be a positive representable duration",field:"deadline",next:"Pass positive integer-unit parts using s, m, h, or d."})}const b=e.outcomeAction,v=e.outcomePayload;if(v!==void 0&&b===void 0)throw new r({error:"outcome_payload_requires_action",message:"--outcome-payload requires --outcome-action",field:"outcome-payload",next:"Pass the declared delivery action with --outcome-action."});let _;if(v!==void 0)try{_=JSON.parse(v)}catch{throw new r({error:"invalid_outcome_payload",message:"--outcome-payload must be valid JSON",field:"outcome-payload",next:"Pass one valid JSON value."})}const x=e.nodeId?.trim();if(a&&w!==void 0)throw new r({error:"worktree_root_conflict",message:"--worktree is mutually exclusive with --root",field:"worktree",next:"Drop either --root or --worktree."});if(n&&!a)throw new r({error:"no_kickoff_requires_root",message:"--no-kickoff is only valid with --root",field:"no-kickoff",next:"Add --root, or drop --no-kickoff and provide a prompt."});if(n&&s==="orchestrator")throw new r({error:"no_kickoff_orchestrator_unsupported",message:"--no-kickoff cannot be combined with --mode orchestrator",field:"no-kickoff",next:"Drop --no-kickoff and provide a prompt, or spawn in base mode."});const q=W(),c=L??q;let u=(k??K())||null;if(u===null&&c!==void 0&&(u=(await I(c))?.profile_id??null),u===null&&c===void 0){const{selectProfileForCwdReadOnly:l}=await import("../../core/profiles/select.js");u=l(process.cwd())}const{exitForMissingProviderCredential:z,hasConfiguredProviderCredential:H}=await import("../../core/runtime/provider-credential-gate.js");await H(u)||z(),O("node_new.create_start",{root:a});const d=await re().createNode({...i!==void 0?{kind:i}:{},mode:s,cwd:process.cwd(),...m!==void 0&&m!==""?{pin_cwd:m}:{},...S!==void 0?{name:S}:{},prompt:t,...a?{root:!0}:{parent:c??null},...q!==void 0?{creator:q}:{},...T?{root_lifecycle:"resident"}:{},...C?{root_lifecycle:"terminal"}:{},...w!==void 0?{worktree:w}:{},...D!==void 0?{fork_from:D}:{},...y!==void 0?{model:y}:{},...k!==void 0?{profile:k}:{},...U!==void 0?{situational_context:U}:{},...n?{no_kickoff:!0}:{},...M!==null?{output_schema:M}:{},...h!==void 0?{deadline:h}:{},...b!==void 0?{outcome_delivery:{action:b,..._===void 0?{}:{payload:_}}}:{},...x!==void 0&&x!==""?{node_id:x}:{},...a?{prefer_warm:!0}:{}}).catch(ie);O("node_new.node_created",{node:d.node_id});let P={};a&&(P=ae(d.node_id,d.cwd,d.name)),a&&O("node_new.viewer_window_opened");const A=!a&&d.frozen_at!==null;return{node_id:d.node_id,name:d.name,...A?{frozen_at:d.frozen_at}:{},window:P.window,session:P.session,follow_up:a?n?"Independent root spawned idle. No kickoff turn ran; hand it off or attach and prompt it. No report wakes you.":"Independent root spawned. You are not subscribed, so its finish does not wake you; hand it off and move on.":A?"Child row exists, but no broker started because capacity is full. It is frozen and will launch when a broker slot frees; its final report wakes you then.":await le(c)}}o(me,"runNodeCreation");const Ue=Y({name:"new",description:"create and start a node immediately",whenToUse:"a unit of work is genuinely separable from what you are doing: a bounded subtask you would otherwise grind out inline, several independent units worth running in parallel (usually via one orchestrator child of the matching kind rather than a flat fan-out from you), a scouting pass over unfamiliar code, a change that wants its own git worktree, or an answer you need in a fixed shape rather than as prose",tier:"important",help:{name:"node new",summary:"create a node immediately and start its detached broker",guide:"The prompt is the child\u2019s entire brief: it wakes with this prompt, its persona, and ambient bearings \u2014 none of your conversation carries over. State the outcome and constraints. Pass an implementation plan only when it is already settled or necessary to preserve an approved decision; otherwise, let the child investigate and choose how. Give the reason along with the request: the larger goal this serves and what the child's output enables, so the child resolves ambiguity toward your intent instead of guessing. Name by absolute path every artifact the task depends on (a spec, an explore report, an earlier child's findings); the child inherits only the files the prompt names. When the report must carry something specific\u2014findings inline, or paths to artifacts it wrote\u2014say so in the prompt.",params:ue(),output:fe(),dynamicState:o(()=>ce(),"dynamicState"),outputKind:"object",effects:he()},run:o(e=>me(e),"run"),render:o(e=>{const t=e.window?` in window ${e.window}`:"",n=[`Spawned "${e.name}" (${e.node_id})${t}.`];return e.session&&n.push(`- session: ${e.session}`),n.push("",String(e.follow_up)),n.join(`
3
+ `)},"render")});export{Ee as assertKind,le as childFollowUp,ce as kindsStateBlock,Ue as nodeNew};
@@ -1 +1 @@
1
- var u=Object.defineProperty;var l=(a,e)=>u(a,"name",{value:e,configurable:!0});import{truncateToWidth as d}from"@earendil-works/pi-tui";import{theme as s,wrapText as m}from"../../../core/tui/panel.js";class P{static{l(this,"PluginsPanel")}manifest;installedPackageIds;onChange;selectedPackageIds=new Set;index=0;expandedId=null;constructor(e,t,n){this.manifest=e,this.installedPackageIds=t,this.onChange=n;for(const i of e)this.selectedPackageIds.add(i.id)}badge(){const e=this.manifest.filter(t=>!this.installedPackageIds.has(t.id)).length;return e===0?`${this.manifest.length} \u2713`:`${e} pending`}get selected(){return this.manifest.filter(e=>this.selectedPackageIds.has(e.id))}current(){return this.manifest[this.index]}handleInput(e,t){if(t===void 0)return!1;if(t("crtr.setup.list-down",e))this.index=this.manifest.length===0?0:(this.index+1)%this.manifest.length;else if(t("crtr.setup.list-up",e))this.index=this.manifest.length===0?0:(this.index-1+this.manifest.length)%this.manifest.length;else if(t("crtr.setup.toggle",e)){const n=this.current();n&&(this.selectedPackageIds.has(n.id)?this.selectedPackageIds.delete(n.id):this.selectedPackageIds.add(n.id))}else if(t("crtr.setup.details",e)){const n=this.current();n&&(this.expandedId=this.expandedId===n.id?null:n.id)}else return!1;return this.onChange(),!0}render(e){const t=[d(`${s.fg("accent",s.bold("Plugins"))}${s.fg("dim"," default ON")}`,e)];for(const[n,i]of this.manifest.entries()){const r=n===this.index,c=this.selectedPackageIds.has(i.id)?s.fg("success","[x]"):s.fg("dim","[ ]"),h=r?s.fg("accent","\u25B6"):s.fg("dim"," "),f=r?s.fg("accent",i.name):i.name,g=this.installedPackageIds.has(i.id)?s.fg("success","\u2713 installed"):s.fg("warning","not installed");if(t.push(d(`${h} ${c} ${f} ${s.fg("dim","\u2014")} ${s.fg("muted",i.shortDescription)} ${g}`,e)),this.expandedId===i.id)for(const o of m(i.longDescription,Math.max(1,e-4)))t.push(d(s.fg("dim",` ${o}`),e))}return t}}export{P as PluginsPanel};
1
+ var p=Object.defineProperty;var c=(a,e)=>p(a,"name",{value:e,configurable:!0});import{truncateToWidth as d}from"@earendil-works/pi-tui";import{theme as t,wrapText as I}from"../../../core/tui/panel.js";const l="crtr-extensions";class ${static{c(this,"PluginsPanel")}manifest;installedPackageIds;onChange;selectedPackageIds=new Set;index=0;expandedId=null;constructor(e,s,n){this.manifest=e,this.installedPackageIds=s,this.onChange=n;for(const i of e)this.selectedPackageIds.add(i.id)}badge(){const e=this.manifest.filter(s=>!this.installedPackageIds.has(s.id)).length;return e===0?`${this.manifest.length} \u2713`:`${e} pending`}get selected(){return this.manifest.filter(e=>this.selectedPackageIds.has(e.id))}current(){return this.manifest[this.index]}handleInput(e,s){if(s===void 0)return!1;if(s("crtr.setup.list-down",e))this.index=this.manifest.length===0?0:(this.index+1)%this.manifest.length;else if(s("crtr.setup.list-up",e))this.index=this.manifest.length===0?0:(this.index-1+this.manifest.length)%this.manifest.length;else if(s("crtr.setup.toggle",e)){const n=this.current();n&&n.id!==l&&(this.selectedPackageIds.has(n.id)?this.selectedPackageIds.delete(n.id):this.selectedPackageIds.add(n.id))}else if(s("crtr.setup.details",e)){const n=this.current();n&&(this.expandedId=this.expandedId===n.id?null:n.id)}else return!1;return this.onChange(),!0}render(e){const s=[d(t.fg("accent",t.bold("Plugins")),e),d(t.fg("muted","Everything is checked by default. Leave it all on unless you have a specific reason not to."),e)];for(const[n,i]of this.manifest.entries()){const r=n===this.index,h=this.selectedPackageIds.has(i.id)?t.fg("success","[x]"):t.fg("dim","[ ]"),f=r?t.fg("accent","\u25B6"):t.fg("dim"," "),o=r?t.fg("accent",i.name):i.name,g=i.id===l?` ${t.fg("dim","required")}`:"",u=this.installedPackageIds.has(i.id)?t.fg("success","\u2713 installed"):t.fg("warning","not installed");if(s.push(d(`${f} ${h} ${o}${g} ${t.fg("dim","\u2014")} ${t.fg("muted",i.shortDescription)} ${u}`,e)),this.expandedId===i.id)for(const m of I(i.longDescription,Math.max(1,e-4)))s.push(d(t.fg("dim",` ${m}`),e))}return s}}export{$ as PluginsPanel};
@@ -52,6 +52,10 @@ export declare class ProviderPanel implements SetupPanel {
52
52
  isNestedFlowActive(): boolean;
53
53
  dispose(): void;
54
54
  private runMutation;
55
+ /** Prefilled label for a new managed account: `default` for the first one, then
56
+ * `account-2`, `account-3`… so Enter alone never collides with an existing row
57
+ * (pool labels compare case-insensitively). */
58
+ private suggestedAccountLabel;
55
59
  private rename;
56
60
  private remove;
57
61
  private promote;
@@ -1 +1 @@
1
- var S=Object.defineProperty;var m=(u,e)=>S(u,"name",{value:e,configurable:!0});import{LoginDialogComponent as k}from"@earendil-works/pi-coding-agent";import{Input as R,matchesKey as h,truncateToWidth as D}from"@earendil-works/pi-tui";import{execFile as E}from"node:child_process";import{dialogAuthInteraction as B}from"../../../core/auth-interaction.js";import{isManagedProvider as F,promoteSubscription as N,readSubscriptionPool as T,renameSubscription as U}from"../../../core/subscription-state.js";import{removeProviderRow as _}from"../../../core/provider-management.js";import{cliClient as V}from"../../api-client.js";import{loginProvider as j}from"../provider-login.js";import{fitTail as C,theme as l,visibleRange as A}from"../../../core/tui/panel.js";function M(u,e){const t=u.getProviders().filter(i=>i.auth.oauth!==void 0),o=new Set(t.map(i=>i.id)),n=new Set;return[...t.map(i=>({providerId:i.id,name:i.name,managed:F(i.id),authType:"oauth"})),...e.getAll().map(i=>({providerId:i.provider,name:e.getProviderDisplayName(i.provider),managed:F(i.provider),authType:o.has(i.provider)?"oauth":"api_key"}))].filter(i=>!n.has(i.providerId)&&!!n.add(i.providerId))}m(M,"buildProviderCatalog");function q(u,e){return e||u instanceof Error&&u.name==="AbortError"?"Login cancelled":`Login error: ${u instanceof Error?u.message:String(u)}`}m(q,"classifyLoginFailure");class Z{static{m(this,"ProviderPanel")}tui;agentDir;runtime;registry;renameInput=new R;rows=[];selected=0;mode="list";notice="";catalog=[];catalogIndex=0;loginProvider;loginFlow;mutationInFlight=!1;onChange;constructor(e,t,o,n){this.tui=e,this.agentDir=t,this.runtime=o,this.registry=n,this.renameInput.onSubmit=()=>this.rename(),this.renameInput.onEscape=()=>{this.mode="list"},this.reload()}notifyChange(){this.onChange?.(),this.tui.requestRender()}reloadAfterAuthChange(){this.reload(),this.registry.refresh().then(()=>{this.reload(),this.notifyChange()})}reload(){const e=this.registry,t=[];for(const o of M(this.runtime,e)){const n=e.getProviderAuthStatus(o.providerId);if(o.managed){const i=T(o.providerId);if(i.length===0&&!n.source)continue;t.push({...o,configured:i.length>0||n.configured,source:n.source,sourceLabel:n.label}),i.forEach((s,c)=>t.push({...o,label:s.label,preferred:c===0,cooldownUntil:s.rateLimitedUntil,accountId:s.accountId}));continue}n.source&&t.push({...o,configured:n.configured,source:n.source,sourceLabel:n.label})}this.rows=t,this.selected=Math.min(this.selected,Math.max(0,t.length))}selectedRow(){return this.rows[this.selected]}openBrowser(e){const t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",o=process.platform==="win32"?["/c","start","",e]:[e];E(t,o,{timeout:5e3},()=>{})}openCatalog(){this.catalog=M(this.runtime,this.registry),this.catalogIndex=0,this.mode="catalog"}startLogin(e,t){this.loginProvider=e;let o;const n=m(r=>{!o.active||this.loginFlow!==o||(o.active=!1,this.loginFlow=void 0,this.mode="list",this.notice=r,this.reloadAfterAuthChange(),this.notifyChange())},"complete"),i=new k(this.tui,e.providerId,(r,p)=>{r||n(p?`Login failed: ${p}`:"Login cancelled")},e.name);o={dialog:i,active:!0,committing:!1},this.loginFlow=o,this.mode="login";const s=i.handleInput.bind(i);i.handleInput=r=>{o.committing||s(r)};const c=m(()=>o.active&&this.loginFlow===o&&!i.signal.aborted,"isActive"),d=m(()=>c()?(o.committing=!0,i.showDetails(["Saving credentials\u2026"]),!0):!1,"beginCommit"),g=m(r=>{n(q(r,i.signal.aborted))},"fail");if(e.authType==="api_key"){i.showPrompt(`Enter API key for ${e.name}:`,"sk-...").then(async r=>{if(c()){if(!r.trim()){n("No key entered \u2014 login cancelled");return}d()&&(await V().installCredential(e.providerId,{kind:"api_key",api_key:r.trim()}),n(`API key saved for ${e.name}`))}}).catch(g);return}const $=B(i,{openBrowser:m(r=>this.openBrowser(r),"openBrowser"),onChange:m(()=>this.notifyChange(),"onChange"),isActive:c});j(this.runtime,e.providerId,$,{label:t,beforeInstall:d}).then(r=>{r&&c()&&n(`Logged in to ${e.name}`)}).catch(g)}isNestedFlowActive(){return this.mode==="login"}dispose(){const e=this.loginFlow;e&&(e.active=!1,this.loginFlow=void 0,e.dialog.handleInput("\x1B"))}runMutation(e){this.mutationInFlight||(this.mutationInFlight=!0,e().catch(t=>{this.notice=t instanceof Error?t.message:String(t)}).finally(()=>{this.mutationInFlight=!1,this.notifyChange()}))}rename(){const e=this.selectedRow();!e?.managed||!e.label||(this.mode="list",this.runMutation(async()=>{await U(e.providerId,e.label,this.renameInput.getValue()),this.notice=`Renamed ${e.name} account`,this.reload()}))}remove(e){this.runMutation(async()=>{this.notice=await _(this.agentDir,e),this.reloadAfterAuthChange()})}promote(e){this.runMutation(async()=>{await N(e.providerId,e.label),this.notice=`Preferred ${e.name} account`,this.reload()})}handleInput(e){if(this.mode==="login")return this.loginFlow?.dialog.handleInput(e),!0;if(this.mutationInFlight)return!0;if(this.mode==="rename"||this.mode==="label")return this.renameInput.handleInput(e),!0;if(this.mode==="catalog"){if(h(e,"escape"))return this.mode="list",!0;if(h(e,"j")||h(e,"down"))return this.catalogIndex=Math.min(this.catalog.length-1,this.catalogIndex+1),!0;if(h(e,"k")||h(e,"up"))return this.catalogIndex=Math.max(0,this.catalogIndex-1),!0;if(h(e,"enter")){const n=this.catalog[this.catalogIndex];return n.managed?(this.loginProvider=n,this.renameInput.setValue(""),this.renameInput.onSubmit=()=>{const i=this.renameInput.getValue().trim();i&&this.startLogin(n,i)},this.mode="label"):this.startLogin(n),!0}return!0}if(this.mode==="remove"){if(h(e,"y")||h(e,"enter")){const n=this.selectedRow();n&&(n.managed||n.configured)&&this.remove(n)}return this.mode="list",!0}if(h(e,"j")||h(e,"down"))return this.selected=Math.min(this.rows.length,this.selected+1),!0;if(h(e,"k")||h(e,"up"))return this.selected=Math.max(0,this.selected-1),!0;const t=this.selectedRow();if(h(e,"p")&&t?.managed&&t.label)return this.promote(t),!0;if(h(e,"r")&&t?.managed&&t.label)return this.renameInput.setValue(t.label),this.renameInput.onSubmit=()=>this.rename(),this.mode="rename",!0;if(h(e,"x")&&(t?.managed||t?.configured))return this.mode="remove",!0;if(h(e,"a"))return this.openCatalog(),!0;const o=t?.source==="environment"||t?.source==="runtime";return h(e,"l")&&t&&!o?(t.managed&&t.label?this.startLogin(t,t.label):this.startLogin(t),!0):h(e,"enter")?(t&&!o?this.startLogin(t,t.managed&&t.label?t.label:void 0):t||this.openCatalog(),!0):!1}badge(){return String(this.rows.filter(e=>e.label===void 0).length)}render(e,t){const o=l.fg("accent",l.bold("Providers")),n=l.fg("dim",`${this.rows.filter(c=>c.label===void 0).length} configured`),i=Math.max(1,t);let s;if(this.mode==="login")s=C(this.loginFlow?.dialog.render(e)??[],i);else if(this.mode==="rename"||this.mode==="label")s=C([o,n,"",l.fg("accent",this.mode==="rename"?"Rename account":`Name the ${this.loginProvider?.name??"provider"} account`),...this.renameInput.render(Math.max(1,e-8))],i);else if(this.mode==="remove"){const c=this.selectedRow(),d=c?.label??(c?.managed?`${c.name} \xB7 all accounts`:c?.name??"account");s=C([o,n,"",l.fg("warning",`Remove ${d}? y/enter confirm \xB7 any other key cancel`)],i)}else{const c=[o,n].slice(0,Math.max(0,i-1)),d=i-c.length;if(s=[...c],this.mode==="catalog"){const g=this.catalog.length,r=g>d&&d>=2,p=r?d-1:d,{start:I,end:v}=A(g,this.catalogIndex,p);let w=d-(v-I)-(r?1:0);w>0&&(s.push(l.fg("dim","Select a provider to add \xB7 esc back")),w-=1);for(let f=I;f<v;f++){const x=this.catalog[f];s.push(`${f===this.catalogIndex?l.fg("accent","\u25B6"):" "} ${x.name}`)}r&&s.push(l.fg("dim",`(${this.catalogIndex+1}/${g})`))}else{const g=this.rows.length+1,r=g>d&&d>=2,p=r?d-1:d,{start:I,end:v}=A(g,this.selected,p);let w=d-(v-I)-(r?1:0);const f=this.rows.length===0&&w>0;f&&(w-=1);const x=!!this.notice&&w>0;f&&s.push(l.fg("warning","No provider configured yet."));for(let b=I;b<v;b++){if(b===this.rows.length){s.push(`${this.selected===this.rows.length?l.fg("accent","\u25B6"):" "} ${l.fg("accent","\uFF0B Add provider")}`);continue}const a=this.rows[b],P=b===this.selected?l.fg("accent","\u25B6"):" ";if(a.label){const L=a.cooldownUntil&&a.cooldownUntil>Date.now()?`cooldown ${Math.ceil((a.cooldownUntil-Date.now())/6e4)}m`:"ready",y=a.accountId?` \xB7 ${a.accountId.length>12?`${a.accountId.slice(0,8)}\u2026${a.accountId.slice(-4)}`:a.accountId}`:"";s.push(`${P} ${a.preferred?l.fg("success","\u25CF"):" "} ${a.label}${l.fg("dim",y)} ${l.fg("dim",L)}${a.preferred?l.fg("accent"," preferred"):""}`)}else{const L=a.managed?`${this.rows.filter(y=>y.providerId===a.providerId&&y.label).length} accounts`:a.source==="environment"||a.source==="runtime"?`${a.source}${a.sourceLabel?` \xB7 ${a.sourceLabel}`:""} (view only)`:"configured";s.push(`${P} ${l.fg("accent",a.name)}${l.fg("dim",` ${L}`)}`)}}r&&s.push(l.fg("dim",`(${this.selected+1}/${g})`)),x&&s.push(l.fg("dim",this.notice))}}return s.map(c=>D(c,e))}}export{Z as ProviderPanel,M as buildProviderCatalog,q as classifyLoginFailure};
1
+ var R=Object.defineProperty;var m=(u,e)=>R(u,"name",{value:e,configurable:!0});import{LoginDialogComponent as D}from"@earendil-works/pi-coding-agent";import{Input as E,matchesKey as h,truncateToWidth as B}from"@earendil-works/pi-tui";import{execFile as N}from"node:child_process";import{dialogAuthInteraction as T}from"../../../core/auth-interaction.js";import{isProviderCredentialConfigured as F}from"../../../core/provider-credential.js";import{isManagedProvider as C,promoteSubscription as U,readSubscriptionPool as k,renameSubscription as _}from"../../../core/subscription-state.js";import{removeProviderRow as V}from"../../../core/provider-management.js";import{cliClient as j}from"../../api-client.js";import{loginProvider as q}from"../provider-login.js";import{fitTail as P,theme as s,visibleRange as M}from"../../../core/tui/panel.js";function S(u,e){const t=u.getProviders().filter(i=>i.auth.oauth!==void 0),n=new Set(t.map(i=>i.id)),o=new Set;return[...t.map(i=>({providerId:i.id,name:i.name,managed:C(i.id),authType:"oauth"})),...e.getAll().map(i=>({providerId:i.provider,name:e.getProviderDisplayName(i.provider),managed:C(i.provider),authType:n.has(i.provider)?"oauth":"api_key"}))].filter(i=>!o.has(i.providerId)&&!!o.add(i.providerId))}m(S,"buildProviderCatalog");function K(u,e){return e||u instanceof Error&&u.name==="AbortError"?"Login cancelled":`Login error: ${u instanceof Error?u.message:String(u)}`}m(K,"classifyLoginFailure");class te{static{m(this,"ProviderPanel")}tui;agentDir;runtime;registry;renameInput=new E;rows=[];selected=0;mode="list";notice="";catalog=[];catalogIndex=0;loginProvider;loginFlow;mutationInFlight=!1;onChange;constructor(e,t,n,o){this.tui=e,this.agentDir=t,this.runtime=n,this.registry=o,this.renameInput.onSubmit=()=>this.rename(),this.renameInput.onEscape=()=>{this.mode="list"},this.reload()}notifyChange(){this.onChange?.(),this.tui.requestRender()}reloadAfterAuthChange(){this.reload(),this.registry.refresh().then(()=>{this.reload(),this.notifyChange()})}reload(){const e=this.registry,t=[];for(const n of S(this.runtime,e)){const o=e.getProviderAuthStatus(n.providerId);if(n.managed){const i=k(n.providerId);if(i.length===0&&!o.source)continue;t.push({...n,configured:F(n.providerId,e),source:o.source,sourceLabel:o.label}),i.forEach((a,c)=>t.push({...n,label:a.label,preferred:c===0,cooldownUntil:a.rateLimitedUntil,accountId:a.accountId}));continue}o.source&&t.push({...n,configured:F(n.providerId,e),source:o.source,sourceLabel:o.label})}this.rows=t,this.selected=Math.min(this.selected,Math.max(0,t.length))}selectedRow(){return this.rows[this.selected]}openBrowser(e){const t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start","",e]:[e];N(t,n,{timeout:5e3},()=>{})}openCatalog(){this.catalog=S(this.runtime,this.registry),this.catalogIndex=0,this.mode="catalog"}startLogin(e,t){this.loginProvider=e;let n;const o=m(r=>{!n.active||this.loginFlow!==n||(n.active=!1,this.loginFlow=void 0,this.mode="list",this.notice=r,this.reloadAfterAuthChange(),this.notifyChange())},"complete"),i=new D(this.tui,e.providerId,(r,p)=>{r||o(p?`Login failed: ${p}`:"Login cancelled")},e.name);n={dialog:i,active:!0,committing:!1},this.loginFlow=n,this.mode="login";const a=i.handleInput.bind(i);i.handleInput=r=>{n.committing||a(r)};const c=m(()=>n.active&&this.loginFlow===n&&!i.signal.aborted,"isActive"),d=m(()=>c()?(n.committing=!0,i.showDetails(["Saving credentials\u2026"]),!0):!1,"beginCommit"),g=m(r=>{o(K(r,i.signal.aborted))},"fail");if(e.authType==="api_key"){i.showPrompt(`Enter API key for ${e.name}:`,"sk-...").then(async r=>{if(c()){if(!r.trim()){o("No key entered \u2014 login cancelled");return}d()&&(await j().installCredential(e.providerId,{kind:"api_key",api_key:r.trim()}),o(`API key saved for ${e.name}`))}}).catch(g);return}const y=T(i,{openBrowser:m(r=>this.openBrowser(r),"openBrowser"),onChange:m(()=>this.notifyChange(),"onChange"),isActive:c});q(this.runtime,e.providerId,y,{label:t,beforeInstall:d}).then(r=>{r&&c()&&o(`Logged in to ${e.name}`)}).catch(g)}isNestedFlowActive(){return this.mode==="login"}dispose(){const e=this.loginFlow;e&&(e.active=!1,this.loginFlow=void 0,e.dialog.handleInput("\x1B"))}runMutation(e){this.mutationInFlight||(this.mutationInFlight=!0,e().catch(t=>{this.notice=t instanceof Error?t.message:String(t)}).finally(()=>{this.mutationInFlight=!1,this.notifyChange()}))}suggestedAccountLabel(e){const t=new Set((C(e)?k(e):[]).map(o=>o.label.toLowerCase()));if(!t.has("default"))return"default";let n=2;for(;t.has(`account-${n}`);)n+=1;return`account-${n}`}rename(){const e=this.selectedRow();!e?.managed||!e.label||(this.mode="list",this.runMutation(async()=>{await _(e.providerId,e.label,this.renameInput.getValue()),this.notice=`Renamed ${e.name} account`,this.reload()}))}remove(e){this.runMutation(async()=>{this.notice=await V(this.agentDir,e),this.reloadAfterAuthChange()})}promote(e){this.runMutation(async()=>{await U(e.providerId,e.label),this.notice=`Preferred ${e.name} account`,this.reload()})}handleInput(e){if(this.mode==="login")return this.loginFlow?.dialog.handleInput(e),!0;if(this.mutationInFlight)return!0;if(this.mode==="rename"||this.mode==="label")return this.renameInput.handleInput(e),!0;if(this.mode==="catalog"){if(h(e,"escape"))return this.mode="list",!0;if(h(e,"j")||h(e,"down"))return this.catalogIndex=Math.min(this.catalog.length-1,this.catalogIndex+1),!0;if(h(e,"k")||h(e,"up"))return this.catalogIndex=Math.max(0,this.catalogIndex-1),!0;if(h(e,"enter")){const o=this.catalog[this.catalogIndex];if(o.managed){this.loginProvider=o;const i=this.suggestedAccountLabel(o.providerId);this.renameInput.setValue(i),this.renameInput.onSubmit=()=>{this.startLogin(o,this.renameInput.getValue().trim()||i)},this.mode="label"}else this.startLogin(o);return!0}return!0}if(this.mode==="remove"){if(h(e,"y")||h(e,"enter")){const o=this.selectedRow();o&&(o.managed||o.configured)&&this.remove(o)}return this.mode="list",!0}if(h(e,"j")||h(e,"down"))return this.selected=Math.min(this.rows.length,this.selected+1),!0;if(h(e,"k")||h(e,"up"))return this.selected=Math.max(0,this.selected-1),!0;const t=this.selectedRow();if(h(e,"p")&&t?.managed&&t.label)return this.promote(t),!0;if(h(e,"r")&&t?.managed&&t.label)return this.renameInput.setValue(t.label),this.renameInput.onSubmit=()=>this.rename(),this.mode="rename",!0;if(h(e,"x")&&(t?.managed||t?.configured))return this.mode="remove",!0;if(h(e,"a"))return this.openCatalog(),!0;const n=t?.source==="environment"||t?.source==="runtime";return h(e,"l")&&t&&!n?(t.managed&&t.label?this.startLogin(t,t.label):this.startLogin(t),!0):h(e,"enter")?(t&&!n?this.startLogin(t,t.managed&&t.label?t.label:void 0):t||this.openCatalog(),!0):!1}badge(){return String(this.rows.filter(e=>e.label===void 0).length)}render(e,t){const n=s.fg("accent",s.bold("Providers")),o=s.fg("dim",`${this.rows.filter(c=>c.label===void 0).length} configured`),i=Math.max(1,t);let a;if(this.mode==="login")a=P(this.loginFlow?.dialog.render(e)??[],i);else if(this.mode==="rename"||this.mode==="label")a=P([n,o,"",s.fg("accent",this.mode==="rename"?"Rename account":`Name the ${this.loginProvider?.name??"provider"} account`),...this.mode==="label"?[s.fg("dim","Names this credential \u2014 keep work and personal accounts on one provider apart")]:[],...this.renameInput.render(Math.max(1,e-8))],i);else if(this.mode==="remove"){const c=this.selectedRow(),d=c?.label??(c?.managed?`${c.name} \xB7 all accounts`:c?.name??"account");a=P([n,o,"",s.fg("warning",`Remove ${d}? y/enter confirm \xB7 any other key cancel`)],i)}else{const c=[n,o].slice(0,Math.max(0,i-1)),d=i-c.length;if(a=[...c],this.mode==="catalog"){const g=this.catalog.length,r=g>d&&d>=2,p=r?d-1:d,{start:I,end:v}=M(g,this.catalogIndex,p);let w=d-(v-I)-(r?1:0);w>0&&(a.push(s.fg("dim","Select a provider to add \xB7 esc back")),w-=1);for(let f=I;f<v;f++){const x=this.catalog[f];a.push(`${f===this.catalogIndex?s.fg("accent","\u25B6"):" "} ${x.name}`)}r&&a.push(s.fg("dim",`(${this.catalogIndex+1}/${g})`))}else{const g=this.rows.length+1,r=g>d&&d>=2,p=r?d-1:d,{start:I,end:v}=M(g,this.selected,p);let w=d-(v-I)-(r?1:0);const f=this.rows.length===0&&w>0;f&&(w-=1);const x=!!this.notice&&w>0;f&&a.push(s.fg("warning","No provider configured yet."));for(let b=I;b<v;b++){if(b===this.rows.length){a.push(`${this.selected===this.rows.length?s.fg("accent","\u25B6"):" "} ${s.fg("accent","\uFF0B Add provider")}`);continue}const l=this.rows[b],A=b===this.selected?s.fg("accent","\u25B6"):" ";if(l.label){const L=l.cooldownUntil&&l.cooldownUntil>Date.now()?`cooldown ${Math.ceil((l.cooldownUntil-Date.now())/6e4)}m`:"ready",$=l.accountId?` \xB7 ${l.accountId.length>12?`${l.accountId.slice(0,8)}\u2026${l.accountId.slice(-4)}`:l.accountId}`:"";a.push(`${A} ${l.preferred?s.fg("success","\u25CF"):" "} ${l.label}${s.fg("dim",$)} ${s.fg("dim",L)}${l.preferred?s.fg("accent"," preferred"):""}`)}else{const L=l.managed?`${this.rows.filter($=>$.providerId===l.providerId&&$.label).length} accounts`:l.source==="environment"||l.source==="runtime"?`${l.source}${l.sourceLabel?` \xB7 ${l.sourceLabel}`:""} (view only)`:"configured";a.push(`${A} ${s.fg("accent",l.name)}${s.fg("dim",` ${L}`)}`)}}r&&a.push(s.fg("dim",`(${this.selected+1}/${g})`)),x&&a.push(s.fg("dim",this.notice))}}return a.map(c=>B(c,e))}}export{te as ProviderPanel,S as buildProviderCatalog,K as classifyLoginFailure};
@@ -1,6 +1,9 @@
1
- var M=Object.defineProperty;var a=(e,t)=>M(e,"name",{value:t,configurable:!0});import{spawnSync as k}from"node:child_process";import{homedir as m}from"node:os";import{basename as j,dirname as F,join as w,resolve as G}from"node:path";import{isDeepStrictEqual as f}from"node:util";import{BINDING_CATALOG as B,normalizeGesture as U,splitGestureExpression as z,inboxShortcut as Y,resolveKeybindings as b}from"../../core/keybindings/index.js";import{builtinPiPackageDir as g}from"../../core/scope.js";import{readJsonIfExists as q,readJsonOrNull as H}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as V}from"../../core/runtime/pi-cli.js";import{crtrVersion as W}from"../../shared/crtr-version.js";import{installTmuxBindings as J}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as X}from"../../core/config.js";import{detectNerdFont as Q,nerdFontInstallCommand as Z,NERD_FONT_SELECT_HINT as ee}from"../../core/runtime/nerd-font.js";import{ensureRenderer as te,isRendererReady as S}from"../../core/termrender/termrender.js";import{installFromMarketplace as ne}from"../pkg/plugin-manage.js";import{addMarketplace as A}from"../pkg/market-manage.js";import{findPluginByName as re,findMarketplaceByName as C}from"../../core/resolver.js";import{expandTilde as ie}from"../../core/fs-utils.js";const R="crouter-official-marketplace",E="https://github.com/crouton-labs/crouter-official-marketplace.git",$="main";function D(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}a(D,"isKeybindingsObject");function d(e){return D(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}a(d,"cloneKeybindings");class Ne{static{a(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=d(t),this.current=d(t),this.baselineInvalidRoot=t!==void 0&&!D(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=X(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!f(this.current,this.baseline)||!f(this.invalidRoot,this.baselineInvalidRoot)||!f(this.currentPassthrough,this.baselinePassthrough)}overrides(){return d(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=b(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=B.find(u=>u.id===t);let i;try{i=n.trim()===""?[]:z(n).map(u=>U(u.trim(),r))}catch(u){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:u instanceof Error?u.message:String(u)}]}}const s=[...new Set(i)],o={...this.current};delete o[t];const p=[...b(o).gestures(t)],c=f(s,p)?o:{...this.current,[t]:s},l=b(c),h=l.diagnostics.filter(u=>u.bindingId===t||u.relatedBindingIds?.includes(t));return h.length>0?{ok:!1,diagnostics:h}:(this.current=c,this.resolutionCache=void 0,{ok:!0,diagnostics:l.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=d(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:d(t),this.baseline=d(t),this.current=d(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const se={"official-marketplace":{name:R,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.1.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"search-plugin":{name:"search",shortDescription:"crtr plugin mounting `crtr search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `search` plugin from the official crtr marketplace. It mounts `crtr search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."}},P={"official-marketplace":{kind:"marketplace-source",source:E},"crtr-extensions":{kind:"local-path",source:g("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.1.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/search"}},ae={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"search-plugin":[]};function x(e=g){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","search-plugin"].map(t=>{const n=se[t],r=P[t].kind==="local-path"?e(n.name):P[t].source;return{id:t,name:n.name,sourceKind:P[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}a(x,"buildSetupManifest");function _e(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}a(_e,"packagePlanAction");function oe(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}a(oe,"npmPackageName");function O(e,t,n){const r=oe(e);if(r!==null)return`npm:${r}`;const i=ie(e,n);return G(t,i)}a(O,"normalizePackageIdentity");function v(e){return`package:${e}`}a(v,"packageNameIdentity");function ce(e){return e.startsWith("npm:")?[]:[v(j(e))]}a(ce,"localPackageNameIdentities");function le(e,t,n){const r=[O(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(v(e.name));for(const i of ae[e.id])r.push(v(i))}return r}a(le,"manifestIdentities");function T(e,t=x(),n=w(m(),".pi","agent","settings.json"),r=m()){const i=F(n),s=new Set,o=new Map;for(const c of t)for(const l of le(c,i,r))o.set(l,c.id);const p=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(p))return s;for(const c of p){const l=typeof c=="string"?c:c&&typeof c=="object"&&typeof c.source=="string"?c.source:null;if(l===null)continue;const h=[O(l,i,r),...ce(l)];for(const u of h){const y=o.get(u);y!==void 0&&s.add(y)}}return s}a(T,"detectInstalledSetupPackageIds");function I(e){return k("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}a(I,"detectCommandOnPath");function ue(e=process.platform,t=I){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}a(ue,"detectPackageManager");function de(e,t,n=I){if(e==="nerd-font"?Q().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const s=Z(t);return{tool:e,installed:!1,command:s.command,hint:`${s.hint} \u2014 ${ee}`,autoInstall:s.autoInstall}}const i=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${i}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${i}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${i}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${i}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}a(de,"buildSystemInstallPlan");function N(e=m()){return w(e,".pi","agent","settings.json")}a(N,"resolveSettingsPath");function Ke(e={}){const t=e.homeDir??m(),n=e.settingsPath??N(t),r=e.manifest??x(g),i=q(n),s=T(i,r,n,t);for(const l of K(r))s.add(l);const o=e.commandExists??I,p=e.packageManager??ue(process.platform,o),c=["tmux","nvim","nerd-font"].map(l=>de(l,p,o));return{manifest:r,installedPackageIds:s,systemPlans:c}}a(Ke,"buildSetupInitialState");function Le(e){const t=e.manifest.map(r=>{const i=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${i})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${Y()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
1
+ var W=Object.defineProperty;var a=(e,t)=>W(e,"name",{value:t,configurable:!0});import{spawn as q,spawnSync as H}from"node:child_process";import{homedir as g}from"node:os";import{basename as V,dirname as J,join as S,resolve as X}from"node:path";import{isDeepStrictEqual as k}from"node:util";import{BINDING_CATALOG as Q,normalizeGesture as Z,splitGestureExpression as ee,inboxShortcut as te,resolveKeybindings as P}from"../../core/keybindings/index.js";import{builtinPiPackageDir as b}from"../../core/scope.js";import{readJsonIfExists as ne,readJsonOrNull as re}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as ie}from"../../core/runtime/pi-cli.js";import{crtrVersion as se}from"../../shared/crtr-version.js";import{installTmuxBindings as ae}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as oe}from"../../core/config.js";import{detectNerdFont as ce,nerdFontInstallCommand as ue,createCurlPercentReader as le,NERD_FONT_MANUAL_LINUX_COMMAND as de,NERD_FONT_SELECT_HINT as pe}from"../../core/runtime/nerd-font.js";import{startProgressBar as he}from"../../core/runtime/progress-bar.js";import{ensureRenderer as fe,isRendererReady as A}from"../../core/termrender/termrender.js";import{installFromMarketplace as me}from"../pkg/plugin-manage.js";import{addMarketplace as $}from"../pkg/market-manage.js";import{findPluginByName as ge,findMarketplaceByName as E}from"../../core/resolver.js";import{expandTilde as ke}from"../../core/fs-utils.js";const R="crouter-official-marketplace",D="https://github.com/crouton-labs/crouter-official-marketplace.git",O="main";function T(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}a(T,"isKeybindingsObject");function h(e){return T(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}a(h,"cloneKeybindings");class Je{static{a(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=h(t),this.current=h(t),this.baselineInvalidRoot=t!==void 0&&!T(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=oe(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!k(this.current,this.baseline)||!k(this.invalidRoot,this.baselineInvalidRoot)||!k(this.currentPassthrough,this.baselinePassthrough)}overrides(){return h(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=P(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=Q.find(p=>p.id===t);let o;try{o=n.trim()===""?[]:ee(n).map(p=>Z(p.trim(),r))}catch(p){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:p instanceof Error?p.message:String(p)}]}}const i=[...new Set(o)],u={...this.current};delete u[t];const c=[...P(u).gestures(t)],l=k(i,c)?u:{...this.current,[t]:i},s=P(l),d=s.diagnostics.filter(p=>p.bindingId===t||p.relatedBindingIds?.includes(t));return d.length>0?{ok:!1,diagnostics:d}:(this.current=l,this.resolutionCache=void 0,{ok:!0,diagnostics:s.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=h(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:h(t),this.baseline=h(t),this.current=h(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const be={"official-marketplace":{name:R,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.1.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"search-plugin":{name:"search",shortDescription:"crtr plugin mounting `crtr search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `search` plugin from the official crtr marketplace. It mounts `crtr search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."}},v={"official-marketplace":{kind:"marketplace-source",source:D},"crtr-extensions":{kind:"local-path",source:b("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.1.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/search"}},we={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"search-plugin":[]};function I(e=b){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","search-plugin"].map(t=>{const n=be[t],r=v[t].kind==="local-path"?e(n.name):v[t].source;return{id:t,name:n.name,sourceKind:v[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}a(I,"buildSetupManifest");function Xe(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}a(Xe,"packagePlanAction");function Pe(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}a(Pe,"npmPackageName");function N(e,t,n){const r=Pe(e);if(r!==null)return`npm:${r}`;const o=ke(e,n);return X(t,o)}a(N,"normalizePackageIdentity");function x(e){return`package:${e}`}a(x,"packageNameIdentity");function ve(e){return e.startsWith("npm:")?[]:[x(V(e))]}a(ve,"localPackageNameIdentities");function Ie(e,t,n){const r=[N(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(x(e.name));for(const o of we[e.id])r.push(x(o))}return r}a(Ie,"manifestIdentities");function L(e,t=I(),n=S(g(),".pi","agent","settings.json"),r=g()){const o=J(n),i=new Set,u=new Map;for(const l of t)for(const s of Ie(l,o,r))u.set(s,l.id);const c=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(c))return i;for(const l of c){const s=typeof l=="string"?l:l&&typeof l=="object"&&typeof l.source=="string"?l.source:null;if(s===null)continue;const d=[N(s,o,r),...ve(s)];for(const p of d){const f=u.get(p);f!==void 0&&i.add(f)}}return i}a(L,"detectInstalledSetupPackageIds");function m(e){return H("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}a(m,"detectCommandOnPath");function xe(e=process.platform,t=m){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}a(xe,"detectPackageManager");function ye(e,t,n=m){if(e==="nerd-font"?ce().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const i=ue(t);return{tool:e,installed:!1,command:i.command,hint:`${i.hint} \u2014 ${pe}`,autoInstall:i.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}a(ye,"buildSystemInstallPlan");function _(e=g()){return S(e,".pi","agent","settings.json")}a(_,"resolveSettingsPath");function Qe(e={}){const t=e.homeDir??g(),n=e.settingsPath??_(t),r=e.manifest??I(b),o=ne(n),i=L(o,r,n,t);for(const s of G(r))i.add(s);const u=e.commandExists??m,c=e.packageManager??xe(process.platform,u),l=["tmux","nvim","nerd-font"].map(s=>ye(s,c,u));return{manifest:r,installedPackageIds:i,systemPlans:l}}a(Qe,"buildSetupInitialState");function Ze(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${te()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
2
2
  `)+`
3
- `}a(Le,"renderSetupStaticInstructions");function pe(e){if(k("sh",["-lc",e],{stdio:"inherit"}).status!==0)throw new Error(`command failed: ${e}`)}a(pe,"runShellCommand");function he(e,t=!1,n=V()){if(k(process.execPath,[n,"install",e],{stdio:t?"pipe":"inherit"}).status!==0)throw new Error(`pi install failed: ${e}`)}a(he,"installPiPackage");function _(e,t){return S()?"current":(e?.(),te(t),S()?"provisioned":"unavailable")}a(_,"ensureManagedRenderer");async function me(){try{J()}catch{}}a(me,"reconcileInboxFrontDoor");function Me(e){return["crtr sys setup complete",e.installed.length>0?`installed: ${e.installed.join(", ")}`:"installed: none",e.skipped.length>0?`skipped: ${e.skipped.join(", ")}`:"skipped: none"].join(`
3
+ `}a(Ze,"renderSetupStaticInstructions");class w extends Error{static{a(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function et(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}a(et,"commandOutput");function M(e,t,n){return new Promise((r,o)=>{const i=q(e,t,{stdio:["ignore","pipe","pipe"]});let u="";i.stdout.setEncoding("utf8"),i.stderr.setEncoding("utf8"),i.stdout.on("data",c=>{u+=c}),i.stderr.on("data",c=>{u+=c,n?.(c)}),i.on("error",c=>o(new w(`${e} failed: ${c.message}`,u))),i.on("close",c=>{c===0?r():o(new w(`${e} failed with status ${c??"unknown"}`,u))})})}a(M,"runCapturedCommand");function y(e,t){return M("sh",["-lc",e],t)}a(y,"runShellCommand");function Ce(e,t=ie()){return M(process.execPath,[t,"install",e])}a(Ce,"installPiPackage");async function K(){m("capture")||await y("npm install -g @crouton-kit/capture")}a(K,"installCaptureCliIfMissing");function F(e){return e instanceof w?e.output:void 0}a(F,"capturedFailureOutput");function Se(e){const n=F(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}a(Se,"firstFailureLine");function Ae(e){const t=F(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
4
+ `)?t:`${t}
5
+ `)}a(Ae,"printCapturedFailure");class $e{static{a(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=he(`Installing ${t}\u2026`),this.bar):null}async clear(){await this.bar?.stop(),this.bar=null}async succeed(t){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2713 ${t}
6
+ `)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${Se(n)}
7
+ `),Ae(n)}async run(t,n){const r=this.start(t);try{const o=await n(r);return await this.succeed(t),o}catch(o){throw await this.fail(t,o),o}}}function j(e,t){return A()?"current":(e?.(),fe(t),A()?"provisioned":"unavailable")}a(j,"ensureManagedRenderer");async function Ee(){try{ae()}catch{}}a(Ee,"reconcileInboxFrontDoor");function B(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}a(B,"summarySection");function tt(e){return["crtr sys setup complete",...B("installed",e.installed),...B("skipped",e.skipped)].join(`
4
8
  `)+`
5
- `}a(Me,"formatSetupExecutionSummary");function K(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?C(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&re(r.name,t)!==null&&n.push(r.id)}catch{}return n}a(K,"detectInstalledMarketplaceEntries");function fe(e,t="user"){if(C(e,t)!==null)return null;if(e!==R)throw new Error(`marketplace not registered: ${e}`);return A({url:E,ref:$,scope:t}),e}a(fe,"ensureMarketplaceRegistered");async function L(e,t=!1){if(e.sourceKind==="marketplace-source")return A({url:e.installSource,ref:$,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[n,r]=e.installSource.split("/"),i=fe(n);return await ne({marketplace:n,plugin:r},"user"),i===null?[e.name]:[i,e.name]}return he(e.installSource,t),[e.name]}a(L,"installSetupPackage");async function je(e){const t=x(g),n=T(H(N()),t);for(const i of K(t,"user"))n.add(i);const r=new Map(t.map(i=>[i.id,i]));for(const i of["crtr-extensions","official-marketplace","capture-plugin","search-plugin"]){const s=r.get(i);if(!n.has(i))try{await L(s,!0)}catch(o){e(s.name,o)}}try{_(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(i){e("termrender renderer",i)}return W()}a(je,"reconcileFirstRun");async function Fe(e){const t=[],n=[],r=[],i=[];for(const s of e.packages){if(e.installedPackageIds.has(s.id)){n.push(`${s.name} (already installed)`);continue}try{t.push(...await L(s))}catch(o){if(s.sourceKind!=="marketplace-source"&&s.sourceKind!=="marketplace-plugin")throw o;n.push(`${s.name} (${o instanceof Error?o.message:String(o)})`)}}for(const s of e.systemDeps){if(s.installed){i.push(`${s.tool} (already installed)`);continue}if(!s.autoInstall||!s.command){i.push(`${s.tool} (${s.hint})`);continue}pe(s.command),r.push(s.tool)}switch(_(()=>process.stdout.write(`Provisioning the pinned termrender renderer\u2026
6
- `))){case"provisioned":t.push("termrender renderer");break;case"current":n.push("termrender renderer (current)");break;case"unavailable":n.push("termrender renderer (unavailable \u2014 install uv)");break}return await me(),{installed:[...t,...r],skipped:[...n,...i]}}a(Fe,"executeSetupSubmission");export{R as OFFICIAL_MARKETPLACE_NAME,$ as OFFICIAL_MARKETPLACE_REF,E as OFFICIAL_MARKETPLACE_URL,Ne as SetupKeybindingsDraft,Ke as buildSetupInitialState,x as buildSetupManifest,de as buildSystemInstallPlan,I as detectCommandOnPath,T as detectInstalledSetupPackageIds,ue as detectPackageManager,Fe as executeSetupSubmission,Me as formatSetupExecutionSummary,O as normalizePackageIdentity,_e as packagePlanAction,je as reconcileFirstRun,me as reconcileInboxFrontDoor,Le as renderSetupStaticInstructions,N as resolveSettingsPath};
9
+ `}a(tt,"formatSetupExecutionSummary");function G(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?E(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&ge(r.name,t)!==null&&n.push(r.id)}catch{}return n}a(G,"detectInstalledMarketplaceEntries");function Re(e,t="user"){if(E(e,t)!==null)return null;if(e!==R)throw new Error(`marketplace not registered: ${e}`);return $({url:D,ref:O,scope:t}),e}a(Re,"ensureMarketplaceRegistered");async function U(e){if(e.sourceKind==="marketplace-source")return $({url:e.installSource,ref:O,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=Re(t);return await me({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await K(),r===null?[e.name]:[r,e.name]}return await Ce(e.installSource),[e.name]}a(U,"installSetupPackage");async function nt(e){const t=I(b),n=L(re(_()),t);for(const i of G(t,"user"))n.add(i);const r=new Map(t.map(i=>[i.id,i])),o=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","search-plugin"];for(const i of o){const u=r.get(i);if(!n.has(i))try{await U(u)}catch(c){e(u.name,c)}}try{j(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(i){e("termrender renderer",i)}return se()}a(nt,"reconcileFirstRun");async function rt(e){const t=[],n=[],r=[],o=[],i=new $e;for(const s of e.packages){if(e.installedPackageIds.has(s.id)){if(n.push(`${s.name} (already installed)`),s.id==="capture-plugin"&&!m("capture"))try{await i.run("Capture CLI",()=>K()),t.push("Capture CLI")}catch(d){n.push(`Capture CLI (${d instanceof Error?d.message:String(d)})`)}continue}try{t.push(...await i.run(s.name,()=>U(s)))}catch(d){if(s.sourceKind!=="marketplace-source"&&s.sourceKind!=="marketplace-plugin")throw d;n.push(`${s.name} (${d instanceof Error?d.message:String(d)})`)}}for(const s of e.systemDeps){if(s.installed){o.push(`${s.tool} (already installed)`);continue}if(!s.autoInstall||!s.command){o.push(`${s.tool} (${s.hint})`);continue}const d=s.command,p=d===de;await i.run(s.tool,f=>{if(!p||f===null)return y(d);const Y=le();return y(d,z=>{const C=Y(z);C!==null&&f.setFraction(C/100)})}),r.push(s.tool)}const u=[];let c=!1,l;try{l=j(()=>{c=!0,i.start("termrender renderer")},s=>u.push(s))}catch(s){throw c&&await i.fail("termrender renderer",s),s}switch(l){case"provisioned":c&&await i.succeed("termrender renderer"),t.push("termrender renderer");break;case"current":n.push("termrender renderer (current)");break;case"unavailable":{const s=new w("unavailable \u2014 install uv",u.join(""));c&&await i.fail("termrender renderer",s),n.push("termrender renderer (unavailable \u2014 install uv)");break}}return await Ee(),{installed:[...t,...r],skipped:[...n,...o]}}a(rt,"executeSetupSubmission");export{R as OFFICIAL_MARKETPLACE_NAME,O as OFFICIAL_MARKETPLACE_REF,D as OFFICIAL_MARKETPLACE_URL,Je as SetupKeybindingsDraft,Qe as buildSetupInitialState,I as buildSetupManifest,ye as buildSystemInstallPlan,m as detectCommandOnPath,L as detectInstalledSetupPackageIds,xe as detectPackageManager,rt as executeSetupSubmission,tt as formatSetupExecutionSummary,N as normalizePackageIdentity,Xe as packagePlanAction,nt as reconcileFirstRun,Ee as reconcileInboxFrontDoor,Ze as renderSetupStaticInstructions,_ as resolveSettingsPath};
@@ -45,4 +45,4 @@ export declare class SetupWizard implements Component, Focusable {
45
45
  private renderConfirm;
46
46
  render(width: number): string[];
47
47
  }
48
- export declare function runSetup(): Promise<void>;
48
+ export declare function runSetup(): Promise<'completed' | 'skipped'>;
@@ -1 +1 @@
1
- var $=Object.defineProperty;var d=(o,e)=>$(o,"name",{value:e,configurable:!0});import{matchesKey as g,truncateToWidth as a,visibleWidth as m}from"@earendil-works/pi-tui";import{formatGesture as b,matchesPiTuiInput as v}from"../../core/keybindings/index.js";import{buildSetupInitialState as S,executeSetupSubmission as P,formatSetupExecutionSummary as k,packagePlanAction as I,reconcileInboxFrontDoor as y,renderSetupStaticInstructions as x}from"./setup-core.js";import{runSetupSettingsProcess as C}from"./setup-settings-runner.js";import{DependenciesPanel as w}from"./panels/dependencies-panel.js";import{PAGE_CHROME_ROWS as D,pageFrame as L,theme as n}from"../../core/tui/panel.js";import{PluginsPanel as W}from"./panels/plugins-panel.js";import{ProviderPanel as T}from"./panels/provider-panel.js";const u=["Providers","Plugins","Dependencies"];class A{static{d(this,"SetupWizard")}bindings;terminalRows;providers;plugins;dependencies;step=0;confirming=!1;cachedWidth;cachedHeight;cachedLines;_focused=!1;installedPackageIds;onSubmit;onCancel;constructor(e,i,t,s,r,c,p,l,f){this.bindings=l,this.terminalRows=f,this.installedPackageIds=i;const h=d(()=>this.invalidate(),"invalidate");this.providers=new T(s,r,c,p),this.providers.onChange=h,this.plugins=new W(e,i,h),this.dependencies=new w(t,h)}set focused(e){this._focused=e}get focused(){return this._focused}invalidate(){this.cachedWidth=void 0,this.cachedHeight=void 0,this.cachedLines=void 0}matches(e,i){return v(this.bindings,e,i,(t,s)=>g(t,s))}label(e){const i=this.bindings.gestures(e);return i.length===0?"disabled":b(i[0].split(" > ").pop())}fieldSafeLabel(e){const i=this.bindings.gestures(e).filter(t=>{if(t.includes(" > "))return!0;const s=t.split("+").pop();return!(s==="up"||s==="down"||s==="left"||s==="right")&&(s.length>1||t.includes("+"))});return i.length===0?"Disabled":i.map(b).join(" / ")}setStep(e){this.step=e,this.invalidate()}moveStep(e){this.setStep((this.step+e+u.length)%u.length)}advance(){this.step===2?this.finalize():this.moveStep(1)}cancel(){if(this.confirming){this.confirming=!1,this.invalidate();return}this.onCancel?.()}dispose(){this.providers.dispose()}hasPendingInstalls(){return this.plugins.selected.some(e=>!this.installedPackageIds.has(e.id))||this.dependencies.selected.length>0}buildSubmission(){return{packages:[...this.plugins.selected],installedPackageIds:new Set(this.installedPackageIds),systemDeps:[...this.dependencies.selected]}}finalize(){if(this.confirming||!this.hasPendingInstalls()){this.onSubmit?.(this.buildSubmission());return}this.confirming=!0,this.invalidate()}currentPanel(){return this.step===0?this.providers:this.step===1?this.plugins:this.dependencies}handleInput(e){const i=this.currentPanel(),t=d((r,c)=>this.matches(r,c),"match");if(this.step===0&&this.providers.isNestedFlowActive()){i.handleInput(e,t)&&this.invalidate();return}if(this.confirming){this.matches("crtr.setup.confirm.accept",e)?this.onSubmit?.(this.buildSubmission()):this.matches("crtr.setup.confirm.back",e)&&(this.confirming=!1,this.invalidate());return}if(this.matches("crtr.setup.cancel",e)){this.cancel();return}if(this.matches("crtr.setup.tab-next",e)){this.moveStep(1);return}if(this.matches("crtr.setup.tab-previous",e)){this.moveStep(-1);return}if(i.handleInput(e,t)){this.invalidate();return}this.matches("crtr.setup.advance",e)&&this.advance()}renderTrail(e){const t=u.map((s,r)=>{if(r===this.step)return n.bg("selectedBg",` ${r+1} ${s} `);const c=r<this.step?n.fg("success","\u2713"):`${r+1}`;return n.fg("dim",` ${c} ${s} `)}).join(n.fg("dim","\u203A"));return m(t)<=e?[a(t,e),""]:[a(`${n.fg("dim",`Step ${this.step+1} of ${u.length}`)} ${n.fg("accent",n.bold(u[this.step]))}`,e),""]}footer(e){const i=`${this.fieldSafeLabel("crtr.setup.tab-next")}/${this.fieldSafeLabel("crtr.setup.tab-previous")} step \xB7 ${this.label("crtr.setup.cancel")} cancel`,t=`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")}`;let s;this.confirming?s=`${this.label("crtr.setup.confirm.accept")} confirm \xB7 ${this.label("crtr.setup.confirm.back")} go back`:this.step===0?s=this.providers.isNestedFlowActive()?"OAuth in progress \xB7 esc cancel":`${t} select \xB7 a add \xB7 p prefer \xB7 r rename \xB7 l re-login \xB7 x remove \xB7 ${this.label("crtr.setup.advance")} next`:this.step===1?s=`${t} move \xB7 ${this.label("crtr.setup.toggle")} toggle \xB7 ${this.label("crtr.setup.details")} details \xB7 ${this.label("crtr.setup.advance")} next`:s=`${t} move \xB7 ${this.label("crtr.setup.toggle")} toggle \xB7 ${this.label("crtr.setup.advance")} finish`;const r=e-m(s)-m(i);return r>=2?`${n.fg("dim",s)}${" ".repeat(r)}${n.fg("dim",i)}`:n.fg("dim",s)}renderConfirm(e){const i=this.buildSubmission(),t=[a(n.fg("warning",n.bold("Confirm installs")),e),""];if(i.packages.length===0&&i.systemDeps.length===0)return[...t,a(n.fg("success",`Nothing to install; ${this.label("crtr.setup.confirm.accept")} finish.`),e)];if(i.packages.length){t.push(a(n.fg("accent","Packages"),e));for(const s of i.packages)t.push(a(` \u2022 ${s.name} ${n.fg("dim","\u2192")} ${this.installedPackageIds.has(s.id)?n.fg("success","skip (already installed)"):n.fg("muted",I(s))}`,e))}if(i.systemDeps.length){t.push(a(n.fg("accent","System deps"),e));for(const s of i.systemDeps)t.push(a(` \u2022 ${s.tool} ${n.fg("dim","\u2192")} ${n.fg("muted",s.command??s.hint)}`,e))}return t}render(e){const i=this.step===0,t=this.terminalRows();if(!i&&this.cachedLines&&this.cachedWidth===e&&this.cachedHeight===t)return this.cachedLines;const s=this.currentPanel(),r=Math.max(1,t-D),c=this.confirming||r<=2?[]:this.renderTrail(e),p=Math.max(1,r-c.length),l=L({width:e,height:t,title:"crouter setup",meta:this.confirming?"review":`step ${this.step+1} of ${u.length}`,body:[...c,...this.confirming?this.renderConfirm(e):s.render(e,p)],footer:this.footer(e)});return i||(this.cachedWidth=e,this.cachedHeight=t,this.cachedLines=l),l}}async function j(){const o=S();if(await y(),!process.stdout.isTTY){process.stdout.write(x(o));return}const e=await C(({tui:t,terminal:s,agentDir:r,runtime:c,registry:p,bindings:l},f)=>{const h=new A(o.manifest,o.installedPackageIds,o.systemPlans,t,r,c,p,l,()=>s.rows);return h.onCancel=f.cancel,h.onSubmit=f.submit,h},(t,s)=>t.length>0&&t.charCodeAt(0)<32&&v(s,"crtr.setup.cancel",t,(r,c)=>g(r,c)));if(e===void 0)return;const i=await P(e);process.stdout.write(k(i))}d(j,"runSetup");export{A as SetupWizard,j as runSetup};
1
+ var S=Object.defineProperty;var p=(o,e)=>S(o,"name",{value:e,configurable:!0});import{matchesKey as b,truncateToWidth as a,visibleWidth as g}from"@earendil-works/pi-tui";import{formatGesture as v,matchesPiTuiInput as $}from"../../core/keybindings/index.js";import{buildSetupInitialState as P,executeSetupSubmission as k,formatSetupExecutionSummary as I,packagePlanAction as y,reconcileInboxFrontDoor as w,renderSetupStaticInstructions as x}from"./setup-core.js";import{runSetupSettingsProcess as C}from"./setup-settings-runner.js";import{DependenciesPanel as W}from"./panels/dependencies-panel.js";import{PAGE_CHROME_ROWS as D,pageFrame as L,theme as n}from"../../core/tui/panel.js";import{PluginsPanel as A}from"./panels/plugins-panel.js";import{ProviderPanel as H}from"./panels/provider-panel.js";const d=["Providers","Plugins","Dependencies"];class T{static{p(this,"SetupWizard")}bindings;terminalRows;providers;plugins;dependencies;step=0;confirming=!1;cachedWidth;cachedHeight;cachedLines;_focused=!1;installedPackageIds;onSubmit;onCancel;constructor(e,i,s,t,r,c,l,u,f){this.bindings=u,this.terminalRows=f,this.installedPackageIds=i;const h=p(()=>this.invalidate(),"invalidate");this.providers=new H(t,r,c,l),this.providers.onChange=h,this.plugins=new A(e,i,h),this.dependencies=new W(s,h)}set focused(e){this._focused=e}get focused(){return this._focused}invalidate(){this.cachedWidth=void 0,this.cachedHeight=void 0,this.cachedLines=void 0}matches(e,i){return $(this.bindings,e,i,(s,t)=>b(s,t))}label(e){const i=this.bindings.gestures(e);return i.length===0?"disabled":v(i[0].split(" > ").pop())}fieldSafeLabel(e){const i=this.bindings.gestures(e).filter(s=>{if(s.includes(" > "))return!0;const t=s.split("+").pop();return!(t==="up"||t==="down"||t==="left"||t==="right")&&(t.length>1||s.includes("+"))});return i.length===0?"Disabled":i.map(v).join(" / ")}setStep(e){this.step=e,this.invalidate()}moveStep(e){this.setStep((this.step+e+d.length)%d.length)}advance(){this.step===2?this.finalize():this.moveStep(1)}cancel(){if(this.confirming){this.confirming=!1,this.invalidate();return}this.onCancel?.()}dispose(){this.providers.dispose()}hasPendingInstalls(){return this.plugins.selected.some(e=>!this.installedPackageIds.has(e.id))||this.dependencies.selected.length>0}buildSubmission(){return{packages:[...this.plugins.selected],installedPackageIds:new Set(this.installedPackageIds),systemDeps:[...this.dependencies.selected]}}finalize(){if(this.confirming||!this.hasPendingInstalls()){this.onSubmit?.(this.buildSubmission());return}this.confirming=!0,this.invalidate()}currentPanel(){return this.step===0?this.providers:this.step===1?this.plugins:this.dependencies}handleInput(e){const i=this.currentPanel(),s=p((r,c)=>this.matches(r,c),"match");if(this.step===0&&this.providers.isNestedFlowActive()){i.handleInput(e,s)&&this.invalidate();return}if(this.confirming){this.matches("crtr.setup.confirm.accept",e)?this.onSubmit?.(this.buildSubmission()):this.matches("crtr.setup.confirm.back",e)&&(this.confirming=!1,this.invalidate());return}if(this.matches("crtr.setup.cancel",e)){this.cancel();return}if(this.matches("crtr.setup.tab-next",e)){this.moveStep(1);return}if(this.matches("crtr.setup.tab-previous",e)){this.moveStep(-1);return}if(i.handleInput(e,s)){this.invalidate();return}this.matches("crtr.setup.advance",e)&&this.advance()}renderTrail(e){const s=d.map((t,r)=>{if(r===this.step)return n.bg("selectedBg",` ${r+1} ${t} `);const c=r<this.step?n.fg("success","\u2713"):`${r+1}`;return n.fg("dim",` ${c} ${t} `)}).join(n.fg("dim","\u203A"));return g(s)<=e?[a(s,e),""]:[a(`${n.fg("dim",`Step ${this.step+1} of ${d.length}`)} ${n.fg("accent",n.bold(d[this.step]))}`,e),""]}footer(e){const i=`${this.fieldSafeLabel("crtr.setup.tab-next")}/${this.fieldSafeLabel("crtr.setup.tab-previous")} step \xB7 ${this.label("crtr.setup.cancel")} cancel`,s=`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")}`;let t;this.confirming?t=`${this.label("crtr.setup.confirm.accept")} confirm \xB7 ${this.label("crtr.setup.confirm.back")} go back`:this.step===0?t=this.providers.isNestedFlowActive()?"OAuth in progress \xB7 esc cancel":`${s} select \xB7 a add \xB7 p prefer \xB7 r rename \xB7 l re-login \xB7 x remove \xB7 ${this.label("crtr.setup.advance")} next`:this.step===1?t=`${s} move \xB7 ${this.label("crtr.setup.toggle")} toggle \xB7 ${this.label("crtr.setup.details")} details \xB7 ${this.label("crtr.setup.advance")} next`:t=`${s} move \xB7 ${this.label("crtr.setup.toggle")} toggle \xB7 ${this.label("crtr.setup.advance")} finish`;const r=e-g(t)-g(i);return r>=2?`${n.fg("dim",t)}${" ".repeat(r)}${n.fg("dim",i)}`:n.fg("dim",t)}renderConfirm(e){const i=this.buildSubmission(),s=[a(n.fg("warning",n.bold("Confirm installs")),e),""];if(i.packages.length===0&&i.systemDeps.length===0)return[...s,a(n.fg("success",`Nothing to install; ${this.label("crtr.setup.confirm.accept")} finish.`),e)];if(i.packages.length){s.push(a(n.fg("accent","Packages"),e));for(const t of i.packages)s.push(a(` \u2022 ${t.name} ${n.fg("dim","\u2192")} ${this.installedPackageIds.has(t.id)?n.fg("success","skip (already installed)"):n.fg("muted",y(t))}`,e))}if(i.systemDeps.length){s.push(a(n.fg("accent","System deps"),e));for(const t of i.systemDeps)s.push(a(` \u2022 ${t.tool} ${n.fg("dim","\u2192")} ${n.fg("muted",t.command??t.hint)}`,e))}return s}render(e){const i=this.step===0,s=this.terminalRows();if(!i&&this.cachedLines&&this.cachedWidth===e&&this.cachedHeight===s)return this.cachedLines;const t=this.currentPanel(),r=Math.max(1,s-D),c=this.confirming||r<=2?[]:this.renderTrail(e),l=Math.max(1,r-c.length),u=L({width:e,height:s,title:"crouter setup",meta:this.confirming?"review":`step ${this.step+1} of ${d.length}`,body:[...c,...this.confirming?this.renderConfirm(e):t.render(e,l)],footer:this.footer(e)});return i||(this.cachedWidth=e,this.cachedHeight=s,this.cachedLines=u),u}}function E(){process.stdout.write("\x1B[2J\x1B[H")}p(E,"clearWizardFrame");async function B(){const o=P();let e=!1;if(await w(),!process.stdout.isTTY)return process.stdout.write(x(o)),"skipped";const i=await C(({tui:t,terminal:r,agentDir:c,runtime:l,registry:u,bindings:f},h)=>{const m=new T(o.manifest,o.installedPackageIds,o.systemPlans,t,c,l,u,f,()=>r.rows);return m.onCancel=h.cancel,m.onSubmit=h.submit,m},(t,r)=>t===""?(e=!0,!0):t.length>0&&t.charCodeAt(0)<32&&$(r,"crtr.setup.cancel",t,(c,l)=>b(c,l)));if(E(),e){const t=new Error("Interrupted");throw t.name="AbortError",t}if(i===void 0)return"skipped";const s=await k(i);return process.stdout.write(I(s)),"completed"}p(B,"runSetup");export{T as SetupWizard,B as runSetup};
@@ -92,6 +92,30 @@ export declare function listNodesByProfile(profileId: string): NodeMeta[];
92
92
  /** All rows, optionally filtered by status and terminal execution traces. Unclaimed warm spares are excluded. */
93
93
  /** Every node's durable memory-resolution coordinates, including unclaimed warm-pool spares. */
94
94
  export declare function listNodeMemoryTargets(): NodeMemoryTarget[];
95
+ export declare function updateNodeTelemetry(nodeId: string, telemetry: {
96
+ tokensIn: number;
97
+ contextTokens: number | null;
98
+ lastActivity: string | null;
99
+ updatedAt: string;
100
+ }): void;
101
+ export interface GraphNodeRow {
102
+ node_id: string;
103
+ name: string;
104
+ description: string | null;
105
+ cycles: number | null;
106
+ kind: string;
107
+ status: NodeStatus;
108
+ frozen_at: string | null;
109
+ pi_pid: number | null;
110
+ telemetry_context_tokens: number | null;
111
+ telemetry_last_activity: string | null;
112
+ fault: NodeRow['fault'];
113
+ streaming: boolean;
114
+ }
115
+ /** Stored fields the attach graph displays, plus the two live execution cues it
116
+ * needs. This keeps the interactive graph off the full node-summary projection
117
+ * and its unused runtime, outcome, and placement fields. */
118
+ export declare function graphNodes(): GraphNodeRow[];
95
119
  export declare function listNodes(filter?: {
96
120
  status?: NodeStatus | NodeStatus[];
97
121
  withRecordedPid?: boolean;
@@ -1,29 +1,43 @@
1
- var k=Object.defineProperty;var o=(e,n)=>k(e,"name",{value:n,configurable:!0});import{envNodeId as O}from"../../shared/env.js";import{existsSync as F,realpathSync as H,rmSync as R,statSync as j}from"node:fs";import{join as I,resolve as U}from"node:path";import{openDb as s,withCanvasWrite as p}from"./db.js";import{activateArmedExternalActionDelivery as M,armExternalActionDelivery as P}from"./deliveries.js";import{findNodeBySessionFileSql as C}from"./sessions.js";import{hydrateFault as $}from"./recovery.js";import{hasUnreconciledWorktree as B,openWorktree as z,readWorktree as J,worktreeFromRow as Y}from"./worktrees.js";import{isPidAlive as h,recordedPidLiveness as q}from"./pid.js";import{ensureHome as V,ensureNodeDirs as G,jobDir as K,nodeDir as S}from"./paths.js";function f(e,n){if(e==null)return null;const t=JSON.stringify(e);if(t===void 0)throw new TypeError(`${n} must be JSON-serializable`);return t}o(f,"jsonValue");function y(e,n,t){P(e,{destinationId:t.actionName,adapter:{adapter:"subprocess",argv:t.argv,cwd:t.cwd,config_origin:t.configOrigin,payload:t.payload??null},idempotencyKey:`node-outcome:${n}`})}o(y,"insertArmedOutcomeDelivery");function Q(e,n){n.prepare('INSERT INTO nodes (node_id, name, description, title, icon, cycles, kind, mode, lifecycle, cwd, host_kind, profile_id, parent, spawned_by, creator, fork_from, fork_source_file, created, passive_default, cycle_pending, model_override, persona_ack_json, review_binding_json, launch_config_json, status, intent, waiting_for, final_report, finalized_at, deadline_at, "window", tmux_session, pane) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').run(e.node_id,e.name,e.description??null,e.title??null,e.icon??null,e.cycles??null,e.kind,e.mode,e.lifecycle,e.cwd,e.host_kind??null,e.profile_id??null,e.parent??null,e.spawned_by??null,e.creator??null,e.fork_from??null,e.fork_source_file??null,e.created,e.passive_default===!0?1:0,e.cycle_pending===!0?1:0,e.model_override??null,f(e.persona_ack,"persona_ack"),f(e.review_binding,"review_binding"),f(e.launch,"launch"),e.status??"active",e.intent??null,e.waiting_for??null,e.final_report??null,e.finalized_at??null,e.deadline_at??null,e.window??null,e.tmux_session??null,e.pane??null)}o(Q,"seedRow");function X(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,r])=>[t==="fault_id"?t:t.slice(6),r]);return $(Object.fromEntries(n))}o(X,"faultFrom");function _(e){const n={node_id:e.node_id,name:e.name,description:e.description??void 0,cycles:e.cycles??void 0,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,parent:e.parent??null,created:e.created,intent:e.intent??null,waiting_for:e.waiting_for??null,frozen_at:e.frozen_at??null,respawn_failures:e.respawn_failures??0,respawn_not_before:e.respawn_not_before??null,launched_at:e.launched_at??null,last_settled_at:e.last_settled_at??null,terminal_reason:e.terminal_reason??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,outcome_kind:e.outcome_kind??null,outcome_reason:e.outcome_reason??null,outcome_at:e.outcome_at??null,outcome_revision:e.outcome_revision??0,outcome_detail_json:e.outcome_detail_json??null,deadline_at:e.deadline_at??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,fault:null,streaming:!1},t=n.pi_pid===null?!1:h(n.pi_pid),r=X(e);return n.fault=r?.link==="pi\u2192provider"&&r.retry.by==="daemon"&&r.retry.disposition==="auto"&&!t?null:r,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}o(_,"rowFrom");function T(e,n=J(e.node_id)){return{..._(e),title:e.title??void 0,icon:e.icon??void 0,spawned_by:e.spawned_by??null,creator:e.creator??null,fork_from:e.fork_from??null,fork_source_file:e.fork_source_file??null,passive_default:e.passive_default===1,cycle_pending:e.cycle_pending===1,model_override:e.model_override??null,persona_ack:e.persona_ack_json==null?void 0:JSON.parse(e.persona_ack_json),review_binding:e.review_binding_json==null?void 0:JSON.parse(e.review_binding_json),launch:e.launch_config_json==null?void 0:JSON.parse(e.launch_config_json),pi_session_id:e.pi_session_id??null,pi_session_file:e.pi_session_file??null,...n===null?{}:{managed_worktree:n}}}o(T,"metaFrom");function Ee(e,n={}){return V(),p(t=>{Q(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&z(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&y(t,e.node_id,n.outcomeDelivery)}),G(e.node_id),E(e.node_id)}o(Ee,"createNode");function E(e){const n=s().prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:T(n)}o(E,"getNode");function me(e){const n=U(e);return F(n)?H(n):n}o(me,"canonicalSessionFile");function we(e){const n=C(e);return n===null?null:E(n)}o(we,"findNodeBySessionFile");function Ne(e){const n=s().prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?_(n):null}o(Ne,"getRow");function Re(e){const n=s().prepare("SELECT * FROM node_rows WHERE pane = ?").get(e);return n?_(n):null}o(Re,"getRowByPane");function Se(e){return s().prepare(`SELECT * FROM node_rows
1
+ var F=Object.defineProperty;var o=(e,n)=>F(e,"name",{value:n,configurable:!0});import{envNodeId as O}from"../../shared/env.js";import{existsSync as H,realpathSync as j,rmSync as N,statSync as I}from"node:fs";import{join as U,resolve as M}from"node:path";import{openDb as d,withCanvasWrite as _}from"./db.js";import{activateArmedExternalActionDelivery as C,armExternalActionDelivery as P}from"./deliveries.js";import{findNodeBySessionFileSql as $}from"./sessions.js";import{hydrateFault as B}from"./recovery.js";import{hasUnreconciledWorktree as z,openWorktree as Y,readWorktree as J,worktreeFromRow as q}from"./worktrees.js";import{isPidAlive as y,recordedPidLiveness as V}from"./pid.js";import{ensureHome as G,ensureNodeDirs as K,jobDir as Q,nodeDir as S}from"./paths.js";function f(e,n){if(e==null)return null;const t=JSON.stringify(e);if(t===void 0)throw new TypeError(`${n} must be JSON-serializable`);return t}o(f,"jsonValue");function h(e,n,t){P(e,{destinationId:t.actionName,adapter:{adapter:"subprocess",argv:t.argv,cwd:t.cwd,config_origin:t.configOrigin,payload:t.payload??null},idempotencyKey:`node-outcome:${n}`})}o(h,"insertArmedOutcomeDelivery");function X(e,n){n.prepare('INSERT INTO nodes (node_id, name, description, title, icon, cycles, kind, mode, lifecycle, cwd, host_kind, profile_id, parent, spawned_by, creator, fork_from, fork_source_file, created, passive_default, cycle_pending, model_override, persona_ack_json, review_binding_json, launch_config_json, status, intent, waiting_for, final_report, finalized_at, deadline_at, "window", tmux_session, pane) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').run(e.node_id,e.name,e.description??null,e.title??null,e.icon??null,e.cycles??null,e.kind,e.mode,e.lifecycle,e.cwd,e.host_kind??null,e.profile_id??null,e.parent??null,e.spawned_by??null,e.creator??null,e.fork_from??null,e.fork_source_file??null,e.created,e.passive_default===!0?1:0,e.cycle_pending===!0?1:0,e.model_override??null,f(e.persona_ack,"persona_ack"),f(e.review_binding,"review_binding"),f(e.launch,"launch"),e.status??"active",e.intent??null,e.waiting_for??null,e.final_report??null,e.finalized_at??null,e.deadline_at??null,e.window??null,e.tmux_session??null,e.pane??null)}o(X,"seedRow");function T(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,r])=>[t==="fault_id"?t:t.slice(6),r]);return B(Object.fromEntries(n))}o(T,"faultFrom");function p(e){const n={node_id:e.node_id,name:e.name,description:e.description??void 0,cycles:e.cycles??void 0,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,parent:e.parent??null,created:e.created,intent:e.intent??null,waiting_for:e.waiting_for??null,frozen_at:e.frozen_at??null,respawn_failures:e.respawn_failures??0,respawn_not_before:e.respawn_not_before??null,launched_at:e.launched_at??null,last_settled_at:e.last_settled_at??null,terminal_reason:e.terminal_reason??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,outcome_kind:e.outcome_kind??null,outcome_reason:e.outcome_reason??null,outcome_at:e.outcome_at??null,outcome_revision:e.outcome_revision??0,outcome_detail_json:e.outcome_detail_json??null,deadline_at:e.deadline_at??null,telemetry_tokens_in:e.telemetry_tokens_in??null,telemetry_context_tokens:e.telemetry_context_tokens??null,telemetry_last_activity:e.telemetry_last_activity??null,telemetry_updated_at:e.telemetry_updated_at??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,fault:null,streaming:!1},t=n.pi_pid===null?!1:y(n.pi_pid),r=T(e);return n.fault=r?.link==="pi\u2192provider"&&r.retry.by==="daemon"&&r.retry.disposition==="auto"&&!t?null:r,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}o(p,"rowFrom");function D(e,n=J(e.node_id)){return{...p(e),title:e.title??void 0,icon:e.icon??void 0,spawned_by:e.spawned_by??null,creator:e.creator??null,fork_from:e.fork_from??null,fork_source_file:e.fork_source_file??null,passive_default:e.passive_default===1,cycle_pending:e.cycle_pending===1,model_override:e.model_override??null,persona_ack:e.persona_ack_json==null?void 0:JSON.parse(e.persona_ack_json),review_binding:e.review_binding_json==null?void 0:JSON.parse(e.review_binding_json),launch:e.launch_config_json==null?void 0:JSON.parse(e.launch_config_json),pi_session_id:e.pi_session_id??null,pi_session_file:e.pi_session_file??null,...n===null?{}:{managed_worktree:n}}}o(D,"metaFrom");function Ee(e,n={}){return G(),_(t=>{X(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&Y(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&h(t,e.node_id,n.outcomeDelivery)}),K(e.node_id),E(e.node_id)}o(Ee,"createNode");function E(e){const n=d().prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:D(n)}o(E,"getNode");function me(e){const n=M(e);return H(n)?j(n):n}o(me,"canonicalSessionFile");function we(e){const n=$(e);return n===null?null:E(n)}o(we,"findNodeBySessionFile");function Re(e){const n=d().prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?p(n):null}o(Re,"getRow");function Ne(e){const n=d().prepare("SELECT * FROM node_rows WHERE pane = ?").get(e);return n?p(n):null}o(Ne,"getRowByPane");function ye(e){return d().prepare(`SELECT * FROM node_rows
2
2
  WHERE deadline_at IS NOT NULL AND outcome_at IS NULL
3
3
  AND deadline_at <= ? AND status IN ('active','idle') AND kind != 'human'
4
- ORDER BY deadline_at, created, node_id`).all(e).map(_)}o(Se,"dueNodeDeadlines");function ge(e,n){return Number(s().prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e).changes)===1}o(ge,"setNodeDeadline");function Oe(e,n){return!Number.isFinite(n)||n<=0?0:p(t=>{const r=t.prepare(`SELECT node_id, deadline_at FROM nodes
5
- WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),i=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let d=0;for(const a of r){const u=Date.parse(a.deadline_at);Number.isNaN(u)||(d+=Number(i.run(new Date(u+n).toISOString(),a.node_id,a.deadline_at).changes))}return d})}o(Oe,"shiftProfileNodeDeadlines");function Z(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}o(Z,"sqlInput");function he(e,n){const t=[],r=o((d,a=d)=>{Object.prototype.hasOwnProperty.call(n,d)&&t.push([a,Z(n[d],d)])},"add");if(r("name"),r("description"),r("title"),r("icon"),r("cycles"),r("kind"),r("mode"),r("lifecycle"),r("cwd"),r("host_kind"),r("profile_id"),r("parent"),r("spawned_by"),r("creator"),r("fork_from"),r("fork_source_file"),r("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",f(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",f(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",f(n.launch,"launch")]),t.length===0){const d=E(e);if(d===null)throw new Error(`unknown node: ${e}`);return d}if(s().prepare(`UPDATE nodes SET ${t.map(([d])=>`${d} = ?`).join(", ")} WHERE node_id = ?`).run(...t.map(([,d])=>d),e).changes!==1)throw new Error(`unknown node: ${e}`);return E(e)}o(he,"updateNode");function ye(e,n){s().prepare("UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}o(ye,"setStatus");function Te(e,n){s().prepare("UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}o(Te,"setIntent");function De(e,n,t={}){if(t.outcome===void 0){const i=[],d=[];Object.prototype.hasOwnProperty.call(n,"status")&&(i.push("status = ?"),d.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(i.push("intent = ?"),d.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(i.push("terminal_reason = ?"),d.push(n.terminal_reason??null));const a=["node_id = ?"];d.push(e),t.fromStatuses!==void 0&&(a.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),d.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&a.push("final_report IS NULL");const u=s().prepare(`UPDATE nodes SET ${i.join(", ")} WHERE ${a.join(" AND ")}`).run(...d);return Number(u.changes)}const r=t.outcome;return p(i=>{const d=[],a=[];Object.prototype.hasOwnProperty.call(n,"status")&&(d.push("status = ?"),a.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(d.push("intent = ?"),a.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(d.push("terminal_reason = ?"),a.push(n.terminal_reason??null));const u=o((re,W)=>r.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${W} END`,"outcomeValue");d.push(`outcome_kind = ${u(r.kind,"outcome_kind")}`,`outcome_reason = ${u(r.reason,"outcome_reason")}`,`outcome_detail_json = ${u(r.detailJson,"outcome_detail_json")}`,`outcome_revision = ${r.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${u(r.at,"outcome_at")}`),a.push(r.kind,r.reason,r.detailJson,r.at);const c=["node_id = ?"];a.push(e),t.fromStatuses!==void 0&&(c.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),a.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&c.push("final_report IS NULL");const l=i.prepare(`UPDATE nodes SET ${d.join(", ")} WHERE ${c.join(" AND ")}`).run(...a);if(Number(l.changes)===0)return 0;const N=i.prepare("SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(r.supersede===!0||N.outcome_at===r.at)&&r.documentJson!==null&&r.documentJson!==void 0&&M(i,{idempotencyKey:`node-outcome:${e}`,label:e,bodyJson:r.documentJson,supersede:r.supersede===!0}),Number(l.changes)})}o(De,"transitionStatusIntent");function Le(e){return s().prepare("SELECT final_report FROM nodes WHERE node_id = ?").get(e)?.final_report??null}o(Le,"getFinalReport");function Ae(e,n){return s().prepare("UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n).changes>0}o(Ae,"clearFinalReportIfMatches");function be(e,n){s().prepare('UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}o(be,"setPresence");function ve(e,n){s().prepare("UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}o(ve,"recordLaunch");function xe(e,n){s().prepare("UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}o(xe,"recordSettledTurn");function We(e,n){s().prepare("UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}o(We,"setFrozen");function ke(e){s().prepare("UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}o(ke,"clearFrozen");function Fe(e,n){s().prepare("UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}o(Fe,"recordRespawnAttempt");const m="node_id NOT IN (SELECT node_id FROM warm_pool)",D=["state","cleanup_state","path","branch","repo_root","base_ref","base_sha","created_at","closed_at","next_attempt_at","attempts","quarantined","sweep_reason","sweep_detail","sweep_last_at","sweep_observed_json","abandoned_json","land_intent_json","disposal_json"];function ee(e){return e.worktree_state===null?null:Y(Object.fromEntries(D.map(n=>[n,e[`worktree_${n}`]])))}o(ee,"worktreeFromProjection");function He(e){const n=D.map(r=>`w.${r} AS worktree_${r}`).join(", ");return s().prepare(`SELECT n.*, ${n} FROM node_rows n LEFT JOIN worktrees w ON w.node_id = n.node_id WHERE n.profile_id = ? ORDER BY n.created`).all(e).map(r=>T(r,ee(r)))}o(He,"listNodesByProfile");function je(){return s().prepare("SELECT node_id, cwd, profile_id FROM nodes ORDER BY created").all().map(e=>{const n=e;return{nodeId:n.node_id,cwd:n.cwd,profileId:n.profile_id}})}o(je,"listNodeMemoryTargets");function ne(e){const n=[m],t=[];if(e?.status!==void 0){const i=Array.isArray(e.status)?e.status:[e.status];n.push(`status IN (${i.map(()=>"?").join(",")})`),t.push(...i)}return e?.withRecordedPid===!0&&n.push("pi_pid IS NOT NULL"),e?.withRecordedPidOrFrozen===!0&&n.push("(pi_pid IS NOT NULL OR frozen_at IS NOT NULL)"),s().prepare(`SELECT * FROM node_rows WHERE ${n.join(" AND ")} ORDER BY created`).all(...t).map(_)}o(ne,"listNodes");function Ie(){return s().prepare(`SELECT * FROM node_rows
4
+ ORDER BY deadline_at, created, node_id`).all(e).map(p)}o(ye,"dueNodeDeadlines");function Se(e,n){return Number(d().prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e).changes)===1}o(Se,"setNodeDeadline");function ge(e,n){return!Number.isFinite(n)||n<=0?0:_(t=>{const r=t.prepare(`SELECT node_id, deadline_at FROM nodes
5
+ WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),i=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let a=0;for(const s of r){const u=Date.parse(s.deadline_at);Number.isNaN(u)||(a+=Number(i.run(new Date(u+n).toISOString(),s.node_id,s.deadline_at).changes))}return a})}o(ge,"shiftProfileNodeDeadlines");function Z(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}o(Z,"sqlInput");function Oe(e,n){const t=[],r=o((a,s=a)=>{Object.prototype.hasOwnProperty.call(n,a)&&t.push([s,Z(n[a],a)])},"add");if(r("name"),r("description"),r("title"),r("icon"),r("cycles"),r("kind"),r("mode"),r("lifecycle"),r("cwd"),r("host_kind"),r("profile_id"),r("parent"),r("spawned_by"),r("creator"),r("fork_from"),r("fork_source_file"),r("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",f(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",f(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",f(n.launch,"launch")]),t.length===0){const a=E(e);if(a===null)throw new Error(`unknown node: ${e}`);return a}if(d().prepare(`UPDATE nodes SET ${t.map(([a])=>`${a} = ?`).join(", ")} WHERE node_id = ?`).run(...t.map(([,a])=>a),e).changes!==1)throw new Error(`unknown node: ${e}`);return E(e)}o(Oe,"updateNode");function he(e,n){d().prepare("UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}o(he,"setStatus");function Te(e,n){d().prepare("UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}o(Te,"setIntent");function De(e,n,t={}){if(t.outcome===void 0){const i=[],a=[];Object.prototype.hasOwnProperty.call(n,"status")&&(i.push("status = ?"),a.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(i.push("intent = ?"),a.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(i.push("terminal_reason = ?"),a.push(n.terminal_reason??null));const s=["node_id = ?"];a.push(e),t.fromStatuses!==void 0&&(s.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),a.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&s.push("final_report IS NULL");const u=d().prepare(`UPDATE nodes SET ${i.join(", ")} WHERE ${s.join(" AND ")}`).run(...a);return Number(u.changes)}const r=t.outcome;return _(i=>{const a=[],s=[];Object.prototype.hasOwnProperty.call(n,"status")&&(a.push("status = ?"),s.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(a.push("intent = ?"),s.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(a.push("terminal_reason = ?"),s.push(n.terminal_reason??null));const u=o((re,W)=>r.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${W} END`,"outcomeValue");a.push(`outcome_kind = ${u(r.kind,"outcome_kind")}`,`outcome_reason = ${u(r.reason,"outcome_reason")}`,`outcome_detail_json = ${u(r.detailJson,"outcome_detail_json")}`,`outcome_revision = ${r.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${u(r.at,"outcome_at")}`),s.push(r.kind,r.reason,r.detailJson,r.at);const c=["node_id = ?"];s.push(e),t.fromStatuses!==void 0&&(c.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),s.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&c.push("final_report IS NULL");const l=i.prepare(`UPDATE nodes SET ${a.join(", ")} WHERE ${c.join(" AND ")}`).run(...s);if(Number(l.changes)===0)return 0;const R=i.prepare("SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(r.supersede===!0||R.outcome_at===r.at)&&r.documentJson!==null&&r.documentJson!==void 0&&C(i,{idempotencyKey:`node-outcome:${e}`,label:e,bodyJson:r.documentJson,supersede:r.supersede===!0}),Number(l.changes)})}o(De,"transitionStatusIntent");function Ae(e){return d().prepare("SELECT final_report FROM nodes WHERE node_id = ?").get(e)?.final_report??null}o(Ae,"getFinalReport");function Le(e,n){return d().prepare("UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n).changes>0}o(Le,"clearFinalReportIfMatches");function ke(e,n){d().prepare('UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}o(ke,"setPresence");function ve(e,n){d().prepare("UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}o(ve,"recordLaunch");function be(e,n){d().prepare("UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}o(be,"recordSettledTurn");function xe(e,n){d().prepare("UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}o(xe,"setFrozen");function We(e){d().prepare("UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}o(We,"clearFrozen");function Fe(e,n){d().prepare("UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}o(Fe,"recordRespawnAttempt");const m="node_id NOT IN (SELECT node_id FROM warm_pool)",A=["state","cleanup_state","path","branch","repo_root","base_ref","base_sha","created_at","closed_at","next_attempt_at","attempts","quarantined","sweep_reason","sweep_detail","sweep_last_at","sweep_observed_json","abandoned_json","land_intent_json","disposal_json"];function ee(e){return e.worktree_state===null?null:q(Object.fromEntries(A.map(n=>[n,e[`worktree_${n}`]])))}o(ee,"worktreeFromProjection");function He(e){const n=A.map(r=>`w.${r} AS worktree_${r}`).join(", ");return d().prepare(`SELECT n.*, ${n} FROM node_rows n LEFT JOIN worktrees w ON w.node_id = n.node_id WHERE n.profile_id = ? ORDER BY n.created`).all(e).map(r=>D(r,ee(r)))}o(He,"listNodesByProfile");function je(){return d().prepare("SELECT node_id, cwd, profile_id FROM nodes ORDER BY created").all().map(e=>{const n=e;return{nodeId:n.node_id,cwd:n.cwd,profileId:n.profile_id}})}o(je,"listNodeMemoryTargets");function Ie(e,n){d().prepare(`UPDATE nodes
6
+ SET telemetry_tokens_in = ?,
7
+ telemetry_context_tokens = COALESCE(?, telemetry_context_tokens),
8
+ telemetry_last_activity = COALESCE(?, telemetry_last_activity),
9
+ telemetry_updated_at = ?
10
+ WHERE node_id = ?
11
+ AND (telemetry_updated_at IS NULL OR telemetry_updated_at < ?)`).run(n.tokensIn,n.contextTokens,n.lastActivity,n.updatedAt,e,n.updatedAt)}o(Ie,"updateNodeTelemetry");function Ue(){return d().prepare(`SELECT
12
+ node_id, name, description, cycles, kind, status, frozen_at,
13
+ telemetry_context_tokens, telemetry_last_activity,
14
+ pi_pid, turn_open_at, turn_closed_at,
15
+ fault_id, fault_link, fault_op, fault_kind, fault_message, fault_since,
16
+ fault_operation_id, fault_anchor_entry_id, fault_retry_disposition,
17
+ fault_retry_by, fault_retry_attempt, fault_retry_max, fault_retry_next_at,
18
+ fault_provider_error_json
19
+ FROM node_rows WHERE ${m} ORDER BY created`).all().map(n=>{const t=n.pi_pid??null,r=y(t),i=T(n);return{node_id:n.node_id,name:n.name,description:n.description??null,cycles:n.cycles??null,kind:n.kind,status:n.status,frozen_at:n.frozen_at??null,pi_pid:t,telemetry_context_tokens:n.telemetry_context_tokens??null,telemetry_last_activity:n.telemetry_last_activity??null,fault:i?.link==="pi\u2192provider"&&i.retry.by==="daemon"&&i.retry.disposition==="auto"&&!r?null:i,streaming:n.turn_open_at!==null&&n.turn_closed_at===null&&r}})}o(Ue,"graphNodes");function ne(e){const n=[m],t=[];if(e?.status!==void 0){const i=Array.isArray(e.status)?e.status:[e.status];n.push(`status IN (${i.map(()=>"?").join(",")})`),t.push(...i)}return e?.withRecordedPid===!0&&n.push("pi_pid IS NOT NULL"),e?.withRecordedPidOrFrozen===!0&&n.push("(pi_pid IS NOT NULL OR frozen_at IS NOT NULL)"),d().prepare(`SELECT * FROM node_rows WHERE ${n.join(" AND ")} ORDER BY created`).all(...t).map(p)}o(ne,"listNodes");function Me(){return d().prepare(`SELECT * FROM node_rows
6
20
  WHERE ${m} AND kind != 'human'
7
21
  AND (status IN ('active', 'idle') OR (status IN ('done', 'canceled', 'dead') AND (pi_pid IS NOT NULL OR frozen_at IS NOT NULL)))
8
- ORDER BY created`).all().map(_)}o(Ie,"listNodesForSupervision");function Ue(){return s().prepare(`SELECT node_id, name, created FROM nodes WHERE ${m} ORDER BY created`).all()}o(Ue,"listNodeIdentities");function Me(e,n){p(t=>{t.prepare("INSERT OR REPLACE INTO warm_pool (node_id, recipe_key, created) VALUES (?, ?, ?)").run(e,n,new Date().toISOString())})}o(Me,"registerWarmSpare");function Pe(e){return p(n=>n.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(e).changes>0)}o(Pe,"unregisterWarmSpare");function g(e,n){const t=`SELECT w.node_id AS node_id, w.recipe_key AS recipe_key, w.created AS created,
22
+ ORDER BY created`).all().map(p)}o(Me,"listNodesForSupervision");function Ce(){return d().prepare(`SELECT node_id, name, created FROM nodes WHERE ${m} ORDER BY created`).all()}o(Ce,"listNodeIdentities");function Pe(e,n){_(t=>{t.prepare("INSERT OR REPLACE INTO warm_pool (node_id, recipe_key, created) VALUES (?, ?, ?)").run(e,n,new Date().toISOString())})}o(Pe,"registerWarmSpare");function $e(e){return _(n=>n.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(e).changes>0)}o($e,"unregisterWarmSpare");function g(e,n){const t=`SELECT w.node_id AS node_id, w.recipe_key AS recipe_key, w.created AS created,
9
23
  n.status AS status, n.pi_pid AS pi_pid, n.pi_pid_identity AS pi_pid_identity
10
- FROM warm_pool w JOIN node_rows n ON n.node_id = w.node_id`+(n===void 0?"":" WHERE w.recipe_key = ?")+" ORDER BY w.created";return(n===void 0?e.prepare(t).all():e.prepare(t).all(n)).map(i=>({node_id:i.node_id,recipe_key:i.recipe_key,created:i.created,status:i.status,pi_pid:i.pi_pid??null,pi_pid_identity:i.pi_pid_identity??null}))}o(g,"warmSpareRowsFor");function Ce(){return g(s())}o(Ce,"listWarmSpares");function $e(e){return s().prepare("SELECT 1 FROM warm_pool WHERE node_id = ?").get(e)!==void 0}o($e,"isWarmSpare");function L(e){return e.status!=="active"&&e.status!=="idle"?!1:q(e.pi_pid,e.pi_pid_identity)==="alive"}o(L,"spareIsClaimable");function Be(e,n,t={}){return p(r=>{const i=g(r,e).find(L);return i===void 0||r.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(i.node_id).changes===0?null:(r.prepare("UPDATE nodes SET created = ?, deadline_at = ? WHERE node_id = ?").run(n,t.deadlineAt??null,i.node_id),t.outcomeDelivery!==void 0&&y(r,i.node_id,t.outcomeDelivery),i.node_id)})}o(Be,"claimWarmSpare");function ze(e){return g(s(),e).filter(L).length}o(ze,"warmSpareCount");function Je(e){return s().prepare("SELECT node_id FROM nodes WHERE parent = ? ORDER BY created").all(e).map(n=>n.node_id)}o(Je,"childrenOf");function Ye(){return s().prepare(`SELECT node_id, name, kind, mode, lifecycle, status, cwd, host_kind, parent, created
11
- FROM nodes WHERE ${m} ORDER BY created`).all().map(e=>({node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,parent:e.parent??null,created:e.created}))}o(Ye,"rosterNodes");function qe(){return s().prepare("SELECT from_id, to_id, active, created FROM edges WHERE type = 'subscribes_to' ORDER BY created").all().map(e=>({from_id:e.from_id,to_id:e.to_id,active:e.active===1,created:e.created}))}o(qe,"rosterEdges");function Ve(e){return s().prepare(`SELECT * FROM node_rows
24
+ FROM warm_pool w JOIN node_rows n ON n.node_id = w.node_id`+(n===void 0?"":" WHERE w.recipe_key = ?")+" ORDER BY w.created";return(n===void 0?e.prepare(t).all():e.prepare(t).all(n)).map(i=>({node_id:i.node_id,recipe_key:i.recipe_key,created:i.created,status:i.status,pi_pid:i.pi_pid??null,pi_pid_identity:i.pi_pid_identity??null}))}o(g,"warmSpareRowsFor");function Be(){return g(d())}o(Be,"listWarmSpares");function ze(e){return d().prepare("SELECT 1 FROM warm_pool WHERE node_id = ?").get(e)!==void 0}o(ze,"isWarmSpare");function L(e){return e.status!=="active"&&e.status!=="idle"?!1:V(e.pi_pid,e.pi_pid_identity)==="alive"}o(L,"spareIsClaimable");function Ye(e,n,t={}){return _(r=>{const i=g(r,e).find(L);return i===void 0||r.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(i.node_id).changes===0?null:(r.prepare("UPDATE nodes SET created = ?, deadline_at = ? WHERE node_id = ?").run(n,t.deadlineAt??null,i.node_id),t.outcomeDelivery!==void 0&&h(r,i.node_id,t.outcomeDelivery),i.node_id)})}o(Ye,"claimWarmSpare");function Je(e){return g(d(),e).filter(L).length}o(Je,"warmSpareCount");function qe(e){return d().prepare("SELECT node_id FROM nodes WHERE parent = ? ORDER BY created").all(e).map(n=>n.node_id)}o(qe,"childrenOf");function Ve(){return d().prepare(`SELECT node_id, name, kind, mode, lifecycle, status, cwd, host_kind, parent, created
25
+ FROM nodes WHERE ${m} ORDER BY created`).all().map(e=>({node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,parent:e.parent??null,created:e.created}))}o(Ve,"rosterNodes");function Ge(){return d().prepare("SELECT from_id, to_id, active, created FROM edges WHERE type = 'subscribes_to' ORDER BY created").all().map(e=>({from_id:e.from_id,to_id:e.to_id,active:e.active===1,created:e.created}))}o(Ge,"rosterEdges");function Ke(e){return d().prepare(`SELECT * FROM node_rows
12
26
  WHERE parent IS NULL AND kind != 'human'
13
27
  AND status IN ('active','idle') AND cwd = ?
14
28
  AND ${m}
15
- ORDER BY created DESC`).all(e).map(_)}o(Ve,"listResumableRoots");function A(e,n,t,r){s().prepare(`INSERT INTO edges (type, from_id, to_id, active, created)
29
+ ORDER BY created DESC`).all(e).map(p)}o(Ke,"listResumableRoots");function k(e,n,t,r){d().prepare(`INSERT INTO edges (type, from_id, to_id, active, created)
16
30
  VALUES (?, ?, ?, ?, ?)
17
- ON CONFLICT(type, from_id, to_id) DO UPDATE SET active=excluded.active`).run(e,n,t,r?1:0,new Date().toISOString())}o(A,"addEdge");function Ge(e,n,t=!0){A("subscribes_to",e,n,t)}o(Ge,"subscribe");function Ke(e,n){s().prepare("DELETE FROM edges WHERE type = ? AND from_id = ? AND to_id = ?").run("subscribes_to",e,n)}o(Ke,"unsubscribe");function Qe(e,n,t){s().prepare("UPDATE edges SET active = ? WHERE type = ? AND from_id = ? AND to_id = ?").run(t?1:0,"subscribes_to",e,n)}o(Qe,"setSubscriptionActive");function Xe(e,n){A("spawned_by",e,n,!0)}o(Xe,"recordSpawn");function Ze(e){return s().prepare(`SELECT from_id AS node_id, active, created FROM edges
18
- WHERE type = 'subscribes_to' AND to_id = ? ORDER BY created`).all(e).map(n=>({node_id:n.node_id,active:n.active===1,created:n.created}))}o(Ze,"subscribersOf");function b(e){return s().prepare(`SELECT to_id AS node_id, active, created FROM edges
19
- WHERE type = 'subscribes_to' AND from_id = ? ORDER BY created`).all(e).map(n=>({node_id:n.node_id,active:n.active===1,created:n.created}))}o(b,"subscriptionsOf");function en(e){const n=new Set([e]),t=[],r=b(e).map(i=>i.node_id);for(;r.length>0;){const i=r.shift();if(!n.has(i)){n.add(i),t.push(i);for(const d of b(i))n.has(d.node_id)||r.push(d.node_id)}}return t}o(en,"view");function nn(e){return s().prepare(`SELECT 1 FROM edges e JOIN nodes n ON n.node_id = e.to_id
31
+ ON CONFLICT(type, from_id, to_id) DO UPDATE SET active=excluded.active`).run(e,n,t,r?1:0,new Date().toISOString())}o(k,"addEdge");function Qe(e,n,t=!0){k("subscribes_to",e,n,t)}o(Qe,"subscribe");function Xe(e,n){d().prepare("DELETE FROM edges WHERE type = ? AND from_id = ? AND to_id = ?").run("subscribes_to",e,n)}o(Xe,"unsubscribe");function Ze(e,n,t){d().prepare("UPDATE edges SET active = ? WHERE type = ? AND from_id = ? AND to_id = ?").run(t?1:0,"subscribes_to",e,n)}o(Ze,"setSubscriptionActive");function en(e,n){k("spawned_by",e,n,!0)}o(en,"recordSpawn");function nn(e){return d().prepare(`SELECT from_id AS node_id, active, created FROM edges
32
+ WHERE type = 'subscribes_to' AND to_id = ? ORDER BY created`).all(e).map(n=>({node_id:n.node_id,active:n.active===1,created:n.created}))}o(nn,"subscribersOf");function v(e){return d().prepare(`SELECT to_id AS node_id, active, created FROM edges
33
+ WHERE type = 'subscribes_to' AND from_id = ? ORDER BY created`).all(e).map(n=>({node_id:n.node_id,active:n.active===1,created:n.created}))}o(v,"subscriptionsOf");function tn(e){const n=new Set([e]),t=[],r=v(e).map(i=>i.node_id);for(;r.length>0;){const i=r.shift();if(!n.has(i)){n.add(i),t.push(i);for(const a of v(i))n.has(a.node_id)||r.push(a.node_id)}}return t}o(tn,"view");function rn(e){return d().prepare(`SELECT 1 FROM edges e JOIN nodes n ON n.node_id = e.to_id
20
34
  WHERE e.type = 'subscribes_to' AND e.from_id = ? AND e.active = 1
21
- AND n.status IN ('active', 'idle') LIMIT 1`).get(e)!==void 0}o(nn,"hasActiveLiveSubscription");function tn(e){return s().prepare(`SELECT 1 FROM edges e JOIN nodes n ON n.node_id = e.from_id
35
+ AND n.status IN ('active', 'idle') LIMIT 1`).get(e)!==void 0}o(rn,"hasActiveLiveSubscription");function on(e){return d().prepare(`SELECT 1 FROM edges e JOIN nodes n ON n.node_id = e.from_id
22
36
  WHERE e.type = 'subscribes_to' AND e.to_id = ? AND e.active = 1
23
- AND n.status IN ('active', 'idle') LIMIT 1`).get(e)!==void 0}o(tn,"hasLiveSubscriber");function rn(e){const n=E(e)?.waiting_for;if(n==null)return!1;const t=E(n);return t!==null&&(t.status==="active"||t.status==="idle")}o(rn,"hasLiveMessageWait");function on(e,n){s().prepare("UPDATE nodes SET waiting_for = ?, waiting_for_generation = waiting_for_generation + 1 WHERE node_id = ?").run(n,e)}o(on,"setMessageWait");function dn(e,n,t){return p(r=>{const i=r.prepare("SELECT waiting_for_generation FROM nodes WHERE node_id = ? AND waiting_for = ?").get(e,n),d=t();return n!==null&&i!==void 0&&r.prepare("UPDATE nodes SET waiting_for = NULL WHERE node_id = ? AND waiting_for = ? AND waiting_for_generation = ?").run(e,n,i.waiting_for_generation),d})}o(dn,"deliverAndSettleMessageWait");function sn(e,n,t){return p(r=>{const i=r.prepare(`SELECT waiter.waiting_for, waiter.waiting_for_generation, target.status AS controller_status
37
+ AND n.status IN ('active', 'idle') LIMIT 1`).get(e)!==void 0}o(on,"hasLiveSubscriber");function an(e){const n=E(e)?.waiting_for;if(n==null)return!1;const t=E(n);return t!==null&&(t.status==="active"||t.status==="idle")}o(an,"hasLiveMessageWait");function dn(e,n){d().prepare("UPDATE nodes SET waiting_for = ?, waiting_for_generation = waiting_for_generation + 1 WHERE node_id = ?").run(n,e)}o(dn,"setMessageWait");function sn(e,n,t){return _(r=>{const i=r.prepare("SELECT waiting_for_generation FROM nodes WHERE node_id = ? AND waiting_for = ?").get(e,n),a=t();return n!==null&&i!==void 0&&r.prepare("UPDATE nodes SET waiting_for = NULL WHERE node_id = ? AND waiting_for = ? AND waiting_for_generation = ?").run(e,n,i.waiting_for_generation),a})}o(sn,"deliverAndSettleMessageWait");function un(e,n,t){return _(r=>{const i=r.prepare(`SELECT waiter.waiting_for, waiter.waiting_for_generation, target.status AS controller_status
24
38
  FROM nodes AS waiter LEFT JOIN nodes AS target ON target.node_id = waiter.waiting_for
25
- WHERE waiter.node_id = ?`).get(e),d=i?.controller_status==="active"||i?.controller_status==="idle";if(i?.waiting_for!==n||d)return null;const a=t();return r.prepare("UPDATE nodes SET waiting_for = NULL WHERE node_id = ? AND waiting_for = ? AND waiting_for_generation = ?").run(e,n,i.waiting_for_generation),a})}o(sn,"settleDeadMessageWait");function an(e,n,t){return p(r=>{const i=r.prepare("SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return i===void 0?{kind:"missing"}:n(i)?{kind:"terminal",status:i.status,final_report:i.final_report}:{kind:"ran",result:t()}})}o(an,"withFreshTerminalGuard");function w(e){return B(e)}o(w,"hasUnreconciledManagedWorktree");function v(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||w(e.node_id)||e.node_id===O()?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}o(v,"isCollectible");function un(e){if(w(e))return{deleted:!1};const n=p(t=>(t.prepare("DELETE FROM nodes WHERE node_id = ?").run(e),{deleted:!0}));return R(S(e),{recursive:!0,force:!0}),n}o(un,"deleteNode");function ln(e){const n=[...new Set(e)];if(n.length===0)return[];const t=n.filter(w);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const r=n.map(()=>"?").join(","),i=p(d=>{const a=d.prepare(`SELECT node_id FROM nodes WHERE node_id IN (${r}) ORDER BY created`).all(...n).map(({node_id:u})=>u);return d.prepare(`DELETE FROM nodes WHERE node_id IN (${r})`).run(...n),a});for(const d of i)R(S(d),{recursive:!0,force:!0});return i}o(ln,"deleteNodes");function cn(e){const n=e.dryRun??!1,t=e.includeStale??!1,r=new Date(Date.now()-e.ttlDays*864e5).toISOString(),i=O()??"",d=s(),a=d.prepare(`SELECT * FROM node_rows
39
+ WHERE waiter.node_id = ?`).get(e),a=i?.controller_status==="active"||i?.controller_status==="idle";if(i?.waiting_for!==n||a)return null;const s=t();return r.prepare("UPDATE nodes SET waiting_for = NULL WHERE node_id = ? AND waiting_for = ? AND waiting_for_generation = ?").run(e,n,i.waiting_for_generation),s})}o(un,"settleDeadMessageWait");function ln(e,n,t){return _(r=>{const i=r.prepare("SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return i===void 0?{kind:"missing"}:n(i)?{kind:"terminal",status:i.status,final_report:i.final_report}:{kind:"ran",result:t()}})}o(ln,"withFreshTerminalGuard");function w(e){return z(e)}o(w,"hasUnreconciledManagedWorktree");function b(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||w(e.node_id)||e.node_id===O()?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}o(b,"isCollectible");function cn(e){if(w(e))return{deleted:!1};const n=_(t=>(t.prepare("DELETE FROM nodes WHERE node_id = ?").run(e),{deleted:!0}));return N(S(e),{recursive:!0,force:!0}),n}o(cn,"deleteNode");function _n(e){const n=[...new Set(e)];if(n.length===0)return[];const t=n.filter(w);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const r=n.map(()=>"?").join(","),i=_(a=>{const s=a.prepare(`SELECT node_id FROM nodes WHERE node_id IN (${r}) ORDER BY created`).all(...n).map(({node_id:u})=>u);return a.prepare(`DELETE FROM nodes WHERE node_id IN (${r})`).run(...n),s});for(const a of i)N(S(a),{recursive:!0,force:!0});return i}o(_n,"deleteNodes");function pn(e){const n=e.dryRun??!1,t=e.includeStale??!1,r=new Date(Date.now()-e.ttlDays*864e5).toISOString(),i=O()??"",a=d(),s=a.prepare(`SELECT * FROM node_rows
26
40
  WHERE status IN ('dead', 'done', 'canceled') AND created < ?
27
- ORDER BY created`).all(r).map(_).filter(l=>v(l,{pastTtl:!0})).map(l=>({node_id:l.node_id,status:l.status,created:l.created})),u=t?d.prepare(`SELECT node_id, status, created, pi_pid FROM node_rows
41
+ ORDER BY created`).all(r).map(p).filter(l=>b(l,{pastTtl:!0})).map(l=>({node_id:l.node_id,status:l.status,created:l.created})),u=t?a.prepare(`SELECT node_id, status, created, pi_pid FROM node_rows
28
42
  WHERE status IN ('active', 'idle') AND created < ?
29
- ORDER BY created`).all(r).filter(l=>{if(l.node_id===i)return!1;const N=l.pi_pid;return!h(N)}).map(l=>({node_id:l.node_id,status:l.status,created:l.created})).filter(l=>!w(l.node_id)):[],c=[...a,...u];return n||c.length===0?{pruned:c,dryRun:n}:(x(c),{pruned:c,dryRun:n})}o(cn,"pruneNodes");function x(e){if(e.length!==0){p(n=>{const t=n.prepare("DELETE FROM nodes WHERE node_id = ?");for(const r of e)t.run(r.node_id)});for(const n of e)R(S(n.node_id),{recursive:!0,force:!0})}}o(x,"deletePrunedNodes");function te(e,n){try{const r=j(I(K(e),"telemetry.json"),{throwIfNoEntry:!1});if(r!==void 0)return r.mtimeMs}catch{}const t=Date.parse(n);return Number.isNaN(t)?0:t}o(te,"recencyMs");function pn(e){const n=e.dryRun??!1,r=ne().map(u=>({row:u,recency:te(u.node_id,u.created),retained:!v(u)})).sort((u,c)=>c.recency-u.recency),i=r.filter(u=>u.retained).length,d=Math.max(e.maxNodes,i),a=r.filter((u,c)=>c>=d&&!u.retained).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created}));return n||a.length===0?{pruned:a,dryRun:n}:(x(a),{pruned:a,dryRun:n})}o(pn,"pruneToLimit");export{me as canonicalSessionFile,Je as childrenOf,Be as claimWarmSpare,Ae as clearFinalReportIfMatches,ke as clearFrozen,Ee as createNode,un as deleteNode,ln as deleteNodes,dn as deliverAndSettleMessageWait,Se as dueNodeDeadlines,we as findNodeBySessionFile,Le as getFinalReport,E as getNode,Ne as getRow,Re as getRowByPane,nn as hasActiveLiveSubscription,rn as hasLiveMessageWait,tn as hasLiveSubscriber,v as isCollectible,$e as isWarmSpare,Ue as listNodeIdentities,je as listNodeMemoryTargets,ne as listNodes,He as listNodesByProfile,Ie as listNodesForSupervision,Ve as listResumableRoots,Ce as listWarmSpares,cn as pruneNodes,pn as pruneToLimit,ve as recordLaunch,Fe as recordRespawnAttempt,xe as recordSettledTurn,Xe as recordSpawn,Me as registerWarmSpare,qe as rosterEdges,Ye as rosterNodes,We as setFrozen,Te as setIntent,on as setMessageWait,ge as setNodeDeadline,be as setPresence,ye as setStatus,Qe as setSubscriptionActive,sn as settleDeadMessageWait,Oe as shiftProfileNodeDeadlines,Ge as subscribe,Ze as subscribersOf,b as subscriptionsOf,De as transitionStatusIntent,Pe as unregisterWarmSpare,Ke as unsubscribe,he as updateNode,en as view,ze as warmSpareCount,an as withFreshTerminalGuard};
43
+ ORDER BY created`).all(r).filter(l=>{if(l.node_id===i)return!1;const R=l.pi_pid;return!y(R)}).map(l=>({node_id:l.node_id,status:l.status,created:l.created})).filter(l=>!w(l.node_id)):[],c=[...s,...u];return n||c.length===0?{pruned:c,dryRun:n}:(x(c),{pruned:c,dryRun:n})}o(pn,"pruneNodes");function x(e){if(e.length!==0){_(n=>{const t=n.prepare("DELETE FROM nodes WHERE node_id = ?");for(const r of e)t.run(r.node_id)});for(const n of e)N(S(n.node_id),{recursive:!0,force:!0})}}o(x,"deletePrunedNodes");function te(e,n){try{const r=I(U(Q(e),"telemetry.json"),{throwIfNoEntry:!1});if(r!==void 0)return r.mtimeMs}catch{}const t=Date.parse(n);return Number.isNaN(t)?0:t}o(te,"recencyMs");function fn(e){const n=e.dryRun??!1,r=ne().map(u=>({row:u,recency:te(u.node_id,u.created),retained:!b(u)})).sort((u,c)=>c.recency-u.recency),i=r.filter(u=>u.retained).length,a=Math.max(e.maxNodes,i),s=r.filter((u,c)=>c>=a&&!u.retained).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created}));return n||s.length===0?{pruned:s,dryRun:n}:(x(s),{pruned:s,dryRun:n})}o(fn,"pruneToLimit");export{me as canonicalSessionFile,qe as childrenOf,Ye as claimWarmSpare,Le as clearFinalReportIfMatches,We as clearFrozen,Ee as createNode,cn as deleteNode,_n as deleteNodes,sn as deliverAndSettleMessageWait,ye as dueNodeDeadlines,we as findNodeBySessionFile,Ae as getFinalReport,E as getNode,Re as getRow,Ne as getRowByPane,Ue as graphNodes,rn as hasActiveLiveSubscription,an as hasLiveMessageWait,on as hasLiveSubscriber,b as isCollectible,ze as isWarmSpare,Ce as listNodeIdentities,je as listNodeMemoryTargets,ne as listNodes,He as listNodesByProfile,Me as listNodesForSupervision,Ke as listResumableRoots,Be as listWarmSpares,pn as pruneNodes,fn as pruneToLimit,ve as recordLaunch,Fe as recordRespawnAttempt,be as recordSettledTurn,en as recordSpawn,Pe as registerWarmSpare,Ge as rosterEdges,Ve as rosterNodes,xe as setFrozen,Te as setIntent,dn as setMessageWait,Se as setNodeDeadline,ke as setPresence,he as setStatus,Ze as setSubscriptionActive,un as settleDeadMessageWait,ge as shiftProfileNodeDeadlines,Qe as subscribe,nn as subscribersOf,v as subscriptionsOf,De as transitionStatusIntent,$e as unregisterWarmSpare,Xe as unsubscribe,Oe as updateNode,Ie as updateNodeTelemetry,tn as view,Je as warmSpareCount,ln as withFreshTerminalGuard};