@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,6 +1,6 @@
1
1
  {
2
2
  "name": "@halcyonlabs/app",
3
- "version": "0.47.0-halcyon.208",
3
+ "version": "0.47.0-halcyon.210",
4
4
  "description": "bb app launcher for npx",
5
5
  "keywords": [
6
6
  "bb",
@@ -1 +1 @@
1
- 3fa7df1c84b1f0d355e967139f78fa4908a81845
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; }