@north-light/cli 0.3.503 → 0.3.505
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.
- package/dist/api/client.d.ts +5 -1
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +40 -0
- package/dist/api/routes.d.ts +2 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +8 -0
- package/dist/clients/attach/viewer.js +575 -575
- package/dist/clients/dashboard/app.d.ts +7 -0
- package/dist/clients/dashboard/app.js +2 -0
- package/dist/clients/dashboard/model.d.ts +39 -0
- package/dist/clients/dashboard/model.js +1 -0
- package/dist/clients/dashboard/render.d.ts +29 -0
- package/dist/clients/dashboard/render.js +3 -0
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/surface/node/focus.js +1 -1
- package/dist/commands/surface-dashboard.d.ts +2 -0
- package/dist/commands/surface-dashboard.js +3 -0
- package/dist/commands/surface.js +1 -1
- package/dist/core/canvas/browse/app.d.ts +3 -0
- package/dist/core/canvas/browse/app.js +3 -3
- package/dist/core/canvas/browse/model.d.ts +5 -1
- package/dist/core/canvas/browse/model.js +1 -1
- package/dist/core/canvas/browse/render.d.ts +5 -0
- package/dist/core/canvas/browse/render.js +3 -3
- package/dist/core/canvas/migrations.js +1 -1
- package/dist/core/canvas/recovery.d.ts +5 -0
- package/dist/core/canvas/recovery.js +2 -2
- package/dist/core/human/requests.d.ts +3 -0
- package/dist/core/human/requests.js +17 -17
- package/dist/core/keybindings/catalog.d.ts +4 -3
- package/dist/core/keybindings/catalog.js +1 -1
- package/dist/core/runtime/broker/model-adapter.d.ts +4 -4
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/focus-viewer.d.ts +6 -0
- package/dist/core/runtime/focus-viewer.js +1 -1
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/placement-tmux.d.ts +1 -1
- package/dist/core/runtime/placement-tmux.js +1 -1
- package/dist/core/runtime/tmux-bindings.js +3 -3
- package/dist/core/runtime/tmux-driver.d.ts +6 -0
- package/dist/core/runtime/tmux-driver.js +5 -5
- package/dist/daemon/api/bridge.js +3 -3
- package/dist/daemon/api/handlers/broker-recovery.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +6 -6
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/viewer-presence.d.ts +3 -0
- package/dist/daemon/api/viewer-presence.js +1 -1
- package/docs/sdk/release-notes.md +8 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -2,7 +2,7 @@ import { type AssistantMessageEventStream, type Context, type Model, type Models
|
|
|
2
2
|
import type { ModelRuntime } from '@earendil-works/pi-coding-agent';
|
|
3
3
|
/** Pi uses availability and auth for its model controls; only the daemon can
|
|
4
4
|
* decide whether a route has credentials. Keep the broker's metadata selectable. */
|
|
5
|
-
export declare function configureBrokerModelRuntime(runtime: ModelRuntime): void;
|
|
5
|
+
export declare function configureBrokerModelRuntime(runtime: ModelRuntime, intent?: string): void;
|
|
6
6
|
export declare const LLM_BROKER_RETRY_WINDOW_S = 300;
|
|
7
7
|
export declare const LLM_REFUSAL_DIAGNOSTIC = "crtr:llm-refusal";
|
|
8
8
|
/** The retry deadline (epoch ms) a final daemon refusal carried on its
|
|
@@ -19,6 +19,6 @@ export declare function refusalRetryAt(message: {
|
|
|
19
19
|
* (Anthropic rejects assistant prefill with a 400), so trailing assistants go
|
|
20
20
|
* too. */
|
|
21
21
|
export declare function wireHistory(messages: Context['messages']): Context['messages'];
|
|
22
|
-
export declare function requestBody(model: Model<any>, context: Context, options: ModelsSimpleStreamOptions): Record<string, unknown>;
|
|
23
|
-
/** One pi stream, backed exclusively by the authenticated daemon llm route. */
|
|
24
|
-
export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream;
|
|
22
|
+
export declare function requestBody(model: Model<any>, context: Context, options: ModelsSimpleStreamOptions, intentOverride?: string): Record<string, unknown>;
|
|
23
|
+
/** One pi stream, backed exclusively by the authenticated daemon llm route. `intent` replaces the node's own `CRTR_MODEL_INTENT` for one stream: a background one-shot of an app-paid node asks for `app/light`, not the node's rung. */
|
|
24
|
+
export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions, intent?: string): AssistantMessageEventStream;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`))>=0;){const
|
|
1
|
+
var W=Object.defineProperty;var d=(e,t)=>W(e,"name",{value:t,configurable:!0});import{setTimeout as j}from"node:timers/promises";import{createAssistantMessageEventStream as J,getCurrentSystemPrompt as Y,getCurrentTools as z}from"@earendil-works/pi-ai";import{socketFetch as X}from"../../../api/node-transport.js";import{apiSocketPath as G}from"../../canvas/paths.js";import{currentNodeToken as H}from"./node-token.js";import{envModelExact as $,envModelIntent as K}from"../../../shared/env.js";import{MODEL_CONTEXT_BODY_MAX_BYTES as v}from"../../llm/body-limits.js";import{modelRequestFromConfig as V}from"../../model-routes.js";import{parseProviderRateLimit as Q,providerFailureDiagnostic as E}from"../../provider-failure.js";import{UPSTREAM_MODEL_UNAVAILABLE as b}from"../../fault-classifier.js";function me(e,t){e.checkAuth=async n=>e.getProvider(n)?{type:"api_key"}:void 0,e.getAvailable=async n=>e.getModels(n),e.getAvailableSnapshot=()=>e.getModels(),e.streamSimple=(n,c,r)=>ne(n,c,r,t)}d(me,"configureBrokerModelRuntime");const Z=300,C="crtr:llm-refusal";class R extends Error{static{d(this,"LlmRefusalError")}retryAt;rateLimit;code;status;constructor(t,n,c,r,o){super(t),this.retryAt=n,this.rateLimit=c,this.code=r,this.status=o}}class S extends Error{static{d(this,"UpstreamModelUnavailableError")}}function N(e,t){const n=e===void 0?"the request body":`the request body (${e} bytes)`;return new Error(`request_too_large: ${n} exceeds the ${t}-byte model request limit; compact the conversation to shrink the context`)}d(N,"contextTooLargeError");function D(e){const t=e.details?.rate_limit;if(!t||typeof t!="object")return;const n=Q(t);if(n===void 0)return;const{provider:c,model:r}=t;return typeof c=="string"&&c!==""&&typeof r=="string"&&r!==""?{...n,model:`${c}/${r}`}:n}d(D,"refusalRateLimit");function he(e){for(const t of e.diagnostics??[]){if(t.type!==C)continue;const n=t.details?.retryAt;if(typeof n=="number"&&Number.isFinite(n)&&n>0)return n}}d(he,"refusalRetryAt");class q extends Error{static{d(this,"ContentFilteredError")}}function B(e){return typeof e=="string"?e:e.map(t=>t.type==="text"?{type:"text",text:t.text}:{type:"image_url",image_url:{url:`data:${t.mimeType};base64,${t.data}`}})}d(B,"wireContent");function ee(e){const t=d(r=>r.role==="assistant"&&(r.stopReason==="error"||r.stopReason==="aborted"),"incomplete"),n=e.some(t)?e.filter(r=>!t(r)):e;let c=n.length;for(;c>0&&n[c-1]?.role==="assistant";)c--;return c===n.length?n:n.slice(0,c)}d(ee,"wireHistory");function te(e,t,n,c){const r=[],o=Y(t.messages),i=z(t.messages);o?r.push({role:"system",content:o}):t.systemPrompt&&r.push({role:"system",content:t.systemPrompt});for(const p of ee(t.messages))p.role==="user"?r.push({role:"user",content:B(p.content)}):p.role==="toolResult"?r.push({role:"tool",content:B(p.content),tool_call_id:p.toolCallId}):p.role==="assistant"&&r.push({role:"assistant",content:p.content.filter(u=>u.type==="text").map(u=>u.text).join("")||null,tool_calls:p.content.filter(u=>u.type==="toolCall").map(u=>({id:u.id,type:"function",function:{name:u.name,arguments:JSON.stringify(u.arguments)}}))});const x=`${e.provider}/${e.id}`,_=c??K();return{model:V(x,_,$())?.kind==="logical"?_:x,model_policy:$()?"exact":"substitute",stream:!0,messages:r,...i.length?{tools:i.map(p=>({type:"function",function:{name:p.name,description:p.description,parameters:p.parameters}}))}:{},...n.reasoning?{reasoning_effort:n.reasoning}:{},...n.temperature!==void 0?{temperature:n.temperature}:{},...n.maxTokens!==void 0?{max_tokens:n.maxTokens}:{}}}d(te,"requestBody");function A(e,t){if(typeof t!="string")return!1;const n=t.indexOf("/");return n<1||n===t.length-1?!1:(e.provider=t.slice(0,n),e.model=t.slice(n+1),!0)}d(A,"applyServedModel");function F(e){if(e.details?.served_model!==void 0)return e.details.served_model;const t=e.details?.rate_limit;return typeof t?.provider=="string"&&typeof t.model=="string"?`${t.provider}/${t.model}`:void 0}d(F,"refusalRoute");function P(e){if(!e||typeof e!="object"||!("error"in e))throw new Error("llm returned an invalid response");const t=e.error;if(!t||typeof t.message!="string")throw new Error("llm returned an invalid refusal");return t}d(P,"parseRefusal");function ne(e,t,n={},c){const r=J(),o={role:"assistant",content:[],api:e.api,provider:e.provider,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};return(async()=>{const i=H();if(!i)throw new Error("llm requires a node token");const x=JSON.stringify(te(e,t,n,c)),_=Buffer.byteLength(x);if(_>v)throw N(_,v);let p=0;for(;;){n.signal?.throwIfAborted();const u=await X(G())("http://localhost/v1/llm",{method:"POST",headers:{authorization:`Bearer ${i}`,"content-type":"application/json"},body:x,signal:n.signal});if(!u.ok){const l=P(await u.json());if(u.status===413||l.code==="payload_too_large")throw N(_,v);if(A(o,F(l)),l.retryable!==!0)throw new R(l.message,void 0,D(l),l.code,u.status);const s=l.retry_after_s;if(typeof s!="number"||!Number.isFinite(s)||s<=0)throw l.code===b?new S(l.message):new Error(l.message);const m=Z-p;if(s>m){const f=Date.now()+s*1e3;throw new R(`${l.message} (retry after ${s}s, at ${new Date(f).toISOString()})`,f,D(l))}await j(s*1e3,void 0,{signal:n.signal}),p+=s;continue}if(!u.body)throw new Error("llm returned no stream");r.push({type:"start",partial:o});const U=u.body.getReader(),L=new TextDecoder;let g="",w="stop",I,M=!1,T=!1;const O=d(l=>{const s=JSON.parse(l);if(s.error){const a=P(s);throw A(o,F(a)),a.code===b?new S(a.message):new Error(a.message)}if(s.served_model){if(T=!0,s.served_model.indexOf("/")<1)throw new Error("llm returned an invalid served_model");A(o,s.served_model)}const m=s.choices?.[0],f=m?.delta;if(f?.reasoning_content){const a=o.content.findIndex(k=>k.type==="thinking"),h=a<0?{type:"thinking",thinking:""}:o.content[a],y=a<0?o.content.push(h)-1:a;if(a<0&&r.push({type:"thinking_start",contentIndex:y,partial:o}),h.type!=="thinking")throw new Error("invalid thinking block");h.thinking+=f.reasoning_content,r.push({type:"thinking_delta",contentIndex:y,delta:f.reasoning_content,partial:o})}if(f?.content){const a=o.content.findIndex(k=>k.type==="text"),h=a<0?{type:"text",text:""}:o.content[a],y=a<0?o.content.push(h)-1:a;if(a<0&&r.push({type:"text_start",contentIndex:y,partial:o}),h.type!=="text")throw new Error("invalid text block");h.text+=f.content,r.push({type:"text_delta",contentIndex:y,delta:f.content,partial:o})}for(const a of f?.tool_calls??[]){const h={type:"toolCall",id:a.id,name:a.function.name,arguments:JSON.parse(a.function.arguments)},y=o.content.push(h)-1;r.push({type:"toolcall_start",contentIndex:y,partial:o}),r.push({type:"toolcall_end",contentIndex:y,toolCall:h,partial:o})}m?.finish_reason&&(w=m.finish_reason),m?.message?.refusal&&(I=m.message.refusal),s.usage&&(M=!0,o.usage={input:s.usage.prompt_tokens,output:s.usage.completion_tokens,cacheRead:s.usage.cache_read_tokens,cacheWrite:s.usage.cache_write_tokens,totalTokens:s.usage.total_tokens,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:typeof s.usage.usd_equivalent=="number"&&Number.isFinite(s.usage.usd_equivalent)?s.usage.usd_equivalent:0}})},"apply");for(;;){const{value:l,done:s}=await U.read();if(s)break;g+=L.decode(l,{stream:!0});let m;for(;(m=g.indexOf(`
|
|
2
|
+
`))>=0;){const f=g.slice(0,m).trim();g=g.slice(m+1),f&&O(f)}}if(g+=L.decode(),g.trim()&&O(g.trim()),!M||!T)throw new Error("llm stream ended without usage or served_model");for(const[l,s]of o.content.entries())s.type==="text"&&r.push({type:"text_end",contentIndex:l,content:s.text,partial:o}),s.type==="thinking"&&r.push({type:"thinking_end",contentIndex:l,content:s.thinking,partial:o});if(w==="content_filter")throw new q(I??"Content filtered");if(!["stop","tool_calls","length"].includes(w))throw new Error(`llm returned unknown finish reason: ${w}`);o.stopReason=w==="tool_calls"?"toolUse":w==="length"?"length":"stop",r.push({type:"done",reason:o.stopReason,message:o}),r.end();return}})().catch(i=>{o.stopReason=n.signal?.aborted?"aborted":"error",o.errorMessage=i instanceof Error?i.message:String(i),i instanceof R&&(o.diagnostics=[{type:C,timestamp:Date.now(),...i.retryAt!==void 0?{details:{retryAt:i.retryAt}}:{}},...i.rateLimit!==void 0?[E({status:429,ratelimit:i.rateLimit})]:[],...i.rateLimit===void 0&&i.code==="cap_exhausted"?[E({status:i.status??402,code:i.code})]:[]]),i instanceof S&&(o.diagnostics=[E({status:503,code:b})]),i instanceof q&&o.stopReason==="error"&&(o.rawStopReason="content_filter"),r.push({type:"error",reason:o.stopReason,error:o}),r.end()}),r}d(ne,"streamBrokerModel");export{Z as LLM_BROKER_RETRY_WINDOW_S,C as LLM_REFUSAL_DIAGNOSTIC,me as configureBrokerModelRuntime,he as refusalRetryAt,te as requestBody,ne as streamBrokerModel,ee as wireHistory};
|
|
@@ -10,6 +10,10 @@ export interface FocusViewerOpts {
|
|
|
10
10
|
pane?: string;
|
|
11
11
|
newPane?: boolean;
|
|
12
12
|
inPlace?: boolean;
|
|
13
|
+
/** With `inPlace`: leave this node's viewer in another pane open instead of closing it. */
|
|
14
|
+
keepOtherViewers?: boolean;
|
|
15
|
+
/** With `inPlace`: the inbox ticket the new viewer opens before showing the conversation. */
|
|
16
|
+
openTicket?: string;
|
|
13
17
|
}
|
|
14
18
|
export interface FocusViewerResult {
|
|
15
19
|
focused: boolean;
|
|
@@ -36,4 +40,6 @@ export declare function focusNode(client: CrtrClient, node: Pick<NodeDetailDTO,
|
|
|
36
40
|
pane: string;
|
|
37
41
|
newPane?: boolean;
|
|
38
42
|
inPlace?: boolean;
|
|
43
|
+
keepOtherViewers?: boolean;
|
|
44
|
+
openTicket?: string;
|
|
39
45
|
}): Promise<FocusNodeResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var A=Object.defineProperty;var o=(t,e)=>A(t,"name",{value:e,configurable:!0});import{envHomeOverride as E}from"../../shared/env.js";import{isFinishedWork as O,isLiveStatus as R}from"../canvas/node-order.js";import{InputError as C}from"../io.js";import{closePane as m,currentTmux as x,displayPopupAsync as y,getPaneOption as P,listLivePanes as H,paneExists as h,paneLocation as l,renameWindow as g,respawnPaneSync as V,selectLayout as W,selectPane as v,selectWindow as $,setPaneOption as L,shellQuote as N,splitWindow as S,switchClient as K,windowOfPane as q}from"./placement-tmux.js";function z(){const t=E();return t!==void 0?{CRTR_HOME:t}:{}}o(z,"viewerEnv");function T(){return{...z(),CRTR_ATTACH_WAKE_PARKED:"0"}}o(T,"focusViewerEnv");function d(t){const e=H();if(e!==null){for(const n of e)if(P(n,"@crtr_node")===t)return n}}o(d,"viewerPaneOf");function _(t,e,n,i,a){const s=S(t,{cwd:n,env:T(),command:`crtr surface attach to ${e}`});if(s===null)return{focused:!1,session:null,inPlace:!1,revived:a};const c=l(s);return c!==null&&W(c.window,"even-horizontal"),v(s),{focused:!0,session:c?.session??i,inPlace:!1,revived:a}}o(_,"openBesideCaller");async function M(t,e,n){const i=n.pane??process.env.TMUX_PANE??x()?.pane;if(i===void 0||i==="")return{focused:!1,session:null,inPlace:!1,revived:!1};const s=(await t.ensureAttach(e,{resume:!0,revive:!0,wakeParked:!1})).revived,c=l(i)?.session??null;if(n.inPlace===!0){const r=P(i,"@crtr_node"),u=d(e);n.keepOtherViewers!==!0&&u!==void 0&&u!==i&&h(u)&&m(u);try{L(i,"@crtr_node","")}catch{}const w=q(i),k={...T(),...r!==void 0&&r!==""?{CRTR_ATTACH_ROSTER:r}:{},...n.openTicket!==void 0?{CRTR_ATTACH_OPEN_TICKET:n.openTicket}:{}},p=V({pane:i,cwd:n.cwd,env:k,command:`crtr surface attach to ${e}`});return p&&w!==null&&g(w,n.name),{focused:p,session:c,inPlace:!0,revived:s}}if(n.newPane===!0){const r=d(e);return r!==void 0&&h(r)&&m(r),_(i,e,n.cwd,c,s)}const f=d(e);if(f!==void 0){const r=l(f);if(r!==null)return K(r.session),$(r.session,r.window),v(f),{focused:!0,session:r.session,inPlace:!0,revived:s}}return _(i,e,n.cwd,c,s)}o(M,"focusViewer");async function U(t,e,n){const i=e.node_id;if(e.kind==="human")throw new C({error:"not_focusable",message:`node ${i} is a human-ask (kind:human), not a conversation \u2014 it has no pi session to focus.`,next:`The pending question is queued for the user; see it with \`crtr human list\`, or retract it with \`crtr human cancel ${i}\`.`});return!R(e.status)&&O({lifecycle:e.lifecycle,finalized:e.final_report!=null})?{focused:await y(n.pane,e.cwd,`crtr node inspect transcript ${N(i)}`),session:null,revived:!1,inPlace:!1}:M(t,i,{cwd:e.cwd,name:e.name,pane:n.pane,...n.newPane===!0?{newPane:!0}:{},...n.inPlace===!0?{inPlace:!0}:{},...n.keepOtherViewers===!0?{keepOtherViewers:!0}:{},...n.openTicket!==void 0?{openTicket:n.openTicket}:{}})}o(U,"focusNode");export{U as focusNode,M as focusViewer,z as viewerEnv,d as viewerPaneOf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var E=Object.defineProperty;var s=(e,t)=>E(e,"name",{value:t,configurable:!0});import{envModelIntent as _,envNodeCwd as N,envProfileId as O}from"../../shared/env.js";import{join as C}from"node:path";import{InMemoryCredentialStore as $}from"@earendil-works/pi-ai";import{PoolCredentialStore as B}from"../pool-credential-store.js";import{secretsDir as H}from"../layout.js";import{APP_FAMILY as g,expandModelCandidates as W,modelRequestFromConfig as A,selectInitialModelRoute as Y}from"../model-routes.js";import{defaultModelLaddersConfig as z}from"../../types.js";import{stripThinkingSuffix as G}from"./model-selection.js";import{configureBrokerModelRuntime as J}from"./broker/model-adapter.js";import{currentNodeToken as K}from"./broker/node-token.js";function Q(e){for(let t=e.length-1;t>=0;t--){const n=e[t];if(n?.role!=="assistant")continue;if(typeof n.content=="string")return n.content.trim();if(!Array.isArray(n.content))continue;const c=n.content.map(i=>{const l=i;return l.type==="text"&&typeof l.text=="string"?l.text:""}).join("").trim();if(c!=="")return c}return""}s(Q,"lastAssistantText");function U(e,t){const n=_();if(!(n===void 0||!n.startsWith(`${g}/`)))return t?{modelRequest:A(e.modelSpec,n,!1),intent:n}:{modelRequest:{kind:"logical",family:g,strength:"light",spec:G(z().anthropic.light)},intent:`${g}/light`}}s(U,"appPaidRequest");async function y(e,t,n,c){let i,l=!1,d=!1,x;const M=s(o=>{i===void 0||l||(l=!0,o&&i.abort().catch(()=>{}),i.dispose())},"disposeSession"),F=new Promise(o=>{x=setTimeout(()=>{d=!0,M(!0),o(t)},e.timeoutMs)}),j=(async()=>{try{const o=await import("@earendil-works/pi-coding-agent"),m=K()!==void 0;if(d)return t;const u=N()??process.cwd(),f=O(),h=o.getAgentDir(),w=await o.ModelRuntime.create({credentials:m?new $:new B(C(H(),"auth.json")),modelsPath:C(h,"models.json")}),S=m?U(e,n):void 0;if(m&&J(w,S?.intent),d)return t;const I=await o.createAgentSessionServices({cwd:u,agentDir:h,modelRuntime:w,settingsManager:o.SettingsManager.inMemory(),resourceLoaderOptions:{noExtensions:!0,noContextFiles:!0,noSkills:!0,noPromptTemplates:!0,noThemes:!0,systemPrompt:e.systemPrompt,...m?{}:{extensionFactories:[(await import("../../builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js")).createProviderRotationExtension({modelIntent:e.modelIntent,nodeCwd:u,profileId:f})]}}});if(d)return t;const p=S?.modelRequest??A(e.modelSpec,e.modelIntent,!1);if(p===void 0)return t;const P=new o.ModelRegistry(I.modelRuntime),R=m?W(p,u,f).map(a=>P.find(a.providerId,a.modelId)).find(a=>a!==void 0):Y(p,P,{cwd:u,profileId:f}).selected?.model;if(R===void 0)return t;let T;const r=e.tool,L=r===void 0?void 0:o.defineTool({name:r.name,label:r.label,description:r.description,parameters:r.parameters,...r.constrainedSampling===void 0?{}:{constrainedSampling:r.constrainedSampling},async execute(a,D){return T=D,{content:[{type:"text",text:"Recorded."}],details:{recorded:!0},terminate:!0}}}),v=o.SessionManager.inMemory(u,e.sessionId===void 0?void 0:{id:e.sessionId});for(const a of e.seedMessages??[])v.appendMessage(a);return{session:i}=await o.createAgentSessionFromServices({services:I,sessionManager:v,model:R,thinkingLevel:"off",...r===void 0?e.toolPolicy==="builtin"?{}:{noTools:"all"}:{tools:[r.name],customTools:[L]}}),d||(await i.bindExtensions({}),d)?t:(await i.prompt(e.userPrompt),d?t:c(i,T))}catch{return t}finally{M(!1)}})();try{return await Promise.race([j,F])}finally{clearTimeout(x)}}s(y,"runHeadless");function re(e){return y(e,null,!1,(t,n)=>n)}s(re,"headlessToolCall");function se(e){return y(e,"",!1,t=>Q(t.messages))}s(se,"headlessText");function de(e){return y(e,"failed",!0,()=>"completed")}s(de,"headlessTurn");export{se as headlessText,re as headlessToolCall,de as headlessTurn};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { paneExists, paneLocation, paneOfNode, paneCurrentPath, paneSize, paneRunning, ensureSession, openNodeWindow, splitWindow, closePane, currentTmux, switchClient, selectWindow, selectLayout, selectPane, getPaneOption, setPaneOption, breakPane, inTmux, piCommand, shellQuote, renameWindow, displayPopup, displayPopupAsync, windowOfPane, respawnPaneSync, respawnPaneInBackground, respawnPaneInPlace, runShellInBackground, paneStartCommand, panePid, windowAlive, listLivePanes, VIEWER_STAMP_OPTION, stampViewerPaneAsync, liveViewerPanes, sendAttachControl, displayClientMessage, displayMessage, windowIndex, sessionExists, tmuxAvailable, tmuxInteractive, } from './tmux-driver.js';
|
|
1
|
+
export { paneExists, paneLocation, paneOfNode, paneCurrentPath, paneSize, paneRunning, ensureSession, openNodeWindow, splitWindow, closePane, currentTmux, switchClient, selectWindow, selectLayout, selectPane, getPaneOption, setPaneOption, breakPane, inTmux, piCommand, shellQuote, renameWindow, displayPopup, displayPopupAsync, windowOfPane, respawnPaneSync, respawnPaneInBackground, respawnPaneInPlace, runShellInBackground, paneStartCommand, swapPanes, paneCurrentCommand, closeWindow, panePid, windowAlive, listLivePanes, VIEWER_STAMP_OPTION, stampViewerPaneAsync, liveViewerPanes, sendAttachControl, displayClientMessage, displayMessage, windowIndex, sessionExists, tmuxAvailable, tmuxInteractive, } from './tmux-driver.js';
|
|
2
2
|
export { installTmuxBindings } from './tmux-bindings.js';
|
|
3
3
|
export { BROKER_VIEW_SOCKET_WAIT_MS, waitForBrokerViewSocket } from './view-socket.js';
|
|
4
4
|
/** Env for a `crtr surface attach` VIEWER pane (the focus split, the spawn viewer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var u=Object.defineProperty;var s=(e,n)=>u(e,"name",{value:n,configurable:!0});import{envHomeOverride as w}from"../../shared/env.js";import{paneLocation as m,ensureSession as P,openNodeWindow as T,splitWindow as f,selectLayout as _}from"./tmux-driver.js";import{BROKER_VIEW_SOCKET_WAIT_MS as
|
|
1
|
+
var u=Object.defineProperty;var s=(e,n)=>u(e,"name",{value:n,configurable:!0});import{envHomeOverride as w}from"../../shared/env.js";import{paneLocation as m,ensureSession as P,openNodeWindow as T,splitWindow as f,selectLayout as _}from"./tmux-driver.js";import{BROKER_VIEW_SOCKET_WAIT_MS as C}from"./view-socket.js";import{paneExists as v,paneLocation as y,paneOfNode as g,paneCurrentPath as h,paneSize as B,paneRunning as M,ensureSession as V,openNodeWindow as k,splitWindow as H,closePane as L,currentTmux as N,switchClient as b,selectWindow as K,selectLayout as z,selectPane as F,getPaneOption as Q,setPaneOption as $,breakPane as j,inTmux as q,piCommand as D,shellQuote as G,renameWindow as J,displayPopup as U,displayPopupAsync as X,windowOfPane as Y,respawnPaneSync as Z,respawnPaneInBackground as ee,respawnPaneInPlace as ne,runShellInBackground as oe,paneStartCommand as ie,swapPanes as ae,paneCurrentCommand as te,closeWindow as re,panePid as se,windowAlive as le,listLivePanes as pe,VIEWER_STAMP_OPTION as ce,stampViewerPaneAsync as de,liveViewerPanes as ue,sendAttachControl as we,displayClientMessage as me,displayMessage as Pe,windowIndex as Te,sessionExists as fe,tmuxAvailable as _e,tmuxInteractive as Ce}from"./tmux-driver.js";import{installTmuxBindings as Se}from"./tmux-bindings.js";import{BROKER_VIEW_SOCKET_WAIT_MS as Ae,waitForBrokerViewSocket as xe}from"./view-socket.js";function I(){const e=w();return e!==void 0?{CRTR_HOME:e}:{}}s(I,"viewerSplitEnv");function E(e,n,o={}){const l=`crtr surface attach to ${e}`,p={...I(),...o.waitForBroker===!0?{CRTR_ATTACH_WAIT_MS:String(C)}:{},...o.initialWhip===!0?{CRTR_ATTACH_INITIAL_WHIP:"1"}:{}},i=o.cwd??process.cwd();if(o.besidePane!==void 0){const t=f(o.besidePane,{cwd:i,env:p,command:l});if(t===null)return null;const c=m(t),d=c?.session??n,r=c?.window??null;return r!==null&&_(r,"even-horizontal"),{pane:t,session:d,window:r}}P(n,i);const a=T({session:n,name:o.name??e,cwd:i,env:p,command:l});return a===null?null:{pane:a.pane,session:n,window:a.window}}s(E,"openViewerPane");export{Ae as BROKER_VIEW_SOCKET_WAIT_MS,ce as VIEWER_STAMP_OPTION,j as breakPane,L as closePane,re as closeWindow,N as currentTmux,me as displayClientMessage,Pe as displayMessage,U as displayPopup,X as displayPopupAsync,V as ensureSession,Q as getPaneOption,q as inTmux,Se as installTmuxBindings,pe as listLivePanes,ue as liveViewerPanes,k as openNodeWindow,E as openViewerPane,te as paneCurrentCommand,h as paneCurrentPath,v as paneExists,y as paneLocation,g as paneOfNode,se as panePid,M as paneRunning,B as paneSize,ie as paneStartCommand,D as piCommand,J as renameWindow,ee as respawnPaneInBackground,ne as respawnPaneInPlace,Z as respawnPaneSync,oe as runShellInBackground,z as selectLayout,F as selectPane,K as selectWindow,we as sendAttachControl,fe as sessionExists,$ as setPaneOption,G as shellQuote,H as splitWindow,de as stampViewerPaneAsync,ae as swapPanes,b as switchClient,_e as tmuxAvailable,Ce as tmuxInteractive,I as viewerSplitEnv,xe as waitForBrokerViewSocket,le as windowAlive,Te as windowIndex,Y as windowOfPane};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var Q=Object.defineProperty;var u=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{mkdtempSync as Y,rmSync as Z,writeFileSync as V}from"node:fs";import{tmpdir as O}from"node:os";import{join as M}from"node:path";import{ATTACH_CONTROL_BINDINGS as U,BINDING_CATALOG as _,BINDING_IDS as ee,encodeAttachControlInput as ne,formatGesture as te,isAttachPaneBinding as re,resolveUserKeybindingSettings as q}from"../keybindings/index.js";import{normalizeTmuxPassthrough as ie}from"../config.js";import{withExclusiveDirectoryLock as oe}from"../exclusive-lock.js";import{surfaceTmuxStyleArgs as se}from"./surface-bg.js";import{runTmux as f,shellQuote as h}from"./tmux-driver.js";const A="@crtr_keybindings_manifest",p="root",ue={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.show-working":{description:"show/hide working",action:{kind:"keys",keys:"/show-working"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.provider-options":{description:"provider options",action:{kind:"popup",run:"sys settings --page provider-options",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.analytics":{description:"analytics",action:{kind:"popup",run:"canvas analytics --pane {pane}",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"98%",h:"96%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function b(e){return e.replace(/#/g,"##")}u(b,"escapeTmuxFormats");function ce(e){return e.map(h).join(" ")}u(ce,"tmuxCommand");const ae={w:"60%",h:"50%"};function G(e,n=!1,t=ae){const r=`crtr canvas chord --pane '#{pane_id}' --run ${h(b(e))}${n?" --interactive":""}`;return n?{argv:["display-popup","-E","-w",t.w,"-h",t.h,"-d","#{pane_current_path}",r],menu:`display-popup -E -w ${t.w} -h ${t.h} -d "#{pane_current_path}" ${h(r)}`}:{argv:["run-shell",`${r} >/dev/null 2>&1`],menu:`run-shell ${h(`${r} >/dev/null 2>&1`)}`}}u(G,"chordCommand");function de(e){const t=`crtr ${b(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",t],menu:`run-shell -b ${h(t)}`}}u(de,"directCommand");function j(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{const n=b(e.keys);return{argv:["send-keys",n,"Enter"],menu:`send-keys -t '#{pane_id}' ${h(n)} Enter`}}case"raw-keys":{const n=b(e.keys);return{argv:["send-keys",n],menu:`send-keys -t '#{pane_id}' ${h(n)}`}}case"literal-input":{const n=b(e.input);return{argv:["send-keys","-l",n],menu:`send-keys -l -t '#{pane_id}' ${h(n)}`}}case"command":return G(e.run);case"direct":return de(e.run);case"popup":return G(e.run,!0,e.size);case"submenu":{const n=N(e.title,e.items);return{argv:n,menu:ce(n)}}}}u(j,"menuActionCommand");function me(e){return j(e)?.menu??""}u(me,"renderMenuAction");function pe(e){return e.replace(/#\[[^\]]*\]/g,"").length}u(pe,"menuItemWidth");function N(e,n){const t=b(e),r=n.reduce((o,c)=>Math.max(o,pe(c.description)),0),s=["display-menu","-T",`#[align=centre]${t}`,...se()];s.push("-x",`#{e|-:#{pane_right},${Math.max(t.length,r)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(const o of n){if(o.action.kind==="separator"){s.push("");continue}const c=o.action.kind==="disabled"?o.description:b(o.description);s.push(c,o.selector,me(o.action))}return s.push("","-esc / q to close","",""),s}u(N,"buildMenuArgs");const le={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function z(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};const n=e.split("+");return{key:n.pop(),modifiers:n}}u(z,"normalizedStrokeParts");function fe(e){return v(e)[0]}u(fe,"tmuxKey");function v(e){let{key:n,modifiers:t}=z(e);const r=new Set(t),s=u((o,c)=>[r.has("ctrl")?"C-":"",r.has("alt")?"M-":"",c?"S-":"",le[o]??o].join(""),"name");if(r.has("shift")&&n.length===1&&/[a-z]/.test(n)){const o=n.toUpperCase();return!r.has("ctrl")&&!r.has("alt")?[s(o,!1)]:[s(o,!0),s(o,!1),s(n,!0)]}return[s(n,r.has("shift"))]}u(v,"tmuxKeyNames");function ge(e){const{key:n,modifiers:t}=z(e);return t.includes("shift")&&/[a-z]/.test(n)?n.toUpperCase():n==="space"?" ":n}u(ge,"menuSelector");function T(e,n,t){const r=[];for(const s of e){const o=n.get(s);if(o!==void 0)for(const c of t.gestures(s))r.push({description:o.description,selector:ge(c),action:o.action})}return r}u(T,"boundMenuItems");function F(e){const n=new Map;for(const[c,l]of Object.entries(ue))l!==void 0&&n.set(c,l);for(const{menuId:c,actionId:l}of U){const x=_.find(w=>w.id===l);if(x===void 0)throw new Error(`missing attach binding definition ${l}`);n.set(c,{description:x.name.toLowerCase(),action:{kind:"literal-input",input:ne(l)}})}const t=T(U.map(({menuId:c})=>c),n,e);t.length>0&&n.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:t}});const r=T(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],n,e);n.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:r}});const s=T(["crtr.tmux.menu.fold-tools","crtr.tmux.menu.show-working"],n,e);n.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:s}});const o=T(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],n,e);return n.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:o}}),n}u(F,"resolvedMenuActions");function K(e,n){const t=u(c=>T(c,n,e),"boundItems"),r=[],s=u((c,l)=>{l.length!==0&&(r.length>0&&r.push({description:"",selector:"",action:{kind:"separator"}}),r.push({description:`-#[bold]${c}`,selector:"",action:{kind:"disabled"}},...l))},"addGroup");s("Explore",t(["crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),s("Current node",t(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),s("Lifecycle",t(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),s("System",t(["crtr.tmux.menu.providers","crtr.tmux.menu.provider-options","crtr.tmux.menu.plugins","crtr.tmux.menu.analytics","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));const o=e.gestures("crtr.tmux.menu.open");if(o.length>0&&r.length>0){r.push({description:"",selector:"",action:{kind:"separator"}});for(const c of o)r.push({description:`${te(c)} to close`,selector:fe(c),action:{kind:"dismiss"}})}return r}u(K,"menuItems");function Pe(e){const n=e??q().bindings;return N(" crtr ",K(n,F(n)))}u(Pe,"crouterMenuTmuxArgs");function S(e,n){let t=n;for(;t<e.length&&/\s/.test(e[t]);)t+=1;if(t>=e.length)return null;let r=null,s="";for(;t<e.length;){const o=e[t];if(r===null&&/\s/.test(o))break;if(r===null&&(o==="'"||o==='"')){r=o,t+=1;continue}if(r===o){r=null,t+=1;continue}if(o==="\\"&&r!=="'"&&t+1<e.length){s+=e[t+1],t+=2;continue}s+=o,t+=1}return{value:s,end:t}}u(S,"readTmuxToken");function B(e){const n=S(e,0);if(n?.value!=="bind-key")return null;let t=n.end,r=!1;for(;;){const s=S(e,t);if(s===null)return null;if(t=s.end,s.value==="-r"){r=!0;continue}if(s.value!=="-T")continue;const o=S(e,t);if(o===null)return null;const c=S(e,o.end);return c===null?null:{table:o.value,key:c.value,command:e.slice(c.end).trimStart(),repeat:r}}}u(B,"parseTmuxBinding");function $(e,n){const t=f(["list-keys","-T",e]);return t.ok?t.stdout.split(`
|
|
1
|
+
var Q=Object.defineProperty;var u=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{mkdtempSync as Y,rmSync as Z,writeFileSync as V}from"node:fs";import{tmpdir as O}from"node:os";import{join as M}from"node:path";import{ATTACH_CONTROL_BINDINGS as U,BINDING_CATALOG as _,BINDING_IDS as ee,encodeAttachControlInput as ne,formatGesture as te,isAttachPaneBinding as re,resolveUserKeybindingSettings as q}from"../keybindings/index.js";import{normalizeTmuxPassthrough as ie}from"../config.js";import{withExclusiveDirectoryLock as oe}from"../exclusive-lock.js";import{surfaceTmuxStyleArgs as se}from"./surface-bg.js";import{runTmux as f,shellQuote as k}from"./tmux-driver.js";const A="@crtr_keybindings_manifest",p="root",ue={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume"}},"crtr.tmux.menu.dashboard":{description:"dashboard",action:{kind:"direct",run:"surface dashboard --pane {pane}"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.show-working":{description:"show/hide working",action:{kind:"keys",keys:"/show-working"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.provider-options":{description:"provider options",action:{kind:"popup",run:"sys settings --page provider-options",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.analytics":{description:"analytics",action:{kind:"popup",run:"canvas analytics --pane {pane}",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"98%",h:"96%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function b(e){return e.replace(/#/g,"##")}u(b,"escapeTmuxFormats");function ce(e){return e.map(k).join(" ")}u(ce,"tmuxCommand");const ae={w:"60%",h:"50%"};function G(e,n=!1,t=ae){const r=`crtr canvas chord --pane '#{pane_id}' --run ${k(b(e))}${n?" --interactive":""}`;return n?{argv:["display-popup","-E","-w",t.w,"-h",t.h,"-d","#{pane_current_path}",r],menu:`display-popup -E -w ${t.w} -h ${t.h} -d "#{pane_current_path}" ${k(r)}`}:{argv:["run-shell",`${r} >/dev/null 2>&1`],menu:`run-shell ${k(`${r} >/dev/null 2>&1`)}`}}u(G,"chordCommand");function de(e){const t=`crtr ${b(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",t],menu:`run-shell -b ${k(t)}`}}u(de,"directCommand");function j(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{const n=b(e.keys);return{argv:["send-keys",n,"Enter"],menu:`send-keys -t '#{pane_id}' ${k(n)} Enter`}}case"raw-keys":{const n=b(e.keys);return{argv:["send-keys",n],menu:`send-keys -t '#{pane_id}' ${k(n)}`}}case"literal-input":{const n=b(e.input);return{argv:["send-keys","-l",n],menu:`send-keys -l -t '#{pane_id}' ${k(n)}`}}case"command":return G(e.run);case"direct":return de(e.run);case"popup":return G(e.run,!0,e.size);case"submenu":{const n=N(e.title,e.items);return{argv:n,menu:ce(n)}}}}u(j,"menuActionCommand");function me(e){return j(e)?.menu??""}u(me,"renderMenuAction");function pe(e){return e.replace(/#\[[^\]]*\]/g,"").length}u(pe,"menuItemWidth");function N(e,n){const t=b(e),r=n.reduce((o,c)=>Math.max(o,pe(c.description)),0),s=["display-menu","-T",`#[align=centre]${t}`,...se()];s.push("-x",`#{e|-:#{pane_right},${Math.max(t.length,r)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(const o of n){if(o.action.kind==="separator"){s.push("");continue}const c=o.action.kind==="disabled"?o.description:b(o.description);s.push(c,o.selector,me(o.action))}return s.push("","-esc / q to close","",""),s}u(N,"buildMenuArgs");const le={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function z(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};const n=e.split("+");return{key:n.pop(),modifiers:n}}u(z,"normalizedStrokeParts");function fe(e){return v(e)[0]}u(fe,"tmuxKey");function v(e){let{key:n,modifiers:t}=z(e);const r=new Set(t),s=u((o,c)=>[r.has("ctrl")?"C-":"",r.has("alt")?"M-":"",c?"S-":"",le[o]??o].join(""),"name");if(r.has("shift")&&n.length===1&&/[a-z]/.test(n)){const o=n.toUpperCase();return!r.has("ctrl")&&!r.has("alt")?[s(o,!1)]:[s(o,!0),s(o,!1),s(n,!0)]}return[s(n,r.has("shift"))]}u(v,"tmuxKeyNames");function ge(e){const{key:n,modifiers:t}=z(e);return t.includes("shift")&&/[a-z]/.test(n)?n.toUpperCase():n==="space"?" ":n}u(ge,"menuSelector");function T(e,n,t){const r=[];for(const s of e){const o=n.get(s);if(o!==void 0)for(const c of t.gestures(s))r.push({description:o.description,selector:ge(c),action:o.action})}return r}u(T,"boundMenuItems");function F(e){const n=new Map;for(const[c,l]of Object.entries(ue))l!==void 0&&n.set(c,l);for(const{menuId:c,actionId:l}of U){const x=_.find(w=>w.id===l);if(x===void 0)throw new Error(`missing attach binding definition ${l}`);n.set(c,{description:x.name.toLowerCase(),action:{kind:"literal-input",input:ne(l)}})}const t=T(U.map(({menuId:c})=>c),n,e);t.length>0&&n.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:t}});const r=T(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],n,e);n.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:r}});const s=T(["crtr.tmux.menu.fold-tools","crtr.tmux.menu.show-working"],n,e);n.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:s}});const o=T(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],n,e);return n.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:o}}),n}u(F,"resolvedMenuActions");function K(e,n){const t=u(c=>T(c,n,e),"boundItems"),r=[],s=u((c,l)=>{l.length!==0&&(r.length>0&&r.push({description:"",selector:"",action:{kind:"separator"}}),r.push({description:`-#[bold]${c}`,selector:"",action:{kind:"disabled"}},...l))},"addGroup");s("Explore",t(["crtr.tmux.menu.dashboard","crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),s("Current node",t(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),s("Lifecycle",t(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),s("System",t(["crtr.tmux.menu.providers","crtr.tmux.menu.provider-options","crtr.tmux.menu.plugins","crtr.tmux.menu.analytics","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));const o=e.gestures("crtr.tmux.menu.open");if(o.length>0&&r.length>0){r.push({description:"",selector:"",action:{kind:"separator"}});for(const c of o)r.push({description:`${te(c)} to close`,selector:fe(c),action:{kind:"dismiss"}})}return r}u(K,"menuItems");function Pe(e){const n=e??q().bindings;return N(" crtr ",K(n,F(n)))}u(Pe,"crouterMenuTmuxArgs");function S(e,n){let t=n;for(;t<e.length&&/\s/.test(e[t]);)t+=1;if(t>=e.length)return null;let r=null,s="";for(;t<e.length;){const o=e[t];if(r===null&&/\s/.test(o))break;if(r===null&&(o==="'"||o==='"')){r=o,t+=1;continue}if(r===o){r=null,t+=1;continue}if(o==="\\"&&r!=="'"&&t+1<e.length){s+=e[t+1],t+=2;continue}s+=o,t+=1}return{value:s,end:t}}u(S,"readTmuxToken");function B(e){const n=S(e,0);if(n?.value!=="bind-key")return null;let t=n.end,r=!1;for(;;){const s=S(e,t);if(s===null)return null;if(t=s.end,s.value==="-r"){r=!0;continue}if(s.value!=="-T")continue;const o=S(e,t);if(o===null)return null;const c=S(e,o.end);return c===null?null:{table:o.value,key:c.value,command:e.slice(c.end).trimStart(),repeat:r}}}u(B,"parseTmuxBinding");function $(e,n){const t=f(["list-keys","-T",e]);return t.ok?t.stdout.split(`
|
|
2
2
|
`).find(r=>{const s=B(r);return s?.table===e&&s.key===n})??null:null}u($,"bindingAt");function Le(e){const n=f(["list-keys","-T",p]);if(!n.ok)return[];const t=new Set(n.stdout.split(`
|
|
3
|
-
`).flatMap(r=>{const s=B(r);return s?.table===p?[s.key]:[]}));return e.filter(r=>!r.includes(" > ")&&v(r).some(s=>t.has(s)))}u(Le,"occupiedTmuxRootGestures");function R(e){return typeof e=="object"&&e!==null&&typeof e.table=="string"&&typeof e.key=="string"}u(R,"isInstalledPair");function
|
|
4
|
-
`,"utf8"),f(["source-file",t])}finally{Z(n,{recursive:!0,force:!0})}}u(be,"sourceBindingLine");function X(e){return e.original===null?f(["unbind-key","-T",p,C(e.key)]):be(e.original)}u(X,"restoreWrappedBinding");function we(){return["run-shell","-b",'crtr surface inbox --quiet --tmux-socket "#{socket_path}" --tmux-client "#{client_name}" --target-pane "#{pane_id}"']}u(we,"inboxToggleTmuxCommand");function ve(e){switch(e){case"crtr.tmux.node.next":return["run-shell","crtr surface node cycle --dir next --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.node.previous":return["run-shell","crtr surface node cycle --dir prev --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.inbox.toggle":return we();default:throw new Error(`no tmux command for ${e}`)}}u(ve,"actionCommand");function $e(){const e=process.env.TMUX?.split(",")[0]?.trim();if(e!==void 0&&e!=="")return`${e}.crtr-keybindings.lock`;const n=f(["display-message","-p","#{socket_path}"]);if(n.ok&&n.stdout!=="")return`${n.stdout}.crtr-keybindings.lock`;const t=typeof process.getuid=="function"?process.getuid():"user";return M(O(),`crtr-tmux-keybindings-${t}.lock`)}u($e,"tmuxBindingLockPath");function De(e,n=[]){return oe($e(),()=>Ie(e,n))}u(De,"installTmuxBindings");function Ie(e,n=[]){const t=e===void 0?q():void 0,r=e??t.bindings,s=e===void 0?t.tmuxPassthrough:ie(n),o=[],c=[],l=
|
|
3
|
+
`).flatMap(r=>{const s=B(r);return s?.table===p?[s.key]:[]}));return e.filter(r=>!r.includes(" > ")&&v(r).some(s=>t.has(s)))}u(Le,"occupiedTmuxRootGestures");function R(e){return typeof e=="object"&&e!==null&&typeof e.table=="string"&&typeof e.key=="string"}u(R,"isInstalledPair");function he(e){if(typeof e!="object"||e===null)return!1;const n=e;return typeof n.bindingId=="string"&&ee.has(n.bindingId)&&typeof n.gesture=="string"&&typeof n.key=="string"&&(typeof n.original=="string"||n.original===null)&&typeof n.wrapper=="string"&&(n.state==="owned"||n.state==="relinquished")}u(he,"isWrappedRootBinding");function ke(){const e=f(["show-options","-s","-q",A]);if(!e.ok)return null;if(e.stdout==="")return{pairs:[],wrappers:[]};const n=f(["show-options","-s","-qv",A]);if(!n.ok)return null;try{const t=JSON.parse(n.stdout);if(Array.isArray(t))return t.every(R)?{pairs:t,wrappers:[]}:null;if(typeof t!="object"||t===null)return null;const r=t;return!Array.isArray(r.pairs)||!r.pairs.every(R)||!Array.isArray(r.wrappers)||!r.wrappers.every(he)?null:{pairs:r.pairs,wrappers:r.wrappers}}catch{return null}}u(ke,"readManifest");function W(e){return f(["set-option","-s",A,JSON.stringify(e)])}u(W,"writeManifest");function C(e){return e.replace(/\\/g,"\\\\").replace(/;/g,"\\;")}u(C,"tmuxKeyArgument");function xe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/;/g,"\\;")}"`}u(xe,"tmuxCommandToken");function ye(e){let n=null,t="";for(let r=0;r<e.length;r+=1){const s=e[r];if(n===null&&(s==="'"||s==='"')){n=s,t+=s;continue}if(n===s){n=null,t+=s;continue}if(s==="\\"&&r+1<e.length){const o=e[r+1];n===null&&o===";"?t+=";":t+=s+o,r+=1;continue}t+=s}return t}u(ye,"bindingCommandForBranch");function be(e){const n=Y(M(O(),"crtr-tmux-binding-")),t=M(n,"binding.conf");try{return V(t,`${e}
|
|
4
|
+
`,"utf8"),f(["source-file",t])}finally{Z(n,{recursive:!0,force:!0})}}u(be,"sourceBindingLine");function X(e){return e.original===null?f(["unbind-key","-T",p,C(e.key)]):be(e.original)}u(X,"restoreWrappedBinding");function we(){return["run-shell","-b",'crtr surface inbox --quiet --tmux-socket "#{socket_path}" --tmux-client "#{client_name}" --target-pane "#{pane_id}"']}u(we,"inboxToggleTmuxCommand");function ve(e){switch(e){case"crtr.tmux.node.next":return["run-shell","crtr surface node cycle --dir next --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.node.previous":return["run-shell","crtr surface node cycle --dir prev --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.inbox.toggle":return we();default:throw new Error(`no tmux command for ${e}`)}}u(ve,"actionCommand");function $e(){const e=process.env.TMUX?.split(",")[0]?.trim();if(e!==void 0&&e!=="")return`${e}.crtr-keybindings.lock`;const n=f(["display-message","-p","#{socket_path}"]);if(n.ok&&n.stdout!=="")return`${n.stdout}.crtr-keybindings.lock`;const t=typeof process.getuid=="function"?process.getuid():"user";return M(O(),`crtr-tmux-keybindings-${t}.lock`)}u($e,"tmuxBindingLockPath");function De(e,n=[]){return oe($e(),()=>Ie(e,n))}u(De,"installTmuxBindings");function Ie(e,n=[]){const t=e===void 0?q():void 0,r=e??t.bindings,s=e===void 0?t.tmuxPassthrough:ie(n),o=[],c=[],l=ke();if(l===null)return o.push({code:"tmux-error",message:`tmux is unavailable or ${A} is malformed`}),{ok:!1,installed:c,diagnostics:o};const x=new Map;for(const i of s){const a=_.find(d=>d.id===i);if(!(a===void 0||!re(a))){for(const d of r.gestures(i))if(!d.includes(" > "))for(const m of v(d))x.has(m)||x.set(m,{bindingId:i,gesture:d})}}const w=new Set,I=[];for(const i of l.wrappers){const a=x.get(i.key),d=$(p,i.key);if(d!==null&&d===i.original)continue;if(i.state==="relinquished"||d!==i.wrapper){w.add(i.key),a!==void 0&&I.push({...i,...a,state:"relinquished"});continue}const m=X(i);m.ok||(w.add(i.key),I.push(i),o.push({code:"tmux-error",bindingId:i.bindingId,gesture:i.gesture,message:`could not restore tmux binding ${p}:${i.key}: ${m.stderr}`}))}for(const i of l.pairs){if(i.table===p&&w.has(i.key))continue;const a=f(["unbind-key","-T",i.table,C(i.key)]);!a.ok&&$(i.table,i.key)!==null&&o.push({code:"tmux-error",message:`could not remove crouter binding ${i.table}:${i.key}: ${a.stderr}`})}if(o.some(i=>i.code==="tmux-error")){const i=W({pairs:l.pairs,wrappers:I});return i.ok||o.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${i.stderr}`}),{ok:!1,installed:c,diagnostics:o}}const E=u((i,a,d,m,h)=>{if($(i,a)!==null)return o.push({code:"occupied",bindingId:m,gesture:h,message:`${i}:${a} is already bound by tmux; ${m} was not installed`}),!1;const g=f(["bind-key","-T",i,C(a),...d]);return g.ok?(c.push({table:i,key:a}),!0):(o.push({code:"tmux-error",bindingId:m,gesture:h,message:`could not install ${m}: ${g.stderr}`}),!1)},"install"),P=F(r),H=N(" crtr ",K(r,P));for(const i of r.gestures("crtr.tmux.menu.open"))for(const a of v(i))E(p,a,H,"crtr.tmux.menu.open",i);for(const i of _){if(i.pair?.field!=="menu")continue;const a=_.find(y=>y.id===i.pair?.pairedId);if(a?.pair?.field!=="global")continue;const d=i.id,m=a.id,h=P.get(d),g=h===void 0?null:j(h.action);if(g===null)throw new Error(`no direct tmux action for paired menu binding ${d}`);for(const y of r.gestures(m))for(const J of v(y))E(p,J,g.argv,m,y)}for(const i of["crtr.tmux.node.next","crtr.tmux.node.previous","crtr.tmux.inbox.toggle"])for(const a of r.gestures(i))for(const d of v(a))E(p,d,ve(i),i,a);const L=[];for(const[i,a]of x){if(w.has(i))continue;const d=$(p,i);if(d===null)continue;const m=B(d);if(m===null||m.command===""){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not parse occupied tmux binding ${p}:${i}`});continue}const h=f(["bind-key",...m.repeat?["-r"]:[],"-T",p,C(i),"if-shell","-F","#{!=:#{@crtr_attach},}",`send-keys ${xe(i)}`,ye(m.command)]);if(!h.ok){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not wrap ${p}:${i}: ${h.stderr}`});continue}const g=$(p,i);if(g===null||!g.includes("@crtr_attach")){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not fingerprint wrapped tmux binding ${p}:${i}`});continue}const y={...a,key:i,original:d,wrapper:g,state:"owned"};I.push(y),L.push(y)}const D=W({pairs:c,wrappers:I});if(!D.ok){o.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${D.stderr}`});for(const i of L)$(p,i.key)===i.wrapper&&X(i)}return{ok:o.every(i=>i.code!=="tmux-error"),installed:c,diagnostics:o}}u(Ie,"reconcileTmuxBindings");export{Pe as crouterMenuTmuxArgs,we as inboxToggleTmuxCommand,De as installTmuxBindings,Le as occupiedTmuxRootGestures};
|
|
@@ -260,6 +260,12 @@ export declare function runShellInBackground(command: string): boolean;
|
|
|
260
260
|
* — the exact command `respawn-pane` with no argument re-runs. undefined when
|
|
261
261
|
* tmux is unreachable or the pane is gone. */
|
|
262
262
|
export declare function paneStartCommand(pane: string): string | undefined;
|
|
263
|
+
/** Swap two panes' places on screen (`swap-pane -s a -t b`). The panes keep their ids and
|
|
264
|
+
* processes; only their positions (and windows) exchange. Returns tmux's error text on
|
|
265
|
+
* failure, null on success. */
|
|
266
|
+
export declare function swapPanes(source: string, target: string): string | null;
|
|
267
|
+
/** The foreground command name of a pane (`#{pane_current_command}`). */
|
|
268
|
+
export declare function paneCurrentCommand(pane: string): string | undefined;
|
|
263
269
|
/** The pane's root process pid (`#{pane_pid}`) — the process tmux launched in
|
|
264
270
|
* the pane (the viewer itself, or the login shell hosting it). undefined when
|
|
265
271
|
* tmux is unreachable or the pane is gone. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var O=Object.defineProperty;var r=(n,t)=>O(n,"name",{value:t,configurable:!0});import{execFile as w,spawnSync as
|
|
2
|
-
`)){const s=e.indexOf(" ");if(!(s<0)&&e.slice(s+1)===n){const u=e.slice(0,s);if(u!=="")return u}}return null}r(nn,"paneOfNode");function T(){if(!M())return null;const n=o(["display-message","-p","#{session_name} #{window_id} #{pane_id}"]);if(!n.ok)return null;const[t,e,s]=n.stdout.split(" ");return{session:t,window:e,pane:s}}r(T,"currentTmux");function tn(){const n=
|
|
1
|
+
var O=Object.defineProperty;var r=(n,t)=>O(n,"name",{value:t,configurable:!0});import{execFile as w,spawnSync as d}from"node:child_process";import{encodeAttachControlInput as C}from"../keybindings/index.js";import{listProcessTable as E}from"../canvas/pid.js";import{bundledPiCommandForShell as $}from"./pi-cli.js";import{shellQuote as l}from"../../shared/shell-quote.js";import{envPiBinaryOverride as N}from"../../shared/env.js";function o(n){const t=d("tmux",n,{encoding:"utf8"});return{ok:t.status===0,stdout:(t.stdout??"").trim(),stderr:(t.stderr??"").trim()}}r(o,"tmux");function p(n,t){return o(n===void 0||n===""?t:["-S",n,...t])}r(p,"tmuxOnSocket");function M(){return process.env.TMUX!==void 0&&process.env.TMUX!==""}r(M,"inTmux");function Y(){return d("tmux",["list-sessions"],{encoding:"utf8",stdio:"ignore"}).status===0}r(Y,"tmuxSessionsReachable");function Z(){return d("tmux",["list-clients","-F","#{client_name}"],{encoding:"utf8"}).status===0}r(Z,"tmuxClientsReachable");function nn(n){if(n==="")return null;const t=o(["list-panes","-a","-F","#{pane_id} #{@crtr_node}"]);if(!t.ok)return null;for(const e of t.stdout.split(`
|
|
2
|
+
`)){const s=e.indexOf(" ");if(!(s<0)&&e.slice(s+1)===n){const u=e.slice(0,s);if(u!=="")return u}}return null}r(nn,"paneOfNode");function T(){if(!M())return null;const n=o(["display-message","-p","#{session_name} #{window_id} #{pane_id}"]);if(!n.ok)return null;const[t,e,s]=n.stdout.split(" ");return{session:t,window:e,pane:s}}r(T,"currentTmux");function tn(){const n=d("tmux",["-V"],{stdio:"ignore"});return n.error===void 0&&n.status===0}r(tn,"tmuxAvailable");function en(n){return d("tmux",n,{stdio:"inherit"}).status??1}r(en,"tmuxInteractive");function F(n){return o(["has-session","-t",n]).ok}r(F,"sessionExists");function A(){const n=o(["show-options","-s","terminal-overrides"]).stdout;/Enbp=\\+E/.test(n)||o(["set-option","-sga","terminal-overrides","*:Enbp=\\E[?2004h:Dsbp=\\E[?2004l"])}r(A,"ensureBracketedPaste");function R(){A(),o(["set-option","-s","focus-events","on"])}r(R,"ensureServerOptions");function rn(n,t){F(n)||o(["new-session","-d","-s",n,"-c",t]),R()}r(rn,"ensureSession");function x(n){const t=[];for(const[e,s]of Object.entries(n))t.push("-e",`${e}=${s}`);return t}r(x,"envFlags");function on(n){const t=o(["new-window","-d","-a","-P","-F","#{window_id} #{pane_id}","-t",`${n.session}:`,"-n",n.name,"-c",n.cwd,...x(n.env),n.command]);if(!t.ok)return null;const[e,s]=t.stdout.split(" ");return e===void 0||e===""||s===void 0||s===""?null:{window:e,pane:s}}r(on,"openNodeWindow");function sn(n,t){const e=o(["split-window","-d",...t.vertical===!0?[]:["-h"],...t.before===!0?["-b"]:[],...t.size!==void 0?["-l",String(t.size)]:[],"-P","-F","#{pane_id}","-t",n,"-c",t.cwd,...x(t.env),t.command]);return e.ok&&e.stdout!==""?e.stdout:null}r(sn,"splitWindow");function un(n,t){return!(T()?.session===n)&&!o(["switch-client","-t",n]).ok?!1:o(["select-window","-t",t]).ok}r(un,"focusWindow");function an(n){return o(["kill-window","-t",n]).ok}r(an,"closeWindow");function cn(n,t){return o(["rename-window","-t",n,t]).ok}r(cn,"renameWindow");function dn(n){const t=o(["break-pane","-d","-P","-F","#{window_id} #{pane_id}","-s",n]);if(!t.ok)return null;const[e,s]=t.stdout.split(" ");return e===void 0||e===""||s===void 0||s===""?null:{window:e,pane:s}}r(dn,"breakPane");function pn(n){return o(["kill-pane","-t",n]).ok}r(pn,"closePane");function ln(n,t,e){return o(h(n,t,e)).ok}r(ln,"displayPopup");function fn(n,t,e){return new Promise(s=>{try{w("tmux",h(n,t,e),i=>s(i===null)).stdin?.end()}catch{s(!1)}})}r(fn,"displayPopupAsync");function h(n,t,e){return["display-popup","-E","-t",n,"-d",t,"-w","90%","-h","90%",e]}r(h,"displayPopupArgs");function mn(n,t){const e=o(["display-message","-p","-t",`${n}:${t}`,"#{pane_id}"]);return e.ok&&e.stdout!==""?e.stdout:null}r(mn,"paneOfWindow");function wn(n){const t=o(["display-message","-p","-t",n,"#{window_id}"]);return t.ok&&t.stdout!==""?t.stdout:null}r(wn,"windowOfPane");function xn(n){const t=o(["display-message","-p","-t",n,"#{session_name} #{window_id}"]);if(!t.ok)return null;const e=/^(.*) (@\d+)$/.exec(t.stdout);return e===null||e[1]===""?null:{session:e[1],window:e[2]}}r(xn,"paneLocation");function kn(n){const t=o(["display-message","-p","-t",n,"#{window_index}"]);return!t.ok||!/^\d+$/.test(t.stdout)?null:Number.parseInt(t.stdout,10)}r(kn,"windowIndex");function gn(n){const t=o(["display-message","-p","-t",n,"#{pane_id}"]);return t.ok&&t.stdout===n}r(gn,"paneExists");function hn(n){const t=o(["display-message","-p","-t",n,"#{pane_id} #{pane_dead}"]);return t.ok&&t.stdout===`${n} 0`}r(hn,"paneRunning");function _n(){const n=o(["list-panes","-a","-F","#{pane_id}"]);return n.ok?new Set(n.stdout.split(`
|
|
3
3
|
`).filter(t=>t!=="")):null}r(_n,"listLivePanes");const V=2e3;async function Pn(){const n=await new Promise(t=>{try{w("tmux",["list-panes","-a","-F","#{pane_id}"],{encoding:"utf8",timeout:V,maxBuffer:4194304},(e,s)=>t(e?null:s))}catch{t(null)}});return n===null?null:new Set(n.trim().split(`
|
|
4
|
-
`).filter(t=>t!==""))}r(Pn,"listLivePanesAsync");function yn(n){const t=o(["display-message","-p","-t",n,"#{pane_current_path}"]);return t.ok&&t.stdout!==""?t.stdout:null}r(yn,"paneCurrentPath");function bn(n){const t=o(["display-message","-p","-t",n,"#{pane_width} #{pane_height}"]);if(!t.ok)return null;const[e,s]=t.stdout.split(" "),u=Number.parseInt(e,10),i=Number.parseInt(s,10);return Number.isInteger(u)&&u>0&&Number.isInteger(i)&&i>0?{cols:u,rows:i}:null}r(bn,"paneSize");function vn(n,t,e=4e3){const s=r(u=>{const i=["display-message",...u?["-C"]:[],"-d",String(e)];return t!==void 0&&t!==""&&i.push("-t",t),i.push(n),i},"args");return o(s(!0)).ok||o(s(!1)).ok}r(vn,"displayMessage");function Sn(n,t,e){return o(["set-option","-p","-t",n,t,e]).ok}r(Sn,"setPaneOption");function In(n,t){const e=o(["show-options","-p","-t",n,"-q","-v",t]);return e.ok?e.stdout:void 0}r(In,"getPaneOption");const W="@crtr_viewer_at";let _=0,P=Promise.resolve();function On(n){if(n==="")return;const t=Math.max(Date.now(),_+1);_=t,P=P.then(()=>new Promise(e=>{try{w("tmux",["set-option","-p","-t",n,W,String(t)],()=>e())}catch{e()}}))}r(On,"stampViewerPaneAsync");function B(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}r(B,"escapeRegex");function k(n,t){const e=n.replace(/^"|"$/g,"");return new RegExp(`(?:^|\\s)surface\\s+attach\\s+to\\s+${B(t)}(?:\\s|$)`).test(e)}r(k,"looksLikeViewerCommand");function L(){const n
|
|
5
|
-
`)){const[i,c,
|
|
6
|
-
`).filter(e=>e!=="")}r(U,"listWindowIds");function
|
|
4
|
+
`).filter(t=>t!==""))}r(Pn,"listLivePanesAsync");function yn(n){const t=o(["display-message","-p","-t",n,"#{pane_current_path}"]);return t.ok&&t.stdout!==""?t.stdout:null}r(yn,"paneCurrentPath");function bn(n){const t=o(["display-message","-p","-t",n,"#{pane_width} #{pane_height}"]);if(!t.ok)return null;const[e,s]=t.stdout.split(" "),u=Number.parseInt(e,10),i=Number.parseInt(s,10);return Number.isInteger(u)&&u>0&&Number.isInteger(i)&&i>0?{cols:u,rows:i}:null}r(bn,"paneSize");function vn(n,t,e=4e3){const s=r(u=>{const i=["display-message",...u?["-C"]:[],"-d",String(e)];return t!==void 0&&t!==""&&i.push("-t",t),i.push(n),i},"args");return o(s(!0)).ok||o(s(!1)).ok}r(vn,"displayMessage");function Sn(n,t,e){return o(["set-option","-p","-t",n,t,e]).ok}r(Sn,"setPaneOption");function In(n,t){const e=o(["show-options","-p","-t",n,"-q","-v",t]);return e.ok?e.stdout:void 0}r(In,"getPaneOption");const W="@crtr_viewer_at";let _=0,P=Promise.resolve();function On(n){if(n==="")return;const t=Math.max(Date.now(),_+1);_=t,P=P.then(()=>new Promise(e=>{try{w("tmux",["set-option","-p","-t",n,W,String(t)],()=>e())}catch{e()}}))}r(On,"stampViewerPaneAsync");function B(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}r(B,"escapeRegex");function k(n,t){const e=n.replace(/^"|"$/g,"");return new RegExp(`(?:^|\\s)surface\\s+attach\\s+to\\s+${B(t)}(?:\\s|$)`).test(e)}r(k,"looksLikeViewerCommand");function L(){const n=E();if(n===null)return null;const t=new Map,e=new Map;for(const{pid:s,ppid:u,command:i}of n){e.set(s,i);const a=t.get(u)??[];a.push(s),t.set(u,a)}return{childrenOf:t,commandOf:e}}r(L,"readProcessTree");function j(n,t,e){const s=[t];for(;s.length>0;){const u=s.pop();if(k(n.commandOf.get(u)??"",e))return!0;const i=n.childrenOf.get(u);i!==void 0&&s.push(...i)}return!1}r(j,"processTreeHasViewer");function Cn(n){const t=p(n,["list-panes","-a","-F","#{pane_id} #{session_name} #{@crtr_node} #{@crtr_viewer_at}"]);if(!t.ok||t.stdout==="")return[];const e=[];let s;for(const u of t.stdout.split(`
|
|
5
|
+
`)){const[i,a,c,b]=u.split(" ");if(i===void 0||i===""||a===void 0||a===""||c===void 0||c==="")continue;const g=p(n,["display-message","-p","-t",i,"#{pane_current_command} #{pane_start_command} #{pane_pid}"]);if(!g.ok)continue;const[v="",S="",I]=g.stdout.split(" ");if(!(k(v,c)||k(S,c))){s??=L();const m=Number.parseInt(I,10);if(s===null||!Number.isInteger(m)||m<=0||!j(s,m,c))continue}const f=Number.parseInt(b??"",10);e.push({pane:i,session:a,nodeId:c,stampMs:Number.isSafeInteger(f)&&f>=0?f:0})}return e}r(Cn,"liveViewerPanes");function En(n,t,e){return p(n,["send-keys","-l","-t",t,C(e)]).ok}r(En,"sendAttachControl");function $n(n,t,e){const s=r(u=>{const i=["display-message",...u?["-C"]:[]];return t!==void 0&&t!==""&&i.push("-c",t),i.push(e),i},"args");return p(n,s(!0)).ok||p(n,s(!1)).ok}r($n,"displayClientMessage");function y(n){return["respawn-pane","-k","-c",n.cwd,...x(n.env),"-t",n.pane,n.command]}r(y,"respawnPaneArgs");function Nn(n){return o(y(n)).ok}r(Nn,"respawnPaneSync");function Mn(n){return z(`tmux ${y(n).map(l).join(" ")} >/dev/null 2>&1`)}r(Mn,"respawnPaneInBackground");function z(n){return o(["run-shell","-b",n]).ok}r(z,"runShellInBackground");function Tn(n){const t=o(["display-message","-p","-t",n,"#{pane_start_command}"]);return t.ok?t.stdout:void 0}r(Tn,"paneStartCommand");function Fn(n,t){const e=o(["swap-pane","-s",n,"-t",t]);return e.ok?null:e.stderr===""?"tmux swap-pane failed":e.stderr}r(Fn,"swapPanes");function An(n){const t=o(["display-message","-p","-t",n,"#{pane_current_command}"]);return t.ok&&t.stdout!==""?t.stdout:void 0}r(An,"paneCurrentCommand");function Rn(n){const t=o(["display-message","-p","-t",n,"#{pane_pid}"]);if(!t.ok)return;const e=Number.parseInt(t.stdout,10);return Number.isInteger(e)&&e>0?e:void 0}r(Rn,"panePid");function Vn(n){return o(["respawn-pane","-k","-t",n]).ok}r(Vn,"respawnPaneInPlace");function Wn(n,t=N()??$(l)){return[t,...n.map(l)].join(" ")}r(Wn,"piCommand");function U(n){const t=o(["list-windows","-t",n,"-F","#{window_id}"]);return!t.ok||t.stdout===""?[]:t.stdout.split(`
|
|
6
|
+
`).filter(e=>e!=="")}r(U,"listWindowIds");function Bn(n,t){return n==null||t==null?!1:U(n).includes(t)}r(Bn,"windowAlive");function Ln(n,t){return o(["select-window","-t",`${n}:${t}`]).ok}r(Ln,"selectWindow");function jn(n,t){return o(["select-layout","-t",n,t]).ok}r(jn,"selectLayout");function zn(n){return o(["select-pane","-t",n]).ok}r(zn,"selectPane");function Un(n){return o(["switch-client","-t",n]).ok}r(Un,"switchClient");function qn(n,t){return o(["send-keys","-t",n,t,"Enter"]).ok}r(qn,"sendKeysEnter");export{W as VIEWER_STAMP_OPTION,dn as breakPane,pn as closePane,an as closeWindow,T as currentTmux,$n as displayClientMessage,vn as displayMessage,ln as displayPopup,fn as displayPopupAsync,rn as ensureSession,un as focusWindow,In as getPaneOption,M as inTmux,_n as listLivePanes,Pn as listLivePanesAsync,U as listWindowIds,Cn as liveViewerPanes,on as openNodeWindow,An as paneCurrentCommand,yn as paneCurrentPath,gn as paneExists,xn as paneLocation,nn as paneOfNode,mn as paneOfWindow,Rn as panePid,hn as paneRunning,bn as paneSize,Tn as paneStartCommand,Wn as piCommand,cn as renameWindow,Mn as respawnPaneInBackground,Vn as respawnPaneInPlace,Nn as respawnPaneSync,z as runShellInBackground,o as runTmux,jn as selectLayout,zn as selectPane,Ln as selectWindow,En as sendAttachControl,qn as sendKeysEnter,F as sessionExists,Sn as setPaneOption,l as shellQuote,sn as splitWindow,On as stampViewerPaneAsync,Fn as swapPanes,Un as switchClient,tn as tmuxAvailable,Z as tmuxClientsReachable,en as tmuxInteractive,Y as tmuxSessionsReachable,Bn as windowAlive,kn as windowIndex,wn as windowOfPane};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
1
|
+
var R=Object.defineProperty;var s=(r,e)=>R(r,"name",{value:e,configurable:!0});import{WebSocketServer as $}from"ws";import{isSafeNodeId as A}from"../../core/canvas/paths.js";import{getNode as S}from"../../core/canvas/index.js";import{BROKER_READ_CAPS as C,CLIENT_READ_CAPS as T,FrameDecoder as x,FrameOverflowError as B}from"../../core/runtime/broker-protocol.js";import{classify as k}from"../../core/fault-classifier.js";import{clearFault as v,markNodeRead as N,recordFault as g}from"../../core/canvas/recovery.js";import{decideAttachRevive as O}from"../../core/runtime/revive.js";import{connectViewSocket as P,probeViewSocket as F,waitForBrokerViewSocket as U}from"../../core/runtime/view-socket.js";import{isBeneathRefusal as D}from"../../core/spaces/open-beneath.js";import{attachViewer as _,detachViewer as V,presentViewer as L}from"./viewer-presence.js";const H=new $({noServer:!0,maxPayload:C.maxLineBytes}),M=25e3,J=6e4;function W(r,e=M,i=J){let o=!0,n=!1,a=Date.now();const f=s(()=>{o=!0},"acknowledge"),m=s(()=>{n||(n=!0,clearInterval(h),r.off("pong",f))},"stop");r.on("pong",f);const h=setInterval(()=>{if(Date.now()-a>i){o=!0;return}if(!o){m(),r.terminate();return}o=!1;try{r.ping()}catch{m(),r.terminate()}},e);return h.unref(),{stop:m,noteActivity:s(()=>{a=Date.now()},"noteActivity")}}s(W,"startRemoteAttachHeartbeat");function b(r){const e=Buffer.from(r,"utf8");return e.byteLength<=123?r:e.subarray(0,123).toString("utf8")}s(b,"clampReason");function u(r,e,i,o,n){const a=JSON.stringify({error:{code:o,message:n}}),f=`HTTP/1.1 ${e} ${i}\r
|
|
2
2
|
content-type: application/json; charset=utf-8\r
|
|
3
3
|
content-length: ${Buffer.byteLength(a)}\r
|
|
4
4
|
connection: close\r
|
|
5
5
|
\r
|
|
6
|
-
`+a;try{r.end(f)}catch{try{r.destroy()}catch{}}}s(u,"refuseUpgrade");function
|
|
6
|
+
`+a;try{r.end(f)}catch{try{r.destroy()}catch{}}}s(u,"refuseUpgrade");function j(r){if(new URL(r.url??"/","http://127.0.0.1").searchParams.get("revive")==="0")return!0;const i=r.headers["x-crtr-attach-revive"];return(Array.isArray(i)?i[0]:i)==="0"}s(j,"reviveOptedOut");function q(r){return new URL(r.url??"/","http://127.0.0.1").searchParams.get("wakeParked")==="1"}s(q,"wakeParkedRequested");function E(r){return r===1e3||r===1001||r===1005}s(E,"isCleanViewerClose");function z(r,e){if(!A(e)){try{r.close(1008,b(`invalid node id: ${e}`))}catch{}return}if(S(e)===null){try{r.close(1011,b(`no node ${e}`))}catch{}return}v(e,{link:"viewer\u2194crtrd"});const i=P(e),o=new x(T);let n=!1,a=!1,f,m=!1,h=!1,d=!1;i.on("connect",()=>{m=!0,!n&&d&&_(e,r),v(e,{link:"relay\u2194broker"})});const p=s((t,l)=>{if(!n){if(n=!0,V(e,r),f?.stop(),!i.destroyed)try{i.destroy()}catch{}try{r.close(t,b(l))}catch{}}},"teardown");f=W(r),i.on("data",t=>{f?.noteActivity();let l;try{l=o.push(t)}catch(c){const y=c instanceof B?`broker sent an oversized frame (${c.message})`:`failed to decode a broker frame for ${e}`;p(1009,y);return}for(const c of l)if(r.readyState===r.OPEN&&(r.send(JSON.stringify(c)),d&&c?.type==="welcome"&&L(e,r)))try{N(e)}catch{}}),i.on("error",t=>{const l=k("relay\u2194broker",t);g(e,{link:"relay\u2194broker",op:"bridge socket",kind:l.kind,retry:{disposition:"manual"},message:t.message});const c=t.code==="ECONNREFUSED"||t.code==="ENOENT"?`no running broker for ${e}`:`view socket error for ${e}: ${t.message}`;p(1011,c)}),i.on("close",t=>{n||t||(v(e,{link:"relay\u2194broker"}),p(1e3,"broker socket closed"))}),r.on("close",(t,l)=>{const c=l.toString("utf8");if(n){E(t)&&v(e,{link:"viewer\u2194crtrd"});return}if(E(t))v(e,{link:"viewer\u2194crtrd"});else if(!a){a=!0;const y=k("viewer\u2194crtrd",{code:t,reason:c});g(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:y.kind,retry:{disposition:"auto"},message:c||`remote attach closed (${t})`})}p(t,c||`remote attach closed (${t})`)}),r.on("error",()=>{if(!a){a=!0;const t=k("viewer\u2194crtrd",{code:1006,reason:"remote attach websocket error"});g(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:t.kind,retry:{disposition:"auto"},message:"remote attach websocket error"})}p(1011,"remote attach websocket error")}),r.on("message",t=>{if(n||i.destroyed)return;f?.noteActivity();const c=(Array.isArray(t)?Buffer.concat(t):Buffer.isBuffer(t)?t:Buffer.from(new Uint8Array(t))).toString("utf8");if(!h)try{const w=JSON.parse(c);w?.type==="hello"&&(h=!0,d=w.attends!==!1,d&&m&&_(e,r))}catch{}const y=c.endsWith(`
|
|
7
7
|
`)?c:c+`
|
|
8
|
-
`;try{i.write(y)}catch{}})}s(
|
|
8
|
+
`;try{i.write(y)}catch{}})}s(z,"bridgeConnection");async function ne(r,e,i,o){e.on("error",()=>{});try{if(!A(o)){u(e,400,"Bad Request","invalid_node_id",`invalid node id: ${o}`);return}if(S(o)===null){u(e,404,"Not Found","node_not_found",`no node ${o}`);return}if(j(r)){if(!await F(o,250)){u(e,409,"Conflict","node_dormant",`node ${o} is dormant and revive was opted out (?revive=0)`);return}}else{let n;try{const a=await O(o,{resume:!0,capacity:"refuse"},q(r));if(a.parked){u(e,409,"Conflict","node_dormant",`node ${o} is parked; attach with ?wakeParked=1 to wake it`);return}n=a.result.launch?.exited}catch(a){const f=a instanceof Error?a.message:String(a);u(e,409,"Conflict","attach_revive_failed",`attach revive failed: ${f}`);return}if(!await U(o,n)){u(e,409,"Conflict","broker_not_ready",`broker view socket for ${o} did not become listenable after revive`);return}}if(e.destroyed)return;H.handleUpgrade(r,e,i,n=>z(n,o))}catch(n){const a=n instanceof Error?n.message:String(n);if(D(n)){u(e,400,"Bad Request","invalid_request",a);return}u(e,500,"Internal Server Error","internal",`attach upgrade failed: ${a}`)}}s(ne,"handleAttachUpgrade");export{M as REMOTE_ATTACH_HEARTBEAT_MS,J as REMOTE_ATTACH_QUIET_MS,ne as handleAttachUpgrade,E as isCleanViewerClose,u as refuseUpgrade,W as startRemoteAttachHeartbeat};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var w=Object.defineProperty;var i=(r,e)=>w(r,"name",{value:e,configurable:!0});import{ApiError as E}from"../../../api/errors.js";import{getNode as I}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as S}from"../../../core/canvas/executions.js";import{admitEpisode as T,clearEpisode as q,clearFault as h,closeTurn as
|
|
1
|
+
var w=Object.defineProperty;var i=(r,e)=>w(r,"name",{value:e,configurable:!0});import{ApiError as E}from"../../../api/errors.js";import{getNode as I}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as S}from"../../../core/canvas/executions.js";import{admitEpisode as T,clearEpisode as q,clearFault as h,closeTurn as P,invalidateEpisode as R,openTurn as v,parseProviderError as F,readEpisode as A,readFault as l,recordFault as b,recordPendingEpisode as N,recordTransportPoisonVerdict as O,recordTurnProgress as j,reopenEpisode as L}from"../../../core/canvas/recovery.js";import{notFound as D,usage as n}from"../../../core/errors.js";import{hasPresentedViewer as B}from"../viewer-presence.js";import{ownerOnly as g}from"../router.js";const f=new Set(["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"]),$=new Set(["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"]),C=new Set(["auto","manual","fatal"]),K=new Set(["sdk","daemon","client"]);function d(r,e){if(typeof r!="object"||r===null||Array.isArray(r))throw n(`${e} requires a JSON object`);return r}i(d,"objectBody");function a(r){if(I(r)===null)throw D(`unknown node: ${r}`,{received:r})}i(a,"requireNode");function u(r,e){if(typeof e!="string"||e==="")throw n("expected_execution_id must be a non-empty string");const t=S(r);if(t===null||t.executionId!==e)throw new E(409,"stale_execution","broker execution is no longer current")}i(u,"requireCurrentExecution");function x(r){if(typeof r!="object"||r===null||Array.isArray(r))throw n("retry must be an object");const e=r;if(!C.has(e.disposition))throw n("retry.disposition must be auto, manual, or fatal");if(e.by!==void 0&&!K.has(e.by))throw n("retry.by must be sdk, daemon, or client");for(const t of["attempt","max"])if(e[t]!==void 0&&(!Number.isSafeInteger(e[t])||e[t]<0))throw n(`retry.${t} must be a non-negative safe integer`);if(e.nextAt!==void 0&&typeof e.nextAt!="string")throw n("retry.nextAt must be a string");return e}i(x,"parseRetry");function _(r){const e=d(r,"fault input");if(!f.has(e.link))throw n("fault link is invalid");if(typeof e.op!="string"||e.op==="")throw n("fault op must be a non-empty string");if(!$.has(e.kind))throw n("fault kind is invalid");if(typeof e.message!="string")throw n("fault message must be a string");if(e.operation_id!==void 0&&(typeof e.operation_id!="string"||e.operation_id===""))throw n("operation_id must be a non-empty string");if(e.since!==void 0&&typeof e.since!="string")throw n("since must be a string");if(e.anchor_entry_id!==void 0&&(typeof e.anchor_entry_id!="string"||e.anchor_entry_id===""))throw n("anchor_entry_id must be a non-empty string");const t=e.provider_error===void 0?void 0:F(e.provider_error);if(e.provider_error!==void 0&&t===void 0)throw n("provider_error is invalid");return{...e,...t===void 0?{}:{provider_error:t},retry:x(e.retry)}}i(_,"parseFaultInput");function y(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,...r.operation_id===void 0?{}:{operation_id:r.operation_id},...r.since===void 0?{}:{since:r.since},...r.anchor_entry_id===void 0?{}:{anchorEntryId:r.anchor_entry_id},...r.provider_error===void 0?{}:{providerError:r.provider_error}}}i(y,"faultInput");function c(r){return{fault_id:r.faultId,link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,since:r.since,operation_id:r.operation_id,...r.anchorEntryId===void 0?{}:{anchor_entry_id:r.anchorEntryId},...r.providerError===void 0?{}:{provider_error:r.providerError}}}i(c,"faultDto");function k(r){const e=l(r),t=A(r);return{fault:e===null?null:c(e),episode:t===null?null:{state:t.state,session_id:t.sessionId,fault:c(t.fault)}}}i(k,"recoveryState");function U(r){const e=d(r,"broker turn"),t=e.event;if(t!=="started"&&t!=="progress"&&t!=="closed"&&t!=="interrupted"&&t!=="exit-diagnostic")throw n("event is invalid");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(t==="closed"){if(e.end_reason!=="settled"&&e.end_reason!=="teardown-aborted")throw n("closed turn requires end_reason settled or teardown-aborted")}else if(e.end_reason!==void 0)throw n("end_reason is valid only for closed turns");if(t==="exit-diagnostic"){const o=d(e.exit_diagnostic,"exit_diagnostic"),s=d(o.transport_poison,"exit_diagnostic.transport_poison");if(o.schema!=="crtr.execution-exit-diagnostic/v1"||!Number.isSafeInteger(s.consecutive_passes)||s.consecutive_passes<1||!Array.isArray(s.routes)||s.routes.length===0||!s.routes.every(p=>typeof p=="string"&&p!==""))throw n("exit_diagnostic is invalid")}else if(e.exit_diagnostic!==void 0)throw n("exit_diagnostic is valid only for exit-diagnostic turns");return e}i(U,"parseTurn");function V(r){const e=r.params.id;a(e);const t=U(r.body);u(e,t.expected_execution_id);let o;switch(t.event){case"started":o=v(t.expected_execution_id,{reason:"agent-start"});break;case"interrupted":o=v(t.expected_execution_id,{reason:"prompt-unsettled"});break;case"progress":o=j(t.expected_execution_id);break;case"closed":o=P(t.expected_execution_id,{endReason:t.end_reason,viewerPresent:B(e)});break;case"exit-diagnostic":{const m=t.exit_diagnostic.transport_poison;o=O(t.expected_execution_id,{consecutivePasses:m.consecutive_passes,routes:m.routes});break}}const s=l(e)?.link;return{status:200,body:{applied:o,fault_link:s==="daemon\u2192node"||s==="pi\u2192provider"?s:null}}}i(V,"handleTurn");function Y(r){const e=d(r,"provider retry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(!["record-pending","admit","reopen","invalidate","clear"].includes(e.op))throw n("provider retry op is invalid");if(typeof e.session_id!="string"||e.session_id==="")throw n("session_id must be a non-empty string");if(e.op==="record-pending"&&(e.input=_(e.input)),e.op==="admit"){if(typeof e.fault_id!="string"||e.fault_id==="")throw n("admit requires fault_id");e.retry=x(e.retry)}return e}i(Y,"parseProviderRetry");function G(r){const e=r.params.id;a(e);const t=Y(r.body);u(e,t.expected_execution_id);let o;switch(t.op){case"record-pending":o=N(e,{sessionId:t.session_id,input:y(t.input)})!==null;break;case"admit":o=T(e,{sessionId:t.session_id,faultId:t.fault_id,retry:t.retry});break;case"reopen":o=L(e,{sessionId:t.session_id});break;case"invalidate":o=R(e,{sessionId:t.session_id});break;case"clear":o=q(e,{sessionId:t.session_id});break}return{status:200,body:{applied:o,episode:k(e).episode}}}i(G,"handleProviderRetry");function J(r){const e=d(r,"broker fault");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(e.op!=="record"&&e.op!=="clear")throw n("fault op must be record or clear");if(e.op==="record"&&(e.input=_(e.input)),e.op==="clear"&&e.link!==void 0&&!f.has(e.link))throw n("fault link is invalid");if(e.preserve_episode!==void 0&&typeof e.preserve_episode!="boolean")throw n("preserve_episode must be boolean");return e}i(J,"parseBrokerFault");function W(r){const e=r.params.id;a(e);const t=J(r.body);u(e,t.expected_execution_id);const o=t.op==="record"?b(e,y(t.input)):(h(e,{...t.link===void 0?{}:{link:t.link},...t.preserve_episode===void 0?{}:{preserveEpisode:t.preserve_episode}}),l(e));return{status:200,body:{fault:o===null?null:c(o)}}}i(W,"handleBrokerFault");function z(r){const e=r.params.id;return a(e),u(e,r.query.get("expected_execution_id")),{status:200,body:k(e)}}i(z,"handleRecovery");function H(r){const e=r.params.id;a(e);const t=b(e,y(_(r.body)));return{status:200,body:{fault:t===null?null:c(t)}}}i(H,"handleNodeFaultRecord");function M(r){const e=r.params.id;a(e);const t=r.query.get("link");if(t!==null&&!f.has(t))throw n("fault link is invalid");const o=r.query.get("preserve_episode");if(o!==null&&o!=="true"&&o!=="false")throw n("preserve_episode must be true or false");return{status:200,body:{cleared:h(e,{...t===null?{}:{link:t},...o===null?{}:{preserveEpisode:o==="true"}})}}}i(M,"handleNodeFaultClear");const ie=g([{method:"POST",pattern:"/v1/broker/:id/turn",handler:V},{method:"POST",pattern:"/v1/broker/:id/provider-retry",handler:G},{method:"POST",pattern:"/v1/broker/:id/fault",handler:W},{method:"GET",pattern:"/v1/broker/:id/recovery",handler:z}]),se=g([{method:"POST",pattern:"/v1/nodes/:id/fault",handler:H},{method:"DELETE",pattern:"/v1/nodes/:id/fault",handler:M}]);export{ie as brokerRecoveryRoutes,se as nodeFaultRoutes,u as requireCurrentExecution};
|