@halcyonlabs/app 0.47.0-halcyon.208 → 0.47.0-halcyon.210
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/index.d.ts
CHANGED
|
@@ -7459,8 +7459,8 @@ declare const hostDaemonCommandRegistry: {
|
|
|
7459
7459
|
skillFilePath: z$1.ZodString;
|
|
7460
7460
|
}, z$1.core.$strict>], "kind">>;
|
|
7461
7461
|
instructionMode: z$1.ZodEnum<{
|
|
7462
|
-
append: "append";
|
|
7463
7462
|
replace: "replace";
|
|
7463
|
+
append: "append";
|
|
7464
7464
|
}>;
|
|
7465
7465
|
type: z$1.ZodLiteral<"thread.rewind.prepare">;
|
|
7466
7466
|
leaseId: z$1.ZodString;
|
|
@@ -7608,8 +7608,8 @@ declare const hostDaemonCommandRegistry: {
|
|
|
7608
7608
|
skillFilePath: z$1.ZodString;
|
|
7609
7609
|
}, z$1.core.$strict>], "kind">>;
|
|
7610
7610
|
instructionMode: z$1.ZodEnum<{
|
|
7611
|
-
append: "append";
|
|
7612
7611
|
replace: "replace";
|
|
7612
|
+
append: "append";
|
|
7613
7613
|
}>;
|
|
7614
7614
|
type: z$1.ZodLiteral<"thread.start">;
|
|
7615
7615
|
requestId: z$1.ZodString;
|
|
@@ -8072,8 +8072,8 @@ declare const hostDaemonCommandRegistry: {
|
|
|
8072
8072
|
envPassthrough: z$1.ZodArray<z$1.ZodString>;
|
|
8073
8073
|
}, z$1.core.$strict>;
|
|
8074
8074
|
instructionMode: z$1.ZodEnum<{
|
|
8075
|
-
append: "append";
|
|
8076
8075
|
replace: "replace";
|
|
8076
|
+
append: "append";
|
|
8077
8077
|
}>;
|
|
8078
8078
|
projectId: z$1.ZodString;
|
|
8079
8079
|
providerId: z$1.ZodString;
|
|
@@ -8288,8 +8288,8 @@ declare const hostDaemonCommandRegistry: {
|
|
|
8288
8288
|
envPassthrough: z$1.ZodArray<z$1.ZodString>;
|
|
8289
8289
|
}, z$1.core.$strict>;
|
|
8290
8290
|
instructionMode: z$1.ZodEnum<{
|
|
8291
|
-
append: "append";
|
|
8292
8291
|
replace: "replace";
|
|
8292
|
+
append: "append";
|
|
8293
8293
|
}>;
|
|
8294
8294
|
projectId: z$1.ZodString;
|
|
8295
8295
|
providerId: z$1.ZodString;
|
|
@@ -9195,9 +9195,9 @@ declare const hostDaemonCommandRegistry: {
|
|
|
9195
9195
|
base64: "base64";
|
|
9196
9196
|
utf8: "utf8";
|
|
9197
9197
|
}>;
|
|
9198
|
-
mimeType: z$1.ZodOptional<z$1.ZodString>;
|
|
9199
|
-
sizeBytes: z$1.ZodNumber;
|
|
9200
9198
|
sha256: z$1.ZodString;
|
|
9199
|
+
sizeBytes: z$1.ZodNumber;
|
|
9200
|
+
mimeType: z$1.ZodOptional<z$1.ZodString>;
|
|
9201
9201
|
modifiedAtMs: z$1.ZodOptional<z$1.ZodNumber>;
|
|
9202
9202
|
notModified: z$1.ZodLiteral<true>;
|
|
9203
9203
|
}, z$1.core.$strip>]>, "onlineRpc", true>;
|
|
@@ -9462,10 +9462,10 @@ declare const hostDaemonCommandRegistry: {
|
|
|
9462
9462
|
health: z$1.ZodObject<{
|
|
9463
9463
|
status: z$1.ZodEnum<{
|
|
9464
9464
|
unknown: "unknown";
|
|
9465
|
+
ready: "ready";
|
|
9465
9466
|
not_installed: "not_installed";
|
|
9466
9467
|
unauthenticated: "unauthenticated";
|
|
9467
9468
|
expired: "expired";
|
|
9468
|
-
ready: "ready";
|
|
9469
9469
|
unsupported_version: "unsupported_version";
|
|
9470
9470
|
}>;
|
|
9471
9471
|
statusMessage: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -9513,9 +9513,9 @@ declare const hostDaemonCommandRegistry: {
|
|
|
9513
9513
|
executablePath: z$1.ZodNullable<z$1.ZodString>;
|
|
9514
9514
|
installed: z$1.ZodBoolean;
|
|
9515
9515
|
installSource: z$1.ZodEnum<{
|
|
9516
|
-
external: "external";
|
|
9517
9516
|
notInstalled: "notInstalled";
|
|
9518
9517
|
npmGlobal: "npmGlobal";
|
|
9518
|
+
external: "external";
|
|
9519
9519
|
}>;
|
|
9520
9520
|
currentVersion: z$1.ZodNullable<z$1.ZodString>;
|
|
9521
9521
|
latestVersion: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -9961,8 +9961,8 @@ declare const hostDaemonCommandRegistry: {
|
|
|
9961
9961
|
message: z$1.ZodNullable<z$1.ZodString>;
|
|
9962
9962
|
state: z$1.ZodNullable<z$1.ZodEnum<{
|
|
9963
9963
|
pending: "pending";
|
|
9964
|
-
ready: "ready";
|
|
9965
9964
|
activating: "activating";
|
|
9965
|
+
ready: "ready";
|
|
9966
9966
|
}>>;
|
|
9967
9967
|
}, z$1.core.$strict>, "onlineRpc", true>;
|
|
9968
9968
|
"server_move.prepare": HostDaemonCommandDescriptor<"server_move.prepare", z$1.ZodObject<{
|
|
@@ -10064,9 +10064,9 @@ declare const providerCliStatusResponseSchema: z$1.ZodRecord<z$1.ZodString, z$1.
|
|
|
10064
10064
|
executablePath: z$1.ZodNullable<z$1.ZodString>;
|
|
10065
10065
|
installed: z$1.ZodBoolean;
|
|
10066
10066
|
installSource: z$1.ZodEnum<{
|
|
10067
|
-
external: "external";
|
|
10068
10067
|
notInstalled: "notInstalled";
|
|
10069
10068
|
npmGlobal: "npmGlobal";
|
|
10069
|
+
external: "external";
|
|
10070
10070
|
}>;
|
|
10071
10071
|
currentVersion: z$1.ZodNullable<z$1.ZodString>;
|
|
10072
10072
|
latestVersion: z$1.ZodNullable<z$1.ZodString>;
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a661183259b3c0ab651b77a260b583fcc19d8fbe
|
|
@@ -446,7 +446,7 @@ if [ -f "$mail" ] && [ ! -L "$mail" ]; then
|
|
|
446
446
|
fi
|
|
447
447
|
sudo -u ${Ge(o)} mkdir -p ${Ge(`${s}/journal`)}
|
|
448
448
|
[ -e ${Ge(`${s}/open-loops.md`)} ] || sudo -u ${Ge(o)} sh -c ${Ge(`printf '# Open loops\\n\\n## Index\\n\\n## Done\\n' > ${s}/open-loops.md`)}`}),k=>k.code!==255);if(h.code!==0)throw new Error(`installing the Orbit conversation's directory: ${h.stderr.trim()}`);tr(e).assertLegacySync();let g=await Z8(e,r.id);if(g&&await J8(e,g))return tr(e).assertLegacySync(),await e.sdk.threads.update({threadId:g,title:en(c.identity)}).catch(()=>{}),g;g&&(await e.sdk.threads.unpin({threadId:g}).catch(()=>{}),e.log.warn(`the Orbit conversation ${g} isn't one Orbit started, so its quiet turns and Orbit's messages can't apply there; starting Orbit's own`)),tr(e).assertLegacySync();let w=await e.sdk.threads.spawn({projectId:n,title:en(c.identity),prompt:l?X8(en(c.identity),Mt(c.identity),l,r.name):K8(en(c.identity),Mt(c.identity)),environment:{type:"host",hostId:r.id,workspace:{type:"unmanaged",path:Rc}},...$s(vi,!0),model:c.models.orbit,pinned:!0});return await dS(e,w.id),e.log.info(`started the Orbit conversation ${w.id} on ${r.name}`),w.id}i(JD,"ensureFront");function ot(e,t,r,n){let s=!1;e.background.schedule(t,r,()=>{s||(s=!0,Promise.resolve().then(n).catch(o=>e.log.warn(`${t}: ${o instanceof Error?o.message:String(o)}`)).finally(()=>{s=!1}))})}i(ot,"scheduleInBackground");import{z as Ds}from"zod";import{createHash as PX}from"node:crypto";var fS=new Map([["orbit",new Set(["route spawn","route tell","schedule add","schedule list","schedule cancel","prefs show","prefs propose","changes propose","changes list","changes show","changes withdraw","changes undo","threads list","threads start","threads archive","thread outcome","thread reply","relay","messages send","messages list","messages read","messages mark-read","messages reply","say","wakes","loops show","loops next"])]]),At="ORB",pS=/^ORB-[1-9][0-9]{0,8}$/,iX=/^[a-z]+(-[a-z]+)*$/,ZD=32,sv={list:{on:"project",values:["--status","--priority","--label","--search","--sort","--limit"],switches:["--active","--json"],required:[]},show:{on:"key",values:[],switches:["--json"],required:[]},create:{on:"project",values:["--title","--description","--priority","--label","--due","--parent"],switches:["--json"],required:["--title"]},update:{on:"key",values:["--status","--priority","--title","--description","--due","--add-label","--remove-label","--parent"],switches:["--no-due","--json"],required:[]},comment:{on:"key",values:["--body"],switches:["--json"],required:["--body"]},"label list":{on:"project",values:[],switches:["--json"],required:[]},"label create":{on:"project",values:["--name"],switches:["--json"],required:["--name"]}};function hS(e){if(e[0]==="show"&&e.some(l=>l==="--compact"||l==="--comments")){let l=e[1];if(l&&pS.test(l)&&e[2]==="--compact"&&(e.length===3||e.length===5&&e[3]==="--comments"&&/^(?:[1-9]|1[0-9]|20)$/.test(e[4])))return;ve("Use bb tasks show ORB-<n> --compact [--comments 1..20].")}let t=e[0]==="label"?2:1,r=e.length>=t?e.slice(0,t).join(" "):void 0,n=e.slice(t),s=r!==void 0&&Object.hasOwn(sv,r)?sv[r]:void 0;s||ve(`of bb tasks, station runs only ${Object.keys(sv).join(", ")}, in the ${At} project`);let o,a=0,c=new Set;for(let l=0;l<n.length;l++){let u=n[l];if(!u.startsWith("-")){(s.on!=="key"||o!==void 0)&&ve(`bb tasks ${r} takes no argument ${JSON.stringify(u)}`),pS.test(u)||ve(`bb tasks ${r} works only on ${At}-<n> tasks, not ${JSON.stringify(u)}`),o=u;continue}if(s.on==="project"&&u==="--project"){n[++l]!==At&&ve(`bb tasks ${r} works only in the ${At} project`),a+=1;continue}if(s.switches.includes(u))continue;s.values.includes(u)||ve(`bb tasks ${r}: ${u} isn't open to station`);let d=n[++l];(d===void 0||d.startsWith("-"))&&ve(`bb tasks ${r}: ${u} takes one value, not starting with -`),u==="--parent"&&!pS.test(d)&&ve(`bb tasks ${r}: --parent is a ${At}-<n> task, not ${JSON.stringify(d)}`),u==="--name"&&c.has(u)&&ve(`bb tasks ${r}: one --name`),u==="--name"&&!(iX.test(d)&&d.length<=ZD)&&ve(`bb tasks ${r}: --name is plain lowercase words, at most ${ZD} characters, not ${JSON.stringify(d)}`),c.add(u)}s.on==="key"&&o===void 0&&ve(`bb tasks ${r} names its task, ${At}-<n>`),s.on==="project"&&a!==1&&ve(`bb tasks ${r} takes --project ${At}, once`);for(let l of s.required)c.has(l)||ve(`bb tasks ${r} needs ${l}`)}i(hS,"checkTaskArgv");var ov={"agent-board":[["show","<thread>"],["show","<thread>","--json"]],"host-monitor":[["snapshot"],["snapshot","--pretty"]]},sX=/^thr_[a-z0-9]+$/;function mS(e){let t=ov[e]??[],r=t.map(n=>`\`${e} ${n.join(" ")}\``).join(", ");return n=>{let s=i(o=>o.length===n.length&&o.every((a,c)=>a==="<thread>"?sX.test(n[c]):a===n[c]),"fits");t.some(s)||ve(`of the ${e} plugin's CLI, station runs only ${r}`)}}i(mS,"readOnlyArgv");var gS="send_operator_inbox_message",yS="The operator inbox is retired. Send questions to the Orbit assistant in your report or a message to the Orbit thread; it asks the owner once, batched, in chat and Waiting for you.",wS=new Map;function oX(e){let{protected:t,...r}=e.station;return{...e,station:r}}i(oX,"own");function Yf(e){return(!e||typeof e!="object"||Array.isArray(e))&&ve("a protected request needs an object"),e}i(Yf,"bodyObject");function vS(e){let t=e.protected;(!t||!["front","canary"].includes(t.role)||t.threadId!==null&&!/^thr_[a-z0-9]+$/.test(t.threadId))&&ve("protected conversation selection unavailable"),e.sharedProjectIds?.size&&ve("a private project cannot have shared sources");let r=new Set([e.hostId]);(!/^host_[a-z0-9]+$/.test(e.hostId)||t.jobs.length>20)&&ve("protected job destinations unavailable");for(let n of t.jobs)(!/^host_[a-z0-9]+$/.test(n.hostId)||r.has(n.hostId)||"protected"in n)&&ve("protected job destinations unavailable"),r.add(n.hostId),[...n.projectIds,...n.sharedProjectIds??[]].some(s=>e.projectIds.has(s))&&ve("private project is also a job destination");return t.jobs}i(vS,"profileStations");async function QD(e,t){let r=vS(t.station),n=t.station.protected,s=oX(t),o=bS(e.path),{method:a,path:c,body:l}=e;if(a==="GET"&&["/health","/install/version","/install/bb-app.tgz","/install.sh"].includes(c))return{gateAuth:!1};if(o[0]==="internal"){let u=new Set(["/internal/hosts/enroll","/internal/session/open","/internal/session/events","/internal/session/interactive-request","/internal/session/interactive-request/interrupt","/internal/session/tool-call"]),d=/^\/internal\/plugins\/(provider-claude-code|provider-codex)\/host\/[a-f0-9]{64}$/.test(c),f=/^\/internal\/skills\/tree\/[a-zA-Z0-9_.-]+$/.test(c),p=c==="/internal/ws"||c==="/internal/session/project-attachment-content"||d||f;if(a==="POST"&&u.has(c)||a==="GET"&&p||ve("internal route is not part of the protected runtime"),a==="POST"){let m=Yf(l);m.hostId!==void 0&&m.hostId!==t.station.hostId&&ve("another daemon identity")}if(c==="/internal/session/project-attachment-content"){let m=new URLSearchParams(e.search);(m.getAll("threadId").length!==1||!n.threadId||m.get("threadId")!==n.threadId||m.getAll("projectId").length!==1||!t.station.projectIds.has(m.get("projectId")))&&ve("another conversation's attachment")}if(c==="/internal/session/tool-call"){let m=Yf(l);(!n.threadId||m.threadId!==n.threadId)&&ve("only the selected protected conversation calls tools"),t.agentTools.has(m.tool)&&ve("the protected workspace is fixed by the server")}return Pi(e,s)}if((o[0]!=="api"||o[1]!=="v1")&&ve("not part of the protected conversation API"),o[2]==="threads"&&o.length===3&&a==="POST"){let u=Yf(l),d=Yf(u.environment),f=r.find(m=>m.hostId===d.hostId);(!f||d.type!=="host")&&ve("work needs an explicit existing job machine"),(!n.threadId||u.parentThreadId!==n.threadId)&&ve("work needs the selected conversation as parent"),u.lifecycleOwnerThreadId!==void 0&&u.lifecycleOwnerThreadId!==n.threadId&&ve("another lifecycle owner"),u.senderThreadId!==void 0&&u.senderThreadId!==n.threadId&&ve("only the selected conversation sends work");let p={...u};return delete p.parentThreadId,delete p.lifecycleOwnerThreadId,delete p.senderThreadId,Pi({...e,body:p},{...t,station:f})}if(o[2]==="threads"&&o[3]&&ci.test(o[3])){let u=o[3];if(u===n.threadId)return a!=="GET"&&ve("the protected conversation is controlled by the server"),Pi(e,s);let d=await t.threadHost(u),f=r.find(p=>p.hostId===d);return f||ve("thread is outside the protected conversation's job destinations"),Pi(e,{...t,station:f})}if(o[2]==="plugins"&&o[4]==="cli"&&o.length===5&&a==="POST")return(!n.threadId||Yf(l).threadId!==n.threadId)&&ve("a protected plugin command names the selected conversation"),Pi(e,s);if(a==="GET"&&o.length===3&&["threads","threads/running","projects","environments","queued-messages"].includes(o[2]))return Pi(e,s);if(a==="GET"&&c==="/api/v1/threads/running")return Pi(e,s);if(a==="GET"&&o[2]==="projects"&&o[3]){let u=r.find(d=>d.projectIds.has(o[3]));if(u)return Pi(e,{...t,station:u})}if(a==="GET"&&o[2]==="environments"&&o[3]){let u=await t.environmentHost(o[3]),d=r.find(f=>f.hostId===u);if(d)return Pi(e,{...t,station:d})}if(a==="GET"&&_S.has(o.slice(2).join("/")))return Pi(e,s);ve("route is not open to the protected conversation")}i(QD,"protectedDecision");async function av(e,t,r){if("protected"in r.station)return aX(e,t,r);Array.isArray(t)||ve(`bb answered ${e} with something other than a list`);let n=i(o=>o!==null&&typeof o=="object"?o:{},"record"),s=i(o=>{let a=n(o),c=n(a.environment);return(a.environmentHostId??c.hostId)===r.station.hostId},"onStation");switch(e){case"threads":return t.filter(s);case"threads/running":case"environments":return t.filter(o=>n(o).hostId===r.station.hostId);case"projects":return t.filter(o=>r.station.projectIds.has(n(o).id)).map(o=>{let a=n(o);return Array.isArray(a.threads)?{...a,threads:a.threads.filter(s)}:a});case"queued-messages":{let o=[];for(let a of t){let c=n(a).threadId;typeof c=="string"&&ci.test(c)&&await r.threadHost(c)===r.station.hostId&&o.push(a)}return o}}}i(av,"filterList");async function aX(e,t,r){let n=vS(r.station),s=r.station.protected,{protected:o,...a}=r.station,c=i(d=>d!==null&&typeof d=="object"?d:{},"record"),l=[];for(let d of[a,...n]){let f=await av(e,t,{...r,station:d}),p=d.hostId===a.hostId;for(let m of f){let y=c(m);p&&["threads","threads/running","queued-messages"].includes(e)&&(y.threadId??y.id)!==s.threadId||p&&e==="environments"||(e==="projects"&&Array.isArray(y.threads)&&p?l.push({...y,threads:y.threads.filter(h=>c(h).id===s.threadId)}):l.push(m))}}let u=new Set;return l.filter(d=>{let f=c(d).id;return typeof f!="string"?!0:u.has(f)?!1:(u.add(f),!0)})}i(aX,"protectedList");var ci=/^([a-z]+)_[a-z0-9]+$/,Pe=class extends Error{static{i(this,"Deny")}};function ve(e){throw new Pe(e)}i(ve,"deny");function bS(e){e.startsWith("/")||ve("not an origin-form path"),/^[A-Za-z0-9\-._~!$&'()*+,;=:@%/]+$/.test(e)||ve("characters outside a URL path");let t=e.slice(1).split("/"),r=!1;return t.forEach((n,s)=>{(n===""||n==="."||n===".."||/%(2e|2f|5c)/i.test(n))&&ve(`unroutable path segment ${JSON.stringify(n)}`),!r&&n.includes("%")&&ve(`escaped route segment ${JSON.stringify(n)}`),s>=2&&(n==="files"||n==="host-files")&&(r=!0)}),t}i(bS,"segments");function cX(e){let t=new Map;for(let[r,n]of new URLSearchParams(e))t.has(r)&&ve(`duplicate query parameter ${r}`),t.set(r,n);return t}i(cX,"queryOf");var _S=new Set(["hosts","thread-sections","plugins","plugins/contributions","system/config","system/version","system/execution-options","system/providers","system/providers/state","system/providers/catalog","system/machine-providers","system/environment-providers"]),lX=new Set(["threads","threads/running","projects","environments","queued-messages"]),uX=new Set(["projectId","providerId","origin","lifecycleOwnerThreadId","visibility","title","input","model","serviceTier","reasoningLevel","permissionMode","executionInputSources","environment","parentThreadId","sectionId","pinned","sourceThreadId","sourceSeqEnd","startedOnBehalfOf","originKind","sendAt","senderThreadId","parentNotifications"]),dX=new Set(["sourceThreadId","sourceSeqEnd","input","agentContextSeed","title","permissionMode","visibility","environment","origin","lifecycleOwnerThreadId"]),pX=new Set(["cols","rows","start","target","title"]),fX=new Set(["hostId","path","rootPath","content","contentEncoding","createParents","expectedSha256","mode","query","limit","includeHidden","excludeNames","includeFiles","includeDirectories","recursive","sourcePath","destinationPath"]),hX=new Set(["read","write","list","paths","mkdir","move","remove"]),mX=new Set(["argv","cwd","threadId","projectId"]);function Ls(e,t){return(e===null||typeof e!="object"||Array.isArray(e))&&ve(`${t} needs a JSON object`),e}i(Ls,"objectBody");function Cs(e,t,r){for(let n of Object.keys(e))t.has(n)||ve(`${r}: unknown field ${n}`)}i(Cs,"onlyFields");async function Jf(e,t){return"protected"in t.station?QD(e,t):Pi(e,t)}i(Jf,"decide");async function Pi(e,t){let{method:r,path:n,search:s="",body:o}=e,a=bS(n);if(a[0]==="internal"){let f=a.slice(1).join("/");return f==="hosts/enroll-key"&&ve("enrollment keys are minted on the server's machine only"),f.startsWith("server-move")&&ve("server moves are the server machine's business"),f==="session/tool-call"&&await yX(o,t),{gateAuth:!1}}if(r==="GET"&&(n==="/health"||n==="/install.sh"||n==="/install/version"||n==="/install/bb-app.tgz"))return{gateAuth:!1};if(a[0]==="ws"&&a[1]==="terminals"&&a.length===3)return await kS(a[2],t),{gateAuth:!1};(a[0]!=="api"||a[1]!=="v1")&&ve("not part of bb's API");let l=r==="POST"&&a[2]==="plugins"&&a[4]==="cli"&&a.length===5&&t.pluginCommands?.has(a[3])&&o&&typeof o=="object"&&!Array.isArray(o)?{...o,argv:[]}:o,u=r==="POST"&&a.length===3&&a[2]==="threads";await vX(l,t,u);let d=await gX(r,a.slice(2),cX(s),o,t);return d?{gateAuth:!0,filter:d}:{gateAuth:!0}}i(Pi,"regularDecision");async function gX(e,t,r,n,s){let[o,a,...c]=t,l=c.join("/");if(o==="threads"&&c[0]==="interactions"&&c.length>=3&&["respond","resolve","cancel"].includes(c[2])&&ve("only the user answers interactions"),o==="threads"&&a&&ci.test(a)&&(e==="POST"&&l==="archive-all"||e==="DELETE"&&l===""))return await Aa(a,s),ej({thread:a},s);if(o==="environments"&&a&&ci.test(a)&&(e==="POST"&&(l==="archive-threads"||l==="cleanup")||e==="DELETE"&&l===""))return await Ku(a,s),ej({environment:a},s);if(o==="threads"&&a&&ci.test(a)&&e==="POST"&&(l==="send"||l==="queued-messages")){let d=n?.senderThreadId;if(typeof d=="string"){let f=await s.quietWorker?.(a,d);f&&ve(f)}}if(o==="threads"&&a&&ci.test(a))return Aa(a,s);if(o==="environments"&&a&&ci.test(a))return Ku(a,s);if(o==="terminals"&&a&&ci.test(a))return kS(a,s);if(o==="hosts"&&a){if(a!==s.station.hostId&&ve("another machine"),e==="GET"||e==="POST"&&l==="paths/exist")return;ve("machine management")}if(o==="projects"&&a){if(cv(a,s),c[0]==="hosts"&&c[1]!==s.station.hostId&&ve("another machine"),e==="GET"&&l!=="machine-environment"&&l!=="prompt-history"||e==="POST"&&(l==="attachments"||l==="attachments/copy"))return;ve("changing the project")}let u=t.join("/");if(!(e==="GET"&&_S.has(u))){if(e==="GET"&&lX.has(u))return u;if(e==="GET"&&u==="terminals"){if(r.get("hostId")===s.station.hostId)return;let d=r.get("threadId");if(d!==void 0)return Aa(d,s);let f=r.get("environmentId");if(f!==void 0)return Ku(f,s);ve("terminals on another machine")}if(e==="POST"&&u==="threads")return EX(n,s);if(e==="POST"&&u==="threads/fork"){let d=Ls(n,"a fork");Cs(d,dX,"a fork"),d.sourceThreadId===void 0&&ve("a fork needs its source"),d.origin==="plugin"&&ve("plugin-origin threads"),d.environment!==void 0&&await tj(d.environment,s);let f=await s.threadProvider(Zf(d.sourceThreadId,"thread"));(f===null||!lv.includes(f))&&ve(`a fork of a thread on ${f??"an unknown provider"}: station's threads run on ${lv.join(" or ")}`),nj(f,d.permissionMode,!0);return}if(!(e==="POST"&&u==="threads/resolve-mentions")){if(e==="POST"&&u==="terminals"){let d=Ls(n,"a terminal");return Cs(d,pX,"a terminal"),AX(d.target,s)}if(e==="POST"&&o==="files"&&t.length===2&&hX.has(a)){let d=Ls(n,"a file operation");Cs(d,fX,"a file operation"),d.hostId!==s.station.hostId&&ve("files on another machine (no hostId means the server's)");return}if(e==="POST"&&o==="plugins"&&t.length===3&&c[0]==="cli"){let d=Ls(n,"a plugin command");if(Cs(d,mX,"a plugin command"),s.pluginClis.has(a))return;let f=s.pluginArgv?.get(a);if(f){let h=d.argv;return(!Array.isArray(h)||!h.every(g=>typeof g=="string"))&&ve("a plugin command's argv must be words"),f(h)}let p=s.pluginCommands?.get(a);p||ve(`the ${a} plugin's CLI isn't allowed on station`),(typeof d.threadId!="string"||!d.threadId)&&ve("a plugin command from station names its thread");let m=d.argv;(!Array.isArray(m)||!m.every(h=>typeof h=="string"))&&ve("a plugin command's argv must be words");let y=m;if(!p.has(y.slice(0,2).join(" "))&&!p.has(y[0]??"")&&ve(`only ${[...p].map(h=>`\`${a} ${h}\``).join(", ")} of the ${a} plugin's CLI are open to station`),a==="orbit"&&(y[0]==="say"||y.slice(0,2).join(" ")==="thread reply")){let h=await s.quietWorker?.("owner",d.threadId);h&&ve(h)}return}ve(`${e} /${u} isn't open to station`)}}}i(gX,"apiRoute");async function yX(e,t){let r=e??{},n=r.tool;if(typeof n!="string"&&ve(`agent tool ${String(n)} isn't allowed on station`),n===gS&&ve(yS),t.agentTools.has(n)){await Aa(r.threadId,t);return}let s=t.stationTools?.get(n);if(s)return typeof r.threadId!="string"&&ve(`${n} is called by one of station's threads`),await Aa(r.threadId,t),s(r.arguments);ve(`agent tool ${n} isn't allowed on station`)}i(yX,"toolCall");var wX=new Set(["type","kind","mode"]);async function vX(e,t,r=!1){let n=[],s,o=i((a,c,l)=>{if(c>64&&ve("a body nested too deeply"),typeof a=="string"){if(l!==void 0&&wX.has(l))return;r&&c===1&&l==="projectId"?s=a:ci.test(a)&&n.push(a)}else if(Array.isArray(a))for(let u of a)o(u,c+1);else if(a!==null&&typeof a=="object")for(let[u,d]of Object.entries(a))(u==="pluginSubmission"||u==="pluginMetadata"||u==="originPluginId")&&ve(`plugin data (${u})`),o(d,c+1,u)},"walk");o(e,0),s!==void 0&&cv(s,t,!0);for(let a of new Set(n)){let c=ci.exec(a)[1];c==="thr"?await Aa(a,t):c==="env"?await Ku(a,t):c==="term"?await kS(a,t):c==="host"&&a!==t.station.hostId?ve(`machine ${a} isn't station`):c==="proj"?cv(a,t):c==="src"&&ve("project sources")}}i(vX,"references");function Zf(e,t){return(typeof e!="string"||!ci.test(e))&&ve(`bad ${t} id`),e}i(Zf,"checkedId");async function ej(e,t){t.archive||ve("archiving from station needs the unpushed work check");try{await t.archive(e)}catch(r){if(r instanceof Pe)throw r;ve(r.message)}}i(ej,"checkArchive");async function Aa(e,t){let r=Zf(e,"thread");await t.threadHost(r)!==t.station.hostId&&ve(`thread ${r} isn't on station`)}i(Aa,"ownThread");async function Ku(e,t){let r=Zf(e,"environment");await t.environmentHost(r)!==t.station.hostId&&ve(`environment ${r} isn't on station`)}i(Ku,"ownEnvironment");async function kS(e,t){let r=Zf(e,"terminal");await t.terminalHost(r)!==t.station.hostId&&ve(`terminal ${r} isn't on station`)}i(kS,"ownTerminal");function cv(e,t,r=!1){let n=Zf(e,"project");t.station.projectIds.has(n)||r&&t.station.sharedProjectIds?.has(n)||ve(`project ${n} isn't station's`)}i(cv,"ownProject");var ES="orbit-job-folder",bX=/^[a-z][a-z0-9-]*:[a-z0-9][a-z0-9_./:#-]{0,254}$/i,_X=/^ORB-[1-9][0-9]{0,8}$/;async function tj(e,t,r=!1){let n=Ls(e,"an environment");switch(n.type){case"provider":{if(!r)break;Cs(n,new Set(["type","environmentProviderId","machine","inputs"]),"an environment"),n.environmentProviderId!==ES&&ve(`environment provider ${String(n.environmentProviderId)} isn't open to station`);let s=Ls(n.machine,"a machine");if(Cs(s,new Set(["type","hostId"]),"a machine"),(s.type!=="existing"||s.hostId!==t.station.hostId)&&ve("a work folder on another machine"),n.inputs!==void 0){let o=Ls(n.inputs,"the inputs");Object.keys(o).some(a=>!["key","adopt","class","loop"].includes(a))&&ve("a work folder's inputs are the plugin's, except the work key, its class and its loop"),o.class!==void 0&&!["promised","repair","background"].includes(o.class)&&ve("a start's class is promised, repair or background"),o.loop!==void 0&&(typeof o.loop!="string"||!_X.test(o.loop))&&ve("a start's loop is an ORB task, like ORB-269"),o.key!==void 0&&(typeof o.key!="string"||!bX.test(o.key))&&ve("a work key is like orb-269:fix-1"),o.adopt!==void 0&&(typeof o.adopt!="string"||!/^\/./.test(o.adopt)||o.adopt.split("/").some(a=>a==="."||a===".."))&&ve("a checkout is an absolute path without parent steps")}return}case"host":Cs(n,new Set(["type","hostId","workspace"]),"an environment"),n.hostId!==t.station.hostId&&ve("a thread on another machine (no hostId means the server's)");return;case"reuse":return Cs(n,new Set(["type","environmentId"]),"an environment"),Ku(n.environmentId,t);case"project-default":Cs(n,new Set(["type"]),"an environment");return}ve(`environment type ${String(n.type)} isn't open to station`)}i(tj,"placement");var rj="claude-code",lv=[rj,"codex"];function nj(e,t,r){e!=="codex"||t===sa||ve(`a Codex thread with permission mode ${t===void 0?r?"left out (the fork would keep its source's, which may be from an earlier release setting)":"left out (bb would take auto)":String(t)}: station's Codex threads start with ${sa}, as in bb thread spawn --provider codex --permission-mode ${sa} (the station kernel enforces access; the release setting controls Codex approval questions)`)}i(nj,"stationPermission");function kX(e){e===void 0&&ve(`a thread that names no provider (bb would take the project's remembered one): station's threads name one, as in bb thread spawn --provider ${rj}`),(typeof e!="string"||!lv.includes(e))&&ve(`a thread on ${String(e)}: station's threads run on ${lv.join(" or ")}`)}i(kX,"stationProvider");async function EX(e,t){let r=Ls(e,"a thread");Cs(r,uX,"a thread"),r.senderThreadId!==void 0&&await Aa(r.senderThreadId,t),kX(r.providerId),nj(r.providerId,r.permissionMode,!1),cv(r.projectId,t,!0),r.origin==="plugin"&&ve("plugin-origin threads"),r.parentNotifications!==void 0&&r.parentNotifications!=="off"&&ve("parent notifications other than off"),!t.station.projectIds.has(r.projectId)&&Ls(r.environment,"an environment").type==="project-default"&&ve("a thread in a project with sources elsewhere is placed on station explicitly"),await tj(r.environment,t,!0)}i(EX,"createThread");async function AX(e,t){let r=Ls(e,"a terminal target");switch(r.kind){case"thread":return Aa(r.threadId,t);case"environment":return Ku(r.environmentId,t);case"host_path":r.hostId!==t.station.hostId&&ve("a terminal on another machine");return;default:ve("unknown terminal target")}}i(AX,"terminalTarget");import{z as un}from"zod";import{open as SX,rename as TX,unlink as xX}from"node:fs/promises";import{randomUUID as OX}from"node:crypto";import{resolve as AS}from"node:path";import{pathToFileURL as $X}from"node:url";var ij=new Set(["report.md","evidence.md","job.log"]);function SS(e){if(!Array.isArray(e))throw new Error("Declare outputs as a JSON list.");let t=[],r=0;for(let n of e){if(typeof n!="string"||Buffer.byteLength(n,"utf8")>4096||/[\u0000-\u001f\u007f\ud800-\udfff\\]/u.test(n)||n.split("/").some(s=>s===""||s==="."||s===".."))throw new Error("Output names must be relative file paths.");if(!ij.has(n)&&!n.startsWith("results/")&&!n.startsWith("logs/"))throw new Error("Extra files belong under results/ or logs/.");if(!t.includes(n)){if(t.some(s=>s.startsWith(n+"/")||n.startsWith(s+"/")))throw new Error("Output names cannot contain one another.");if(!ij.has(n)&&++r>32)throw new Error("Declare at most 32 extra output files.");t.push(n)}}return t}i(SS,"outputNames");async function IX(e,t){let r=SS(e),n=AS(t,".orbit-outputs-"+OX()),s=AS(t,".orbit-outputs.json"),o=await SX(n,"wx",384);try{await o.writeFile(JSON.stringify(r)+`
|
|
449
|
-
`),await o.sync(),await o.close(),await TX(n,s)}finally{await o.close(),await xX(n).catch(a=>{if(a.code!=="ENOENT")throw a})}return r}i(IX,"declareOutputs");if(process.argv[1]&&import.meta.url===$X(AS(process.argv[1])).href)try{if(process.argv.length!==3)throw new Error("Usage: node declare-outputs.mjs JSON_LIST (writes in the current folder)");await IX(JSON.parse(process.argv[2]),process.cwd())}catch(e){console.error(e.message),process.exitCode=1}var Hr=ES,sj=i(e=>PX("sha256").update(e).digest("hex").slice(0,32),"jobId"),RX=un.array(un.string()).superRefine((e,t)=>{try{SS(e)}catch(r){t.addIssue({code:"custom",message:r instanceof Error?r.message:"Invalid output names."})}}).default(["report.md","evidence.md","job.log"]),NX=un.string().regex(/^\/./).refine(e=>!e.split("/").some(t=>t==="."||t===".."),"Checkout paths cannot contain parent steps."),CX=un.object({outputs:RX,key:un.string().regex(lS).optional(),adopt:NX.optional()}).strict(),LX=new Set(["queued","admitted","running"]);function DX(e,t){return t.aborted?Promise.reject(t.reason):new Promise((r,n)=>{let s=i(()=>n(t.reason),"stop");t.addEventListener("abort",s,{once:!0}),e.then(o=>{t.removeEventListener("abort",s),r(o)})})}i(DX,"settled");function TS(e,t){return t.aborted?Promise.reject(t.reason):new Promise((r,n)=>{let s=setTimeout(()=>{t.removeEventListener("abort",o),r()},e),o=i(()=>{clearTimeout(s),n(t.reason)},"stop");t.addEventListener("abort",o,{once:!0})})}i(TS,"nap");var Sa=class extends Error{static{i(this,"CapacityFull")}},oj=un.object({checkouts:un.array(un.object({path:un.string(),branches:un.array(un.object({branch:un.string(),commits:un.number().int().positive()}).strict()),detached:un.number().int().nonnegative(),uncommitted:un.number().int().nonnegative(),untracked:un.number().int().nonnegative(),stashes:un.number().int().nonnegative()}).strict())}).strict(),aj=i(e=>e?/\/job-([a-f0-9]{32})$/.exec(e)?.[1]??null:null,"jobFolderId");function cj(e,t,r){let{items:n,admission:s}=r,o=new Map;function a(u,d,f,p){let m=u.key??`thread:${d.id.toLowerCase()}`,y=n.get(m);if(y){if(y.thread===null&&y.attempt>1&&typeof d.createdAt=="number"){let g=n.history(m).find(w=>w.attempt===y.attempt)?.at;if(g!==void 0&&d.createdAt<g)throw new Error(`@thread:${d.id} is from an earlier attempt of ${m}; it doesn't take attempt ${y.attempt}'s place.`)}}else{if(u.key)throw new Error(`The start's work item ${m} is missing; start it again.`);n.claim({key:m,host:f,mode:u.adopt?"checkout":"folder",class:"asked",loop:null,source:"station"})}let h=n.bind(m,d.id);return n.bindPath(p,m),h}i(a,"itemFor");async function c(u,d,f,p,m,y,h){let g=!1;try{for(;;){let w=await s.admit(u,p,m,()=>{g=!0},h),k=s.generation();n.recordJob(d,w.job),g||p.step(f);try{return await y(w.job),s.answered(u),g&&p.step(f),w.job}catch(x){if(!(x instanceof Sa))throw s.answered(u),x;g=!0,await s.refused(u,x.message,p,m,k)}}}finally{s.done(u)}}i(c,"admitted"),e.experimental_environments.register({id:Hr,displayName:"Orbit work folder",description:"A temporary work folder. Declared results are saved before bb removes it.",icon:"Folder",requires:{},inputs:CX,policy:{retireGraceMs:3e5,pathKeys:"per-attempt",experimental_cleanupFailedBeforeRun:!0,internal_DO_NOT_USE_removeChecksWorkspaceUse:!0},async availability({host:u}){try{return await t.location(u.id),{status:"available"}}catch{return{status:"unavailable",message:"This machine cannot create Orbit work folders."}}},async validate({host:u}){return await t.location(u.id),{action:"accept"}},async create({host:u,project:d,thread:f,pathKey:p,inputs:m,experimental_claimPath:y,signal:h,report:g}){let w=a(m,f,u.id,p);if(m.adopt){let I=m.adopt,O=i(j=>(n.get(w.key)?.state==="queued"&&(n.move(w.key,"sharing",j),s.wake()),{status:"created",path:I,ownsPath:!1,resource:{key:w.key}}),"share"),L=`${u.id}\0${d.id}\0${I}`,b=i(async()=>(await e.sdk.environments.list({hostId:u.id,path:I,limit:5})).find(j=>j.projectId===d.id&&(j.status==="ready"||j.status==="provisioning")),"here"),_=!1,A=null,E=i(()=>{},"resolveEntry"),D=i(()=>{A&&o.get(L)===A&&o.delete(L),E(!1),A=null},"letGo");for(;;){let j=o.get(L),F=j&&j.key!==w.key?n.get(j.key):null;if(j&&F&&LX.has(F.state)){if(_||g.step(`Waiting for ${F.key}, which is taking this checkout's slot`),_=!0,!await DX(j.reserved,h))continue;let J=await b(),ie=J?.lifecycle?.phase==="teardown"||J?.lifecycle?.phase==="destroyed";if(J?.environmentProviderId===Hr&&J.status==="ready"&&!ie)return O(`shares the checkout ${I} with ${F.key}, and its slot`);await TS(2e3,h);continue}let X;A={key:w.key,pathKey:p,reserved:new Promise(J=>X=J)},E=X,o.set(L,A);let ne=await b().catch(J=>{throw D(),J});if(ne&&D(),ne&&(ne.lifecycle?.phase==="teardown"||ne.lifecycle?.phase==="destroyed")){_||g.step(`Waiting for the environment at ${I} to be removed`),_=!0,await TS(5e3,h);continue}if(ne?.environmentProviderId===Hr&&ne.status==="provisioning"){_||g.step(`Waiting for the environment being made at ${I}`),_=!0,await TS(5e3,h);continue}if(ne)return O(ne.environmentProviderId===Hr?`shares the environment already at ${I}, and its slot`:`runs in the environment already at ${I}, which the queue doesn't track (no slot)`);break}try{await c(w.key,p,"Taking a station slot",g,h,j=>t.reserve(u.id,j,f.id,h)),E(!0)}catch(j){throw D(),j}return{status:"created",path:I,ownsPath:!1,resource:{key:w.key}}}let k=await t.location(u.id),x=m.key===void 0?sj(p):void 0,v=await c(w.key,p,"Creating the work folder",g,h,async I=>{if(!await y(`${k}/job-${I}`))throw new Error("The work folder could not be claimed.");await t.create(u.id,I,f.id,m.outputs,h)},x);return{status:"created",path:`${k}/job-${v}`,ownsPath:!0,resource:{key:w.key}}},async remove({hostId:u,path:d,pathKey:f,signal:p,report:m}){if(u===null)return{status:"removed"};let y=n.envOf(f);if(!y){let g=sj(f),w=`${await t.location(u)}/job-${g}`;if(d!==null&&d!==w)throw new Error("The work folder path does not match its creation key.");return m.step("Saving declared results and removing the work folder"),await t.remove(u,g,p),{status:"removed"}}if(y.job!==null)if(y.mode==="checkout")m.step("Releasing the station slot"),await t.release(u,y.job,p);else{let g=`${await t.location(u)}/job-${y.job}`;if(d!==null&&d!==g)throw new Error("The work folder path does not match its work item.");m.step("Saving declared results and removing the work folder"),await t.remove(u,y.job,p)}for(let[g,w]of o)w.pathKey===f&&o.delete(g);let h=n.get(y.key);return h&&await r.removed(h,y.attempt),s.wake(),{status:"removed"}}});async function l(u){if(u.status!=="error"||u.environmentId===null)return;let d=await e.sdk.environments.get({environmentId:u.environmentId});!d.managed||d.environmentProviderId!==Hr||d.lifecycle.phase!=="active"||(await e.sdk.threads.events.list({threadId:u.id,types:["turn/started","thread/identity"],limit:"1"})).length>0||await e.sdk.environments.experimental_cleanup({environmentId:d.id})}i(l,"cleanup"),e.events.on("thread.failed",({thread:u})=>l(u).catch(d=>e.log.warn(`Work folder cleanup for @thread:${u.id}: ${String(d)}`)))}i(cj,"setupJobWorkspaces");var Xu=Ds.object({free:Ds.number().int().nonnegative(),floor:Ds.number().int().nonnegative(),inodes:Ds.number().int().nonnegative().nullable(),inodeFloor:Ds.number().int().nonnegative(),low:Ds.boolean(),bytes:Ds.number().int().nonnegative().nullable(),files:Ds.number().int().nonnegative().nullable(),complete:Ds.boolean().nullable()}).strict(),Nc=class extends Error{static{i(this,"JobMeasurementError")}stage;constructor(t,r){super(`Work folder measurement failed during ${t}.`,{cause:r}),this.stage=t}};function pj(e){if(e instanceof Nc)return`${e.stage}: ${pj(e.cause)}`;if(e instanceof Ds.ZodError)return`ZodError: ${e.issues.slice(0,10).map(n=>`${n.path.length===1&&typeof n.path[0]=="string"&&Object.hasOwn(Xu.shape,n.path[0])?n.path[0]:"response"}=${n.code}`).join(", ")}`;let t=[["manager-disconnected",/managing machine.*isn't connected/],["manager-unavailable",/no connected machine manages/],["timeout",/timed? out|timeout/i],["permission-denied",/permission denied/i],["disk-full",/no space left on device/i],["connection-refused",/connection refused/i]],r=[e instanceof SyntaxError?"SyntaxError":e instanceof Error?"Error":"unknown error"];if(e instanceof Error){let n=t.find(([,s])=>s.test(e.message))?.[0];n&&r.push(`reason=${n}`)}return e&&typeof e=="object"&&("exitCode"in e&&Number.isSafeInteger(e.exitCode)&&r.push(`exitCode=${e.exitCode}`),"code"in e&&typeof e.code=="string"&&["ENOENT","EACCES","EPERM","ENOSPC","ETIMEDOUT","ECONNRESET","ECONNREFUSED","EPIPE","EIO"].includes(e.code)&&r.push(`code=${e.code}`)),r.join(" ")}i(pj,"measurementDiagnostic");var jX=i(e=>e.usage!==null,"measured"),xS=i((e,t)=>(t?e.usage?.files:e.usage?.bytes)??0,"size"),lj=i((e,t)=>e.usage===null||e.usage.complete===!1?Number.POSITIVE_INFINITY:xS(e,t),"rank"),MX=i(e=>e.free<e.floor,"bytesLow"),uv=i(e=>!MX(e)&&e.inodes!==null&&e.inodes<e.inodeFloor,"filesOnly"),uj=new Set(["starting","active","stopping"]),OS=i(e=>(e/1e9).toFixed(1).replace(/\.0$/,""),"gb"),$S=i(e=>e.toLocaleString("en-US"),"count"),dj=i(e=>uv(e)?`below ${$S(e.inodeFloor)} free file entries`:`below ${OS(e.floor)} GB free`,"shortage"),BX=i(e=>uv(e)?`${$S(e.inodes??0)} left`:`${OS(e.free)} GB left`,"left");function fj(e,t,r){let n=new AbortController;e.onDispose(()=>n.abort());let s=!1;function o(m,y,h,g){e.log.warn(`Work folder measurement failed: environment=${m.id} host=${m.hostId} folder=${y} phase=${h}; ${pj(g)}`)}i(o,"measurementFailed");async function a(m,y){e.log.warn(y),await e.storage.kv.get(m)!==y&&(await r(y),await e.storage.kv.set(m,y))}i(a,"flagOnce");async function c(m){let y=[];for(let h=0;;h+=100){let g=await e.sdk.threads.list({environmentId:m.id,archived:!1,includeHidden:!0,offset:h,limit:100});for(let w of g){let k=await e.sdk.threads.get({threadId:w.id});k&&k.environmentId===m.id&&!k.archivedAt&&y.push(k)}if(g.length<100)return y}}i(c,"threadsOf");async function l(m){let y=await e.sdk.environments.get({environmentId:m.id});return y.path===m.path&&y.hostId===m.hostId&&y.environmentProviderId===Hr&&y.lifecycle.phase==="active"}i(l,"stillActive");async function u(m){for(let{env:y,id:h}of m)try{return Xu.parse(await t.measure(y.hostId,h,n.signal,{size:!1}))}catch(g){o(y,h,"fresh",g)}return null}i(u,"freshReading");async function d(m,y){await e.storage.kv.delete(`work-storage-low:${m}`);for(let{env:h,usage:g}of y){await e.storage.kv.delete(`work-storage-warning:${h.id}`),await e.storage.kv.delete(`work-storage-stopped:${h.id}`);let w=`work-storage-check:${h.id}`;if(g!==null){await e.storage.kv.delete(w);continue}let k=(await c(h)).slice(0,10).map(x=>`@thread:${x.id}`);await a(w,`${k.join(", ")} The station disk's free space could not be checked for this work folder. Its work keeps running; the check repeats every minute, and if the disk is low this folder is stopped first.`.trim())}}i(d,"settle");async function f(m,y){let h=[];for(let I of y){if(I.usage===null||I.usage.low){h.push(I);continue}let O=null;try{O=Xu.parse(await t.measure(I.env.hostId,I.id,n.signal))}catch(L){o(I.env,I.id,"size",L)}h.push({...I,usage:O})}let g=h.filter(jX),w=g.find(I=>I.usage.low)??g[0];if(!w)return;let k=w.usage,x=i((I,O)=>[...I].sort((L,b)=>lj(b,O)-lj(L,O)||xS(b,O)-xS(L,O)),"largestFirst"),v=new Set;for(;;){let I=h.filter(S=>!v.has(S.env.id));if(I.length===0||n.signal.aborted)break;let O=await u([...x(I,uv(k)),...g.filter(S=>v.has(S.env.id))]);if(O&&!O.low){await d(m,h);return}O&&(k=O);let L=uv(k),b=x(I,L)[0];if(!b)break;let{env:_,id:A,usage:E}=b;if(v.add(_.id),!await l(_))continue;let D=`work-storage-warning:${_.id}`,j=`work-storage-stopped:${_.id}`,F=await c(_);if(!F.some(S=>uj.has(S.status))&&await e.storage.kv.get(j)!==void 0)try{await t.stopFolder(_.hostId,A,n.signal);continue}catch{await e.storage.kv.delete(j)}if(!await l(_))continue;let ne=F.slice(0,10).map(S=>`@thread:${S.id}`),J=!0;try{for(let S of F){let M=await e.sdk.threads.get({threadId:S.id});if(!M||M.environmentId!==_.id||M.archivedAt)continue;await e.sdk.threads.stop({threadId:S.id});let T=await e.sdk.threads.get({threadId:S.id});if(T&&uj.has(T.status))throw new Error("Work has not confirmed that it stopped.")}await t.stopFolder(_.hostId,A,n.signal),await e.storage.kv.set(j,!0)}catch{J=!1}let ie=L?E?.files:E?.bytes,le=i(S=>L?`${$S(S)} files`:`${OS(S)} GB`,"sizeText"),Ae=E?.complete===!0&&ie!==null&&ie!==void 0?`This was the largest work folder (${le(ie)}), so`:`This work folder's size could not be fully measured${ie?` (at least ${le(ie)})`:""}, so it counts as the largest and`,$=`${ne.join(", ")} Station disk ${dj(k)} (${BX(k)}). ${Ae} ${J?"its work was stopped":"its work was asked to stop, but stopping could not be confirmed"}; other work keeps running. Its folder is kept as it was, with all its files and declared results. Free disk space and resume it, or handle its result and archive it.`,C=await e.storage.kv.get(D);if(!J&&typeof C=="string"&&C.includes("could not be confirmed")){e.log.warn($.trim());return}await a(D,$.trim());return}await a(`work-storage-low:${m}`,`Station disk ${dj(k)}, and the work in every work folder is already stopped. The folders are kept. Archive handled work to free disk space.`)}i(f,"relieve");async function p(){if(!(s||n.signal.aborted)){s=!0;try{let m=await e.sdk.environments.list({environmentProviderId:Hr,status:"ready",limit:100}),y=new Map;for(let h of m){if(n.signal.aborted)return;if(!h.managed||h.environmentProviderId!==Hr||h.lifecycle.phase!=="active"||!h.path)continue;let g=/\/job-([a-f0-9]{32})$/.exec(h.path)?.[1];if(!g)throw new Error("A managed work folder has an invalid path.");let w=null;try{w=Xu.parse(await t.measure(h.hostId,g,n.signal))}catch(k){o(h,g,"tick",k),w=null}y.set(h.hostId,[...y.get(h.hostId)??[],{env:h,id:g,usage:w}])}for(let[h,g]of y){if(n.signal.aborted)return;if(g.some(w=>w.usage?.low)){await f(h,g);continue}await d(h,g)}}finally{s=!1}}}return i(p,"tick"),ot(e,"managed-work-storage","* * * * *",p),{tick:p}}i(fj,"setupJobWatchdog");import{createHash as Rie}from"node:crypto";import{readFileSync as Nie}from"node:fs";import{join as Cie}from"node:path";import{z as UX}from"zod";var hj=UX.string().refine(e=>e===""||/^(?:[1-8][0-9]|90)$/.test(e),{message:"Moonlet chat compaction must be empty or a whole percentage from 10 to 90."}),mj={type:"string",label:"Moonlet chat compaction (%)",description:"When Moonlet summarises older chat history. Empty keeps the current default. Enter a whole percentage from 10 to 90; 20 aims near 200,000 tokens with a one-million-token window. The full window stays available. Applies at the next main chat session start; a running turn keeps its value.",default:"",experimental_schema:hj};function gj(e,t,r){if(!t||t!==r)return[];let n=hj.parse(e);return n===""?[]:[{name:"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE",value:n,reason:"Moonlet main chat compaction percentage"}]}i(gj,"mainChatCompactionEnv");Ao();import{existsSync as _ie}from"node:fs";import{homedir as kie}from"node:os";import{join as Eie}from"node:path";ya();Wr();var qX="tag:orbit",WX="2596A99EAAB33821893C0A79458CA832957F5868";function yj(e){return e==="linux"?"/usr/bin/tailscale":"/opt/homebrew/bin/tailscale"}i(yj,"tailscale");var HX=`if ! command -v tailscale >/dev/null; then
|
|
449
|
+
`),await o.sync(),await o.close(),await TX(n,s)}finally{await o.close(),await xX(n).catch(a=>{if(a.code!=="ENOENT")throw a})}return r}i(IX,"declareOutputs");if(process.argv[1]&&import.meta.url===$X(AS(process.argv[1])).href)try{if(process.argv.length!==3)throw new Error("Usage: node declare-outputs.mjs JSON_LIST (writes in the current folder)");await IX(JSON.parse(process.argv[2]),process.cwd())}catch(e){console.error(e.message),process.exitCode=1}var Hr=ES,sj=i(e=>PX("sha256").update(e).digest("hex").slice(0,32),"jobId"),RX=un.array(un.string()).superRefine((e,t)=>{try{SS(e)}catch(r){t.addIssue({code:"custom",message:r instanceof Error?r.message:"Invalid output names."})}}).default(["report.md","evidence.md","job.log"]),NX=un.string().regex(/^\/./).refine(e=>!e.split("/").some(t=>t==="."||t===".."),"Checkout paths cannot contain parent steps."),CX=un.object({outputs:RX,key:un.string().regex(lS).optional(),adopt:NX.optional()}).strict(),LX=new Set(["queued","admitted","running"]);function DX(e,t){return t.aborted?Promise.reject(t.reason):new Promise((r,n)=>{let s=i(()=>n(t.reason),"stop");t.addEventListener("abort",s,{once:!0}),e.then(o=>{t.removeEventListener("abort",s),r(o)})})}i(DX,"settled");function TS(e,t){return t.aborted?Promise.reject(t.reason):new Promise((r,n)=>{let s=setTimeout(()=>{t.removeEventListener("abort",o),r()},e),o=i(()=>{clearTimeout(s),n(t.reason)},"stop");t.addEventListener("abort",o,{once:!0})})}i(TS,"nap");var Sa=class extends Error{static{i(this,"CapacityFull")}},oj=un.object({checkouts:un.array(un.object({path:un.string(),branches:un.array(un.object({branch:un.string(),commits:un.number().int().positive()}).strict()),detached:un.number().int().nonnegative(),uncommitted:un.number().int().nonnegative(),untracked:un.number().int().nonnegative(),stashes:un.number().int().nonnegative()}).strict())}).strict(),aj=i(e=>e?/\/job-([a-f0-9]{32})$/.exec(e)?.[1]??null:null,"jobFolderId");function cj(e,t,r){let{items:n,admission:s}=r,o=new Map;function a(u,d,f,p){let m=u.key??`thread:${d.id.toLowerCase()}`,y=n.get(m);if(y){if(y.thread===null&&y.attempt>1&&typeof d.createdAt=="number"){let g=n.history(m).find(w=>w.attempt===y.attempt)?.at;if(g!==void 0&&d.createdAt<g)throw new Error(`@thread:${d.id} is from an earlier attempt of ${m}; it doesn't take attempt ${y.attempt}'s place.`)}}else{if(u.key)throw new Error(`The start's work item ${m} is missing; start it again.`);n.claim({key:m,host:f,mode:u.adopt?"checkout":"folder",class:"asked",loop:null,source:"station"})}let h=n.bind(m,d.id);return n.bindPath(p,m),h}i(a,"itemFor");async function c(u,d,f,p,m,y,h){let g=!1;try{for(;;){let w=await s.admit(u,p,m,()=>{g=!0},h),k=s.generation();n.recordJob(d,w.job),g||p.step(f);try{return await y(w.job),s.answered(u),g&&p.step(f),w.job}catch(x){if(!(x instanceof Sa))throw s.answered(u),x;g=!0,await s.refused(u,x.message,p,m,k)}}}finally{s.done(u)}}i(c,"admitted"),e.experimental_environments.register({id:Hr,displayName:"Orbit work folder",description:"A temporary work folder. Declared results are saved before bb removes it.",icon:"Folder",requires:{},inputs:CX,policy:{retireGraceMs:3e5,pathKeys:"per-attempt",experimental_cleanupFailedBeforeRun:!0,internal_DO_NOT_USE_removeChecksWorkspaceUse:!0},async availability({host:u}){try{return await t.location(u.id),{status:"available"}}catch{return{status:"unavailable",message:"This machine cannot create Orbit work folders."}}},async validate({host:u}){return await t.location(u.id),{action:"accept"}},async create({host:u,project:d,thread:f,pathKey:p,inputs:m,experimental_claimPath:y,signal:h,report:g}){let w=a(m,f,u.id,p);if(m.adopt){let I=m.adopt,O=i(j=>(n.get(w.key)?.state==="queued"&&(n.move(w.key,"sharing",j),s.wake()),{status:"created",path:I,ownsPath:!1,resource:{key:w.key}}),"share"),L=`${u.id}\0${d.id}\0${I}`,b=i(async()=>(await e.sdk.environments.list({hostId:u.id,path:I,limit:5})).find(j=>j.projectId===d.id&&(j.status==="ready"||j.status==="provisioning")),"here"),_=!1,A=null,E=i(()=>{},"resolveEntry"),D=i(()=>{A&&o.get(L)===A&&o.delete(L),E(!1),A=null},"letGo");for(;;){let j=o.get(L),F=j&&j.key!==w.key?n.get(j.key):null;if(j&&F&&LX.has(F.state)){if(_||g.step(`Waiting for ${F.key}, which is taking this checkout's slot`),_=!0,!await DX(j.reserved,h))continue;let J=await b(),ie=J?.lifecycle?.phase==="teardown"||J?.lifecycle?.phase==="destroyed";if(J?.environmentProviderId===Hr&&J.status==="ready"&&!ie)return O(`shares the checkout ${I} with ${F.key}, and its slot`);await TS(2e3,h);continue}let X;A={key:w.key,pathKey:p,reserved:new Promise(J=>X=J)},E=X,o.set(L,A);let ne=await b().catch(J=>{throw D(),J});if(ne&&D(),ne&&(ne.lifecycle?.phase==="teardown"||ne.lifecycle?.phase==="destroyed")){_||g.step(`Waiting for the environment at ${I} to be removed`),_=!0,await TS(5e3,h);continue}if(ne?.environmentProviderId===Hr&&ne.status==="provisioning"){_||g.step(`Waiting for the environment being made at ${I}`),_=!0,await TS(5e3,h);continue}if(ne)return O(ne.environmentProviderId===Hr?`shares the environment already at ${I}, and its slot`:`runs in the environment already at ${I}, which the queue doesn't track (no slot)`);break}try{await c(w.key,p,"Taking a station slot",g,h,j=>t.reserve(u.id,j,f.id,h)),E(!0)}catch(j){throw D(),j}return{status:"created",path:I,ownsPath:!1,resource:{key:w.key}}}let k=await t.location(u.id),x=m.key===void 0?sj(p):void 0,v=await c(w.key,p,"Creating the work folder",g,h,async I=>{if(!await y(`${k}/job-${I}`))throw new Error("The work folder could not be claimed.");await t.create(u.id,I,f.id,m.outputs,h)},x);return{status:"created",path:`${k}/job-${v}`,ownsPath:!0,resource:{key:w.key}}},async remove({hostId:u,path:d,pathKey:f,signal:p,report:m}){if(u===null)return{status:"removed"};let y=n.envOf(f);if(!y){let g=sj(f),w=`${await t.location(u)}/job-${g}`;if(d!==null&&d!==w)throw new Error("The work folder path does not match its creation key.");return m.step("Saving declared results and removing the work folder"),await t.remove(u,g,p),{status:"removed"}}if(y.job!==null)if(y.mode==="checkout")m.step("Releasing the station slot"),await t.release(u,y.job,p);else{let g=`${await t.location(u)}/job-${y.job}`;if(d!==null&&d!==g)throw new Error("The work folder path does not match its work item.");m.step("Saving declared results and removing the work folder"),await t.remove(u,y.job,p)}for(let[g,w]of o)w.pathKey===f&&o.delete(g);let h=n.get(y.key);return h&&await r.removed(h,y.attempt),s.wake(),{status:"removed"}}});async function l(u){if(u.status!=="error"||u.environmentId===null)return;let d=await e.sdk.environments.get({environmentId:u.environmentId});!d.managed||d.environmentProviderId!==Hr||d.lifecycle.phase!=="active"||(await e.sdk.threads.events.list({threadId:u.id,types:["turn/started","thread/identity"],limit:"1"})).length>0||await e.sdk.environments.experimental_cleanup({environmentId:d.id})}i(l,"cleanup"),e.events.on("thread.failed",({thread:u})=>l(u).catch(d=>e.log.warn(`Work folder cleanup for @thread:${u.id}: ${String(d)}`)))}i(cj,"setupJobWorkspaces");var Xu=Ds.object({free:Ds.number().int().nonnegative(),floor:Ds.number().int().nonnegative(),inodes:Ds.number().int().nonnegative().nullable(),inodeFloor:Ds.number().int().nonnegative(),low:Ds.boolean(),bytes:Ds.number().int().nonnegative().nullable(),files:Ds.number().int().nonnegative().nullable(),complete:Ds.boolean().nullable()}).strict(),Nc=class extends Error{static{i(this,"JobMeasurementError")}stage;constructor(t,r){super(`Work folder measurement failed during ${t}.`,{cause:r}),this.stage=t}};function pj(e){if(e instanceof Nc)return`${e.stage}: ${pj(e.cause)}`;if(e instanceof Ds.ZodError)return`ZodError: ${e.issues.slice(0,10).map(n=>`${n.path.length===1&&typeof n.path[0]=="string"&&Object.hasOwn(Xu.shape,n.path[0])?n.path[0]:"response"}=${n.code}`).join(", ")}`;let t=[["manager-disconnected",/managing machine.*isn't connected/],["manager-unavailable",/no connected machine manages/],["timeout",/timed? out|timeout/i],["permission-denied",/permission denied/i],["disk-full",/no space left on device/i],["connection-refused",/connection refused/i]],r=[e instanceof SyntaxError?"SyntaxError":e instanceof Error?"Error":"unknown error"];if(e instanceof Error){let n=t.find(([,s])=>s.test(e.message))?.[0];n&&r.push(`reason=${n}`)}return e&&typeof e=="object"&&("exitCode"in e&&Number.isSafeInteger(e.exitCode)&&r.push(`exitCode=${e.exitCode}`),"code"in e&&typeof e.code=="string"&&["ENOENT","EACCES","EPERM","ENOSPC","ETIMEDOUT","ECONNRESET","ECONNREFUSED","EPIPE","EIO"].includes(e.code)&&r.push(`code=${e.code}`)),r.join(" ")}i(pj,"measurementDiagnostic");var jX=i(e=>e.usage!==null,"measured"),xS=i((e,t)=>(t?e.usage?.files:e.usage?.bytes)??0,"size"),lj=i((e,t)=>e.usage===null||e.usage.complete===!1?Number.POSITIVE_INFINITY:xS(e,t),"rank"),MX=i(e=>e.free<e.floor,"bytesLow"),uv=i(e=>!MX(e)&&e.inodes!==null&&e.inodes<e.inodeFloor,"filesOnly"),uj=new Set(["starting","active","stopping"]),OS=i(e=>(e/1e9).toFixed(1).replace(/\.0$/,""),"gb"),$S=i(e=>e.toLocaleString("en-US"),"count"),dj=i(e=>uv(e)?`below ${$S(e.inodeFloor)} free file entries`:`below ${OS(e.floor)} GB free`,"shortage"),BX=i(e=>uv(e)?`${$S(e.inodes??0)} left`:`${OS(e.free)} GB left`,"left");function fj(e,t,r){let n=new AbortController;e.onDispose(()=>n.abort());let s=!1;function o(m,y,h,g){e.log.warn(`Work folder measurement failed: environment=${m.id} host=${m.hostId} folder=${y} phase=${h}; ${pj(g)}`)}i(o,"measurementFailed");async function a(m,y){e.log.warn(y),await e.storage.kv.get(m)!==y&&(await r(y),await e.storage.kv.set(m,y))}i(a,"flagOnce");async function c(m){let y=[];for(let h=0;;h+=100){let g=await e.sdk.threads.list({environmentId:m.id,archived:!1,includeHidden:!0,offset:h,limit:100});for(let w of g){let k=await e.sdk.threads.get({threadId:w.id});k&&k.environmentId===m.id&&!k.archivedAt&&y.push(k)}if(g.length<100)return y}}i(c,"threadsOf");async function l(m){let y=await e.sdk.environments.get({environmentId:m.id});return y.path===m.path&&y.hostId===m.hostId&&y.environmentProviderId===Hr&&y.lifecycle.phase==="active"}i(l,"stillActive");async function u(m){for(let{env:y,id:h}of m)try{return Xu.parse(await t.measure(y.hostId,h,n.signal,{size:!1}))}catch(g){o(y,h,"fresh",g)}return null}i(u,"freshReading");async function d(m,y){await e.storage.kv.delete(`work-storage-low:${m}`);for(let{env:h,usage:g}of y){await e.storage.kv.delete(`work-storage-warning:${h.id}`),await e.storage.kv.delete(`work-storage-stopped:${h.id}`);let w=`work-storage-check:${h.id}`;if(g!==null){await e.storage.kv.delete(w);continue}let k=(await c(h)).slice(0,10).map(x=>`@thread:${x.id}`);await a(w,`${k.join(", ")} The station disk's free space could not be checked for this work folder. Its work keeps running; the check repeats every minute, and if the disk is low this folder is stopped first.`.trim())}}i(d,"settle");async function f(m,y){let h=[];for(let I of y){if(I.usage===null||I.usage.low){h.push(I);continue}let O=null;try{O=Xu.parse(await t.measure(I.env.hostId,I.id,n.signal))}catch(L){o(I.env,I.id,"size",L)}h.push({...I,usage:O})}let g=h.filter(jX),w=g.find(I=>I.usage.low)??g[0];if(!w)return;let k=w.usage,x=i((I,O)=>[...I].sort((L,b)=>lj(b,O)-lj(L,O)||xS(b,O)-xS(L,O)),"largestFirst"),v=new Set;for(;;){let I=h.filter(S=>!v.has(S.env.id));if(I.length===0||n.signal.aborted)break;let O=await u([...x(I,uv(k)),...g.filter(S=>v.has(S.env.id))]);if(O&&!O.low){await d(m,h);return}O&&(k=O);let L=uv(k),b=x(I,L)[0];if(!b)break;let{env:_,id:A,usage:E}=b;if(v.add(_.id),!await l(_))continue;let D=`work-storage-warning:${_.id}`,j=`work-storage-stopped:${_.id}`,F=await c(_);if(!F.some(S=>uj.has(S.status))&&await e.storage.kv.get(j)!==void 0)try{await t.stopFolder(_.hostId,A,n.signal);continue}catch{await e.storage.kv.delete(j)}if(!await l(_))continue;let ne=F.slice(0,10).map(S=>`@thread:${S.id}`),J=!0;try{for(let S of F){let M=await e.sdk.threads.get({threadId:S.id});if(!M||M.environmentId!==_.id||M.archivedAt)continue;await e.sdk.threads.stop({threadId:S.id});let T=await e.sdk.threads.get({threadId:S.id});if(T&&uj.has(T.status))throw new Error("Work has not confirmed that it stopped.")}await t.stopFolder(_.hostId,A,n.signal),await e.storage.kv.set(j,!0)}catch{J=!1}let ie=L?E?.files:E?.bytes,le=i(S=>L?`${$S(S)} files`:`${OS(S)} GB`,"sizeText"),Ae=E?.complete===!0&&ie!==null&&ie!==void 0?`This was the largest work folder (${le(ie)}), so`:`This work folder's size could not be fully measured${ie?` (at least ${le(ie)})`:""}, so it counts as the largest and`,$=`${ne.join(", ")} Station disk ${dj(k)} (${BX(k)}). ${Ae} ${J?"its work was stopped":"its work was asked to stop, but stopping could not be confirmed"}; other work keeps running. Its folder is kept as it was, with all its files and declared results. Free disk space and resume it, or handle its result and archive it.`,C=await e.storage.kv.get(D);if(!J&&typeof C=="string"&&C.includes("could not be confirmed")){e.log.warn($.trim());return}await a(D,$.trim());return}await a(`work-storage-low:${m}`,`Station disk ${dj(k)}, and the work in every work folder is already stopped. The folders are kept. Archive handled work to free disk space.`)}i(f,"relieve");async function p(){if(!(s||n.signal.aborted)){s=!0;try{let m=await e.sdk.environments.list({environmentProviderId:Hr,status:"ready",limit:100}),y=new Map;for(let h of m){if(n.signal.aborted)return;if(!h.managed||h.environmentProviderId!==Hr||h.lifecycle.phase!=="active"||!h.path)continue;let g=/\/job-([a-f0-9]{32})$/.exec(h.path)?.[1];if(!g)throw new Error("A managed work folder has an invalid path.");let w=null;try{w=Xu.parse(await t.measure(h.hostId,g,n.signal))}catch(k){o(h,g,"tick",k),w=null}y.set(h.hostId,[...y.get(h.hostId)??[],{env:h,id:g,usage:w}])}for(let[h,g]of y){if(n.signal.aborted)return;if(g.some(w=>w.usage?.low)){await f(h,g);continue}await d(h,g)}}finally{s=!1}}}return i(p,"tick"),ot(e,"managed-work-storage","* * * * *",p),{tick:p}}i(fj,"setupJobWatchdog");import{createHash as Rie}from"node:crypto";import{readFileSync as Nie}from"node:fs";import{join as Cie}from"node:path";import{z as UX}from"zod";var hj=UX.string().refine(e=>e===""||/^(?:[1-8][0-9]|90)$/.test(e),{message:"Moonlet chat compaction must be empty or a whole percentage from 10 to 90."}),mj={type:"string",label:"Moonlet chat compaction (%)",description:"When Moonlet summarises older chat history. Defaults to 20 when unset. Empty uses the usual compaction point instead. Enter a whole percentage from 10 to 90; 20 aims near 200,000 tokens with a one-million-token window. The full window stays available. Applies at the next main chat session start; a running turn keeps its value.",default:"20",experimental_schema:hj};function gj(e,t,r){if(!t||t!==r)return[];let n=hj.parse(e);return n===""?[]:[{name:"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE",value:n,reason:"Moonlet main chat compaction percentage"}]}i(gj,"mainChatCompactionEnv");Ao();import{existsSync as _ie}from"node:fs";import{homedir as kie}from"node:os";import{join as Eie}from"node:path";ya();Wr();var qX="tag:orbit",WX="2596A99EAAB33821893C0A79458CA832957F5868";function yj(e){return e==="linux"?"/usr/bin/tailscale":"/opt/homebrew/bin/tailscale"}i(yj,"tailscale");var HX=`if ! command -v tailscale >/dev/null; then
|
|
450
450
|
. /etc/os-release
|
|
451
451
|
case "$ID" in ubuntu|debian) ;; *) echo "the Tailscale integration supports Debian and Ubuntu, not $ID" >&2; exit 1 ;; esac
|
|
452
452
|
[ -n "\${VERSION_CODENAME:-}" ] || { echo "no release codename in /etc/os-release" >&2; exit 1; }
|