@halcyonlabs/app 0.47.0-halcyon.210 → 0.47.0-halcyon.213
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/bb-app.js +2 -1
- package/dist/bb-host-daemon.js +2 -1
- package/dist/bb-server.js +2 -1
- package/dist/bb.js +2 -1
- package/host-daemon/dist/bb +1 -1
- package/host-daemon/dist/bb-chunks/{chunk-DQXZ6RW2.js → chunk-YWDVXI6C.js} +1 -1
- package/host-daemon/dist/bb-chunks/{guide-3NQJLWVD.js → guide-I2YUWTE2.js} +1 -1
- package/host-daemon/dist/bb-chunks/{server-MHWGYSLO.js → server-LJ3QLCU4.js} +2 -2
- package/host-daemon/dist/daemon-bundle.mjs +2 -2
- package/package.json +1 -1
- package/server/dist/builtin-plugins/orbit/dist/assets/orbit/revision +1 -1
- package/server/dist/start-server.js +1749 -1479
package/dist/bb-app.js
CHANGED
|
@@ -17022,7 +17022,8 @@ var SERVER_OWNED_TOP_LEVEL_FILES = [
|
|
|
17022
17022
|
var SERVER_OWNED_TOP_LEVEL_DIRECTORIES = [
|
|
17023
17023
|
"attachments",
|
|
17024
17024
|
"skills",
|
|
17025
|
-
"theme"
|
|
17025
|
+
"theme",
|
|
17026
|
+
"secrets"
|
|
17026
17027
|
];
|
|
17027
17028
|
var PLUGINS_DIR_NAME = "plugins";
|
|
17028
17029
|
var TOP_LEVEL_FILE_NAMES = new Set(
|
package/dist/bb-host-daemon.js
CHANGED
|
@@ -16372,7 +16372,8 @@ var SERVER_OWNED_TOP_LEVEL_FILES = [
|
|
|
16372
16372
|
var SERVER_OWNED_TOP_LEVEL_DIRECTORIES = [
|
|
16373
16373
|
"attachments",
|
|
16374
16374
|
"skills",
|
|
16375
|
-
"theme"
|
|
16375
|
+
"theme",
|
|
16376
|
+
"secrets"
|
|
16376
16377
|
];
|
|
16377
16378
|
var PLUGINS_DIR_NAME = "plugins";
|
|
16378
16379
|
var TOP_LEVEL_FILE_NAMES = new Set(
|
package/dist/bb-server.js
CHANGED
|
@@ -16289,7 +16289,8 @@ var SERVER_OWNED_TOP_LEVEL_FILES = [
|
|
|
16289
16289
|
var SERVER_OWNED_TOP_LEVEL_DIRECTORIES = [
|
|
16290
16290
|
"attachments",
|
|
16291
16291
|
"skills",
|
|
16292
|
-
"theme"
|
|
16292
|
+
"theme",
|
|
16293
|
+
"secrets"
|
|
16293
16294
|
];
|
|
16294
16295
|
var PLUGINS_DIR_NAME = "plugins";
|
|
16295
16296
|
var TOP_LEVEL_FILE_NAMES = new Set(
|
package/dist/bb.js
CHANGED
|
@@ -16209,7 +16209,8 @@ var SERVER_OWNED_TOP_LEVEL_FILES = [
|
|
|
16209
16209
|
var SERVER_OWNED_TOP_LEVEL_DIRECTORIES = [
|
|
16210
16210
|
"attachments",
|
|
16211
16211
|
"skills",
|
|
16212
|
-
"theme"
|
|
16212
|
+
"theme",
|
|
16213
|
+
"secrets"
|
|
16213
16214
|
];
|
|
16214
16215
|
var PLUGINS_DIR_NAME = "plugins";
|
|
16215
16216
|
var TOP_LEVEL_FILE_NAMES = new Set(
|
package/host-daemon/dist/bb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __createRequire } from "node:module";import { dirname as __pathDirname } from "node:path";import { fileURLToPath as __fileURLToPath } from "node:url";const require = __createRequire(import.meta.url);const __filename = __fileURLToPath(import.meta.url);const __dirname = __pathDirname(__filename);
|
|
3
|
-
import{a as g,b as v,c as C}from"./bb-chunks/chunk-
|
|
3
|
+
import{a as g,b as v,c as C}from"./bb-chunks/chunk-YWDVXI6C.js";import{a as d,b as p,d as u}from"./bb-chunks/chunk-NCQMSH7M.js";import"./bb-chunks/chunk-5PWLIQO6.js";import{spawnSync as _}from"node:child_process";import{realpathSync as R}from"node:fs";import{resolve as S,win32 as B}from"node:path";var f="BB_CLI_REEXEC";function I(e){return e.platform==="win32"&&B.extname(e.target)===""?{command:e.nodePath,args:[e.target,...e.argv]}:{command:e.target,args:e.argv}}function x(e){try{return R(S(e))}catch{return null}}function b(e={}){let n=e.env??process.env;if(n[f]==="1")return;let r=n.BB_CLI?.trim();if(!r)return;let t=e.currentExecutablePath??process.argv[1];if(!t)return;let o=x(r),a=x(t);if(o===null||a===null||o===a)return;let i=e.argv??process.argv.slice(2),c={...n,[f]:"1"};if(e.reexec){e.reexec({target:o,argv:i,env:c});return}let l=I({argv:i,nodePath:process.execPath,platform:process.platform,target:o}),s=_(l.command,l.args,{env:c,stdio:"inherit"});if(s.error){process.stderr.write(`Moonlet: failed to re-exec BB_CLI=${o}: ${s.error.message}
|
|
4
4
|
`),process.exitCode=1;return}process.exit(s.status===null?1:s.status)}process.env.FORCE_COLOR!==void 0&&delete process.env.NO_COLOR;b();var m=new p;m.name("bb").description("Moonlet CLI - manage your AI coding agents").enablePositionalOptions().exitOverride().showSuggestionAfterError(!1).version(u());var O=new Set([...g.map(e=>e.name),"help"]);function A(e){let n,r=()=>n??=e.createCliRuntimeContext();return{getUrl:()=>e.resolveServerUrl(r()),getContext:()=>e.resolveContextSnapshot(r())}}async function L(e,n,r){let t=await import("./bb-chunks/plugin-cli-proxy-HRCQQTJZ.js"),o=await t.fetchPluginCliContributions(n());if(o.outcome==="unreachable"){if(r)return;let s=t.describeUnreachableServer(n(),o.cause,o.lastTimeoutMs,o.attempts);console.error(s);let{isJsonInvocation:E,writeCliErrorEnvelope:y}=await import("./bb-chunks/cli-error-output-KERMGTKZ.js");y({code:"server_unreachable",hint:null,message:s},E(process.argv)),process.exit(1)}if(o.outcome==="invalid")return;let a=t.findPluginCliCommand(o.contributions,e);if(a===void 0){let s=await t.findDisabledPluginForCommand(n(),e);s!==null&&(console.error(`bb ${e} is provided by the "${s}" plugin, which is disabled \u2014 run \`bb plugin enable ${s}\` or enable it in Plugins.`),process.exit(1));return}let i=process.argv.slice(3),c=a.commands.find(s=>s.name===i[0]);c!==void 0&&a.rendersHelp!==!0&&i.slice(1).some(s=>s==="--help"||s==="-h")&&(console.log(c.usage),process.exit(0));let l=await t.runPluginCliCommand(n(),a.pluginId,i);l!==0&&await w({code:"plugin_command_failed",command:t.pluginCommandLabel(a,i),exitCode:l,token:null}),process.exit(l)}async function w(e){let[{appendCliErrorLogEntry:n},{commandPathLabel:r}]=await Promise.all([import("./bb-chunks/cli-error-log-PHJFENHA.js"),import("./bb-chunks/commander-errors-BOS22JFH.js")]);n({at:new Date().toISOString(),cliVersion:u(),code:e.code,command:e.command??r(m,process.argv),exitCode:e.exitCode,threadId:process.env.BB_THREAD_ID??null,token:e.token})}async function P(e,n){e.exitCode===0&&process.exit(0);let[r,t]=await Promise.all([import("./bb-chunks/commander-errors-BOS22JFH.js"),import("./bb-chunks/context-hints-UXH4OTTI.js")]),o=await r.summarizeCommanderError({argv:process.argv,error:e,program:m,resolveHostId:n===null?async()=>null:t.createContextHostIdResolver(n)});r.writeCommanderErrorSummary(o,process.argv),await w({code:o.code,command:null,exitCode:e.exitCode,token:o.logToken}),process.exit(e.exitCode)}async function h(e){try{await m.parseAsync(process.argv)}catch(n){throw n instanceof d&&await P(n,e),n}}async function M(e){let n=await import("./bb-chunks/command-resolution-U7GVB5KQ.js");if(!n.hasHelpFlag(process.argv))return;let r=n.resolveInvocation(m,process.argv);if(r.unknownSubcommand===null)return;let t=`error: unknown command '${r.unknownSubcommand}'`;console.error(t),await P(new d(1,"commander.unknownCommand",t),e)}async function k(){let[{JSON_SHAPE_BY_COMMAND_PATH:e,jsonShapeHelp:n},r]=await Promise.all([import("./bb-chunks/json-shapes-TGDCNQZQ.js"),import("./bb-chunks/command-resolution-U7GVB5KQ.js")]);for(let t of Object.keys(e)){let o=r.resolveInvocation(m,["node","bb",...t.split(" ")]),a=n(t);a===null||o.path.join(" ")!==t||o.command.addHelpText("after",a)}}async function D(){let e=process.argv[2],n=v(e);if(n.length===0){await h(null);return}let[r,...t]=await Promise.all([import("./bb-chunks/context-env-XTJLCT5E.js"),...n.map(i=>i.load())]),o=A(r);m.addHelpText("after",()=>{let i=o.getContext(),c=i.projectId??"<unset>",l=i.threadId??"<unset>";return`
|
|
5
5
|
|
|
6
6
|
Current context:
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module";import { dirname as __pathDirname } from "node:path";import { fileURLToPath as __fileURLToPath } from "node:url";const require = __createRequire(import.meta.url);const __filename = __fileURLToPath(import.meta.url);const __dirname = __pathDirname(__filename);
|
|
2
|
-
function o(e,r,t){return{name:e,load:()=>r().then(t)}}var m=[o("browser",()=>import("./browser-RWEUDASS.js"),e=>(r,t)=>e.registerBrowserCommands(r,t.getUrl)),o("status",()=>import("./status-5KEKYI27.js"),e=>(r,t)=>e.registerStatusCommand(r,t.getUrl,t.getContext)),o("settings",()=>import("./settings-EZMOESWW.js"),e=>(r,t)=>e.registerSettingsCommands(r,t.getUrl)),o("project",()=>import("./project-ELMO4ZHY.js"),e=>(r,t)=>e.registerProjectCommands(r,t.getUrl)),o("prompt-history",()=>import("./prompt-history-OPVCTDH7.js"),e=>(r,t)=>e.registerPromptHistoryCommands(r,t.getUrl)),o("provider",()=>import("./provider-4SNAD6EB.js"),e=>(r,t)=>e.registerProviderCommands(r,t.getUrl)),o("machine",()=>import("./machine-P3KPUL4Y.js"),e=>(r,t)=>e.registerMachineCommands(r,t.getUrl)),o("server",()=>import("./server-
|
|
2
|
+
function o(e,r,t){return{name:e,load:()=>r().then(t)}}var m=[o("browser",()=>import("./browser-RWEUDASS.js"),e=>(r,t)=>e.registerBrowserCommands(r,t.getUrl)),o("status",()=>import("./status-5KEKYI27.js"),e=>(r,t)=>e.registerStatusCommand(r,t.getUrl,t.getContext)),o("settings",()=>import("./settings-EZMOESWW.js"),e=>(r,t)=>e.registerSettingsCommands(r,t.getUrl)),o("project",()=>import("./project-ELMO4ZHY.js"),e=>(r,t)=>e.registerProjectCommands(r,t.getUrl)),o("prompt-history",()=>import("./prompt-history-OPVCTDH7.js"),e=>(r,t)=>e.registerPromptHistoryCommands(r,t.getUrl)),o("provider",()=>import("./provider-4SNAD6EB.js"),e=>(r,t)=>e.registerProviderCommands(r,t.getUrl)),o("machine",()=>import("./machine-P3KPUL4Y.js"),e=>(r,t)=>e.registerMachineCommands(r,t.getUrl)),o("server",()=>import("./server-LJ3QLCU4.js"),e=>(r,t)=>e.registerServerCommands(r,t.getUrl)),o("updates",()=>import("./updates-YX2JWHQ2.js"),e=>(r,t)=>e.registerUpdatesCommands(r,t.getUrl)),o("terminal",()=>import("./terminal-BWYHTGRL.js"),e=>(r,t)=>e.registerTerminalCommands(r,t.getUrl)),o("thread",()=>import("./thread-FYWQ3VAE.js"),e=>(r,t)=>e.registerThreadCommands(r,t.getUrl)),o("environment",()=>import("./environment-YMLUROZW.js"),e=>(r,t)=>e.registerEnvironmentCommands(r,t.getUrl)),o("file",()=>import("./file-BW573MH5.js"),e=>(r,t)=>e.registerFileCommands(r,t.getUrl)),o("theme",()=>import("./theme-UHZAJL2X.js"),e=>(r,t)=>e.registerThemeCommands(r,t.getUrl)),o("plugin",()=>import("./plugin-AFWYIKJV.js"),e=>(r,t)=>e.registerPluginCommands(r,t.getUrl)),o("marketplace",()=>import("./marketplace-3ZWSDWGY.js"),e=>(r,t)=>e.registerMarketplaceCommands(r,t.getUrl)),o("skill",()=>import("./skill-KY4B46TS.js"),e=>(r,t)=>e.registerSkillCommands(r,t.getUrl,t.getContext)),o("guide",()=>import("./guide-I2YUWTE2.js"),e=>r=>e.registerGuideCommand(r)),o("diagnostics",()=>import("./diagnostics-SBKMH5AE.js"),e=>r=>e.registerDiagnosticsCommands(r)),o("voice",()=>import("./voice-VJKWLPWH.js"),e=>(r,t)=>e.registerVoiceCommands(r,t.getUrl))];function n(e){if(e==="--version"||e==="-V")return[];let r=m.find(t=>t.name===e);return r===void 0?m:[r]}function i(e,r){return e===void 0||e.length===0||e.startsWith("-")||r.has(e)?null:e}export{m as a,n as b,i as c};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module";import { dirname as __pathDirname } from "node:path";import { fileURLToPath as __fileURLToPath } from "node:url";const require = __createRequire(import.meta.url);const __filename = __fileURLToPath(import.meta.url);const __dirname = __pathDirname(__filename);
|
|
2
|
-
import{a}from"./chunk-
|
|
2
|
+
import{a}from"./chunk-YWDVXI6C.js";import{a as s,j as p}from"./chunk-LLWWPIPF.js";import{b as d}from"./chunk-NCQMSH7M.js";import"./chunk-WWZ7D6EQ.js";import{G as u}from"./chunk-3AXE4NG4.js";import"./chunk-VLWNZSJS.js";import{a as c}from"./chunk-ENKJDW2P.js";import"./chunk-G5CP5ERL.js";import"./chunk-MEAST3SW.js";import"./chunk-E7J2DJY7.js";import"./chunk-BNG7SSF7.js";import"./chunk-5PWLIQO6.js";function f(e){return e.registeredArguments.map(t=>{let o=`${t.name()}${t.variadic?"...":""}`;return t.required?`<${o}>`:`[${o}]`}).join(" ")}function g(e,t){return e.commands.flatMap(o=>{if(o.name()==="help")return[];let r=[...t,o.name()],i=g(o,r);return i.length>0?i:[{aliases:o.aliases(),arguments:f(o),description:o.description(),options:o.options.filter(n=>!n.hidden).map(n=>n.flags.replace(/^-\w, /u,"")),path:r.join(" ")}]})}async function C(e){let t=new d,o={getUrl:()=>"",getContext:()=>({serverUrl:""})};for(let n of a)(await n.load())(t,o);let r=g(t,[]);if(e===void 0)return r;let i=r.filter(n=>n.path===e||n.path.startsWith(`${e} `));if(i.length===0)throw new c({code:"invalid_value",hint:`Command groups: ${a.map(n=>n.name).join(", ")}`,message:`Unknown command group '${e}'.`});return i}function b(e,t){let r=[`bb ${[e.path,...e.aliases.map(n=>`|${n}`)].join("")}`,e.arguments].filter(n=>n.length>0).join(" "),i=t&&e.options.length>0?` ${e.options.map(n=>`[${n}]`).join(" ")}`:"";return`${r}${i}
|
|
3
3
|
${e.description}`}function j(e){e.command("guide [chapter] [group]").description("Show the Moonlet system overview and CLI guide; `bb guide commands [group]` lists every core command on one page").option("--json","Print machine-readable JSON output").action(p(async(t,o,r)=>{if(t==="commands"){let n=await C(o);if(s(r,{chapter:t,commands:n}))return;let m=n.map(l=>b(l,o!==void 0));console.log(m.join(`
|
|
4
4
|
`)),o===void 0&&console.log("\nRun `bb guide commands <group>` (for example `bb guide commands thread`) to include every option. Commands contributed by plugins are listed by `bb plugin list`.");return}let i=u().render({chapter:t});if(t){if(s(r,i))return;console.log(i.content);return}s(r,{overview:i.content})||console.log(i.content)}))}export{C as buildCommandIndex,j as registerGuideCommand};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module";import { dirname as __pathDirname } from "node:path";import { fileURLToPath as __fileURLToPath } from "node:url";const require = __createRequire(import.meta.url);const __filename = __fileURLToPath(import.meta.url);const __dirname = __pathDirname(__filename);
|
|
2
2
|
import{c as gt}from"./chunk-ZXUCBQR7.js";import{f as vt}from"./chunk-4L5JT7JK.js";import"./chunk-XSBF3HQR.js";import{a as f,d as M,e as ht,i as b,j as w}from"./chunk-LLWWPIPF.js";import{d as ft}from"./chunk-NCQMSH7M.js";import"./chunk-WWZ7D6EQ.js";import{b as G}from"./chunk-ZEP7SUMG.js";import{ba as ce,t as mt}from"./chunk-3AXE4NG4.js";import{e as T}from"./chunk-VLWNZSJS.js";import"./chunk-ENKJDW2P.js";import{b as pt}from"./chunk-G5CP5ERL.js";import"./chunk-MEAST3SW.js";import{e as Pe,f as Re}from"./chunk-E7J2DJY7.js";import{a as s}from"./chunk-BNG7SSF7.js";import"./chunk-5PWLIQO6.js";import{createHash as Es,randomBytes as Ms}from"node:crypto";import{existsSync as bs}from"node:fs";import{open as xs,rename as As,rm as Ps,stat as dt}from"node:fs/promises";import{basename as Rs,dirname as jr,join as ut,resolve as Lr}from"node:path";import{pipeline as _s}from"node:stream/promises";function St(e){if(e.length===0)return!1;let t=e.replaceAll("\\","/");return!t.startsWith("/")&&!/^[a-zA-Z]:\//u.test(t)&&t.split("/").every(r=>r!==""&&r!=="."&&r!=="..")}var Jr=s.string().min(1).refine(St,"Skill roots must be relative paths without dot segments"),wt=s.array(Jr).superRefine((e,t)=>{new Set(e).size!==e.length&&t.addIssue({code:"custom",message:"Skill roots must not contain duplicates"})}),yt=s.object({user:wt.default([]),project:wt.default([])}).strict(),Et=s.record(T,s.string().min(1)),Ls=s.object({flag:s.string().min(1),supportedLevels:s.array(T).min(1),levelValues:Et.optional(),defaultLevel:T.optional()}).strict().superRefine((e,t)=>{let r=new Set(e.supportedLevels);r.size!==e.supportedLevels.length&&t.addIssue({code:"custom",message:"supportedLevels must not contain duplicates",path:["supportedLevels"]}),e.defaultLevel!==void 0&&!r.has(e.defaultLevel)&&t.addIssue({code:"custom",message:"defaultLevel must be one of supportedLevels",path:["defaultLevel"]})}),Vs=s.object({configId:s.string().min(1),supportedLevels:s.array(T).min(1),levelValues:Et.optional(),defaultLevel:T.optional()}).strict().superRefine((e,t)=>{let r=new Set(e.supportedLevels);r.size!==e.supportedLevels.length&&t.addIssue({code:"custom",message:"supportedLevels must not contain duplicates",path:["supportedLevels"]}),e.defaultLevel!==void 0&&!r.has(e.defaultLevel)&&t.addIssue({code:"custom",message:"defaultLevel must be one of supportedLevels",path:["defaultLevel"]})}),_e=s.array(s.string().min(1)).min(1),Hs=s.object({full:_e.optional(),workspaceWrite:_e.optional(),readonly:_e.optional(),insertAfterArgs:s.number().int().min(0).optional()}).strict().superRefine((e,t)=>{e.full===void 0&&e.workspaceWrite===void 0&&e.readonly===void 0&&t.addIssue({code:"custom",message:"permissionCli must configure at least one permission mode"})});var Wr=["stop-work","update-target","export","transfer","start-target","verify-address","switch"],Ie=s.enum(Wr),K=s.enum(["connect","direct"]),le=s.object({moveId:s.string().min(1),fromHostId:s.string().min(1),fromHostName:s.string().min(1),toHostId:s.string().min(1),toHostName:s.string().min(1),completedAt:s.number().int().nonnegative(),oldCopyDeletedAt:s.number().int().nonnegative().nullable()}).strict(),Mt=["B","KB","MB","GB","TB"];function q(e){let t=e,r=0;for(;t>=1024&&r<Mt.length-1;)t/=1024,r+=1;return`${r===0||t>=10?Math.round(t):t.toFixed(1)} ${Mt[r]}`}import{rm as Tt}from"node:fs/promises";import{resolve as Ot,sep as mn}from"node:path";import{rm as cn,unlink as ln}from"node:fs/promises";import{join as E}from"node:path";var d=class extends Error{constructor(r,n,o){super(n,o);this.code=r;this.name="ServerArchiveError"}code};function v(e,t){return e instanceof Error&&"code"in e&&e.code===t}import{randomBytes as Gr}from"node:crypto";import{mkdir as Kr,readFile as qr,rename as Yr,rm as Xr,writeFile as Zr}from"node:fs/promises";import{dirname as Qr}from"node:path";async function ke(e){try{return await qr(e,"utf8")}catch(t){if(v(t,"ENOENT"))return null;throw t}}function Fe(e,t){try{return JSON.parse(t)}catch(r){throw new Error(`Invalid JSON at ${e}`,{cause:r})}}async function de(e,t){let r=await ke(e);if(r===null)return null;let n=t.safeParse(Fe(e,r));if(!n.success)throw new Error(`Invalid ${e}: ${n.error.message}`,{cause:n.error});return n.data}async function Y(e,t){await Kr(Qr(e),{recursive:!0});let r=`${e}.${Gr(6).toString("hex")}.tmp`;try{await Zr(r,`${JSON.stringify(t,null,2)}
|
|
3
|
-
`,{encoding:"utf8",mode:384}),await Yr(r,e)}catch(n){throw await Xr(r,{force:!0}),n}}import{join as en}from"node:path";var tn=4096,rn=/[\u0000-\u001f\u007f]/u;function O(e){return e.length===0||Buffer.byteLength(e)>tn||e.includes("\\")||rn.test(e)?!1:e.split("/").every(t=>t.length>0&&t!=="."&&t!=="..")}var bt=s.string().refine(O,{message:"Expected a relative POSIX path without '.' or '..' segments"});function Ce(e){let t=new Set;for(let r of e){if(t.has(r))return r;t.add(r)}for(let r of e){let n=r.split("/");for(let o=1;o<n.length;o+=1)if(t.has(n.slice(0,o).join("/")))return r}return null}function h(e,t){return en(e,...t.split("/"))}var xt=["bb.db","config.json","env.json","auth-secret","machine-environment-key","AGENTS.md","telemetry-id"],At=["attachments","skills","theme"],Pt="plugins",nn=new Set(xt),on=new Set(At),Rt=new Set(["npm","cache","snapshots"]),sn=new Set(["host-data","bridge-data","logs","data.db-wal","data.db-shm","data.db-journal"]),an="toolchain-";function _t(e){return!Rt.has(e)&&!e.startsWith(an)&&mt.safeParse(e).success}function It(e){let t=e.split("/"),r=t[0]??"";if(nn.has(r))return{path:r,kind:"file"};if(on.has(r))return{path:r,kind:"tree"};if(r!==Pt||t.length<2)return null;let n=t[1]??"";if(Rt.has(n))return{path:t.slice(0,2).join("/"),kind:"tree"};let o=t[2]??"";return t.length<3||!_t(n)||sn.has(o)?null:{path:t.slice(0,3).join("/"),kind:"tree"}}function X(e){if(!O(e))return!1;let t=It(e);return t!==null&&(t.kind==="tree"||t.path===e)}var Z="server-moved.json",R="server-import.json",D="server-import-journal.json";var Q="server-connect-hold.json",P=s.string().min(1),ue=s.number().int().nonnegative(),me=s.string().refine(X,{message:"Expected a server-owned path relative to the data directory"}),Ne=s.object({version:s.literal(1),moveId:P,movedAt:ue,fromHostId:P,toHostId:P,toHostName:P,serverUrl:s.string().min(1),mode:K,connectHandle:s.string().min(1).nullable(),oldCopyEntries:s.array(me)}).strict(),dn=s.enum(["move","manual"]),kt=s.object({version:s.literal(1),kind:dn,moveId:P.nullable(),activationToken:s.string().min(1).nullable(),sourceDataDir:s.string().min(1),sourceServerHostId:P.nullable(),targetHostId:P.nullable(),serverUrl:s.string().min(1).nullable(),importedEntries:s.array(me),createdAt:ue,fixupsAppliedAt:ue.nullable()}).strict().superRefine((e,t)=>{e.kind==="move"&&(e.moveId===null&&t.addIssue({code:"custom",message:"A move import requires a moveId",path:["moveId"]}),e.activationToken===null&&t.addIssue({code:"custom",message:"A move import requires an activationToken",path:["activationToken"]}))}),Ft=s.object({version:s.literal(1),entries:s.array(me),preexistingEntries:s.array(me)}).strict(),da=le.extend({version:s.literal(1)}).strict(),un=s.object({version:s.literal(1),reason:s.literal("manual-import"),createdAt:ue}).strict();function B(e){return de(E(e,Z),Ne)}async function Te(e,t){await Y(E(e,Z),Ne.parse(t))}function pe(e){return de(E(e,R),kt)}async function Oe(e,t){await Y(E(e,R),kt.parse(t))}function Ct(e){return de(E(e,D),Ft)}async function Nt(e,t){await Y(E(e,D),Ft.parse(t))}async function $(e){await cn(E(e,D),{force:!0})}async function ee(e){let t=await Ct(e);if(t===null)return{kind:"none"};let r=await pe(e);if(r===null)return{kind:"interrupted",journal:t};let n=new Set(r.importedEntries);return t.entries.every(o=>n.has(o))?{kind:"committed",journal:t}:{kind:"interrupted",journal:t}}async function De(e,t){await Y(E(e,Q),un.parse(t))}async function L(e){try{return await ln(E(e,Q)),!0}catch(t){if(v(t,"ENOENT"))return!1;throw t}}var pn=new Set(["auth.json","bb-app-runtime.json","checkouts","config.json","daemon.lock","env.json","host-id","last-server-move.json","logs","npm","personal-workspaces","runtime","server-moved.json","thread-storage","worktrees"]);async function Be(e,t,r=()=>{}){let n=Ot(e),o=[];for(let i of t.oldCopyEntries){let a=Ot(n,...i.split("/")),c=i.split("/")[0]??i;if(!a.startsWith(`${n}${mn}`)||pn.has(c)){r(i);continue}await Tt(a,{recursive:!0,force:!0}),i.endsWith(".db")&&await Promise.all(["-wal","-shm","-journal"].map(l=>Tt(`${a}${l}`,{force:!0}))),o.push(i)}return await Te(e,{...t,oldCopyEntries:[]}),{dataDir:e,deleted:!0,deletedEntries:o}}import{open as hn}from"node:fs/promises";var $e=Buffer.from([31,139]),Dt=Buffer.from("BBSA","ascii");async function fn(e){let t=await hn(e,"r");try{let r=Buffer.alloc(Dt.length),{bytesRead:n}=await t.read(r,0,r.length,0);return r.subarray(0,n)}finally{await t.close()}}async function te(e){let t=await fn(e);if(t.equals(Dt))throw new d("unsupported_version","This export was encrypted by an older bb; re-export it with bb server export");if(t.length<$e.length||!t.subarray(0,$e.length).equals($e))throw new d("corrupt","File is not a bb server archive")}import{createHash as jn}from"node:crypto";import{createReadStream as zn,createWriteStream as Un}from"node:fs";import{mkdir as Jt,readdir as Jn,rm as Wn}from"node:fs/promises";import{dirname as Gn,join as Wt}from"node:path";import{pipeline as Gt}from"node:stream/promises";import{createGunzip as Kn}from"node:zlib";var Le="bb-server-archive",he=2,fe="manifest.json",_="files",vn=s.object({path:bt,size:s.number().int().nonnegative(),sha256:s.string().regex(/^[0-9a-f]{64}$/u)}).strict(),Ve=s.object({format:s.literal(Le),version:s.literal(he),createdAt:s.number().int().nonnegative(),bbVersion:s.string().min(1),protocolVersion:s.number().int().nonnegative(),migrationCount:s.number().int().nonnegative(),sourceDataDir:s.string().min(1),sourceServerHostId:s.string().min(1).nullable(),serverMoveExperiment:s.boolean(),entries:s.array(vn)}).strict().superRefine((e,t)=>{let r=Ce(e.entries.map(n=>n.path));r!==null&&t.addIssue({code:"custom",message:`Archive path ${r} conflicts with another entry`,path:["entries"]})}),gn=s.object({format:s.literal(Le),version:s.number()});function Bt(e){let t=gn.safeParse(e);if(!t.success)throw new d("corrupt","Archive manifest is not a bb server archive manifest");if(t.data.version!==he)throw new d("unsupported_version",`Unsupported bb server archive version ${String(t.data.version)}`);let r=Ve.safeParse(e);if(!r.success)throw new d("corrupt",`Archive manifest is invalid: ${r.error.message}`);return r.data}import{posix as V}from"node:path";var $t=(e,t)=>{if(Number.isSafeInteger(e))e<0?wn(e,t):Sn(e,t);else throw Error("cannot encode number outside of javascript safe integer range");return t},Sn=(e,t)=>{t[0]=128;for(var r=t.length;r>1;r--)t[r-1]=e&255,e=Math.floor(e/256)},wn=(e,t)=>{t[0]=255;var r=!1;e=e*-1;for(var n=t.length;n>1;n--){var o=e&255;e=Math.floor(e/256),r?t[n-1]=Vt(o):o===0?t[n-1]=0:(r=!0,t[n-1]=Ht(o))}},Lt=e=>{let t=e[0],r=t===128?En(e.subarray(1,e.length)):t===255?yn(e):null;if(r===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(r))throw Error("parsed number outside of javascript safe integer range");return r},yn=e=>{for(var t=e.length,r=0,n=!1,o=t-1;o>-1;o--){var i=Number(e[o]),a;n?a=Vt(i):i===0?a=i:(n=!0,a=Ht(i)),a!==0&&(r-=a*Math.pow(256,t-o-1))}return r},En=e=>{for(var t=e.length,r=0,n=t-1;n>-1;n--){var o=Number(e[n]);o!==0&&(r+=o*Math.pow(256,t-n-1))}return r},Vt=e=>(255^e)&255,Ht=e=>(255^e)+1&255;var ve=e=>ge.has(e);var jt=new Set(["0","","1","2","3","4","5","6","7","D"]),ge=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]),zt=new Map(Array.from(ge).map(e=>[e[1],e[0]]));var xn=e=>e===void 0||e<0?void 0:e,H=class{cksumValid=!1;needPax=!1;nullBlock=!1;block;path;mode;uid;gid;size;cksum;#t="Unsupported";linkpath;uname;gname;devmaj=0;devmin=0;atime;ctime;mtime;charset;comment;constructor(t,r=0,n,o){Buffer.isBuffer(t)?this.decode(t,r||0,n,o):t&&this.#e(t)}decode(t,r,n,o){if(r||(r=0),!t||!(t.length>=r+512))throw new Error("need 512 bytes for header");let i=I(t,r+156,1),a=jt.has(i),c=a?n:void 0,l=a?o:void 0;if(this.path=c?.path??I(t,r,100),this.mode=c?.mode??l?.mode??x(t,r+100,8),this.uid=c?.uid??l?.uid??x(t,r+108,8),this.gid=c?.gid??l?.gid??x(t,r+116,8),this.size=xn(c?.size??l?.size??x(t,r+124,12)),this.mtime=c?.mtime??l?.mtime??He(t,r+136,12),this.cksum=x(t,r+148,12),l&&this.#e(l,!0),c&&this.#e(c),ve(i)&&(this.#t=i||"0"),this.#t==="0"&&this.path.slice(-1)==="/"&&(this.#t="5"),this.#t==="5"&&(this.size=0),this.linkpath=I(t,r+157,100),t.subarray(r+257,r+265).toString()==="ustar\x0000")if(this.uname=c?.uname??l?.uname??I(t,r+265,32),this.gname=c?.gname??l?.gname??I(t,r+297,32),this.devmaj=c?.devmaj??l?.devmaj??x(t,r+329,8)??0,this.devmin=c?.devmin??l?.devmin??x(t,r+337,8)??0,t[r+475]!==0){let m=I(t,r+345,155);this.path=m+"/"+this.path}else{let m=I(t,r+345,130);m&&(this.path=m+"/"+this.path),this.atime=n?.atime??o?.atime??He(t,r+476,12),this.ctime=n?.ctime??o?.ctime??He(t,r+488,12)}let u=256;for(let m=r;m<r+148;m++)u+=t[m];for(let m=r+156;m<r+512;m++)u+=t[m];this.cksumValid=u===this.cksum,this.cksum===void 0&&u===256&&(this.nullBlock=!0)}#e(t,r=!1){Object.assign(this,Object.fromEntries(Object.entries(t).filter(([n,o])=>!(o==null||n==="size"&&Number(o)<0||n==="path"&&r||n==="linkpath"&&r||n==="global"))))}encode(t,r=0){if(t||(t=this.block=Buffer.alloc(512)),this.#t==="Unsupported"&&(this.#t="0"),!(t.length>=r+512))throw new Error("need 512 bytes for header");let n=this.ctime||this.atime?130:155,o=An(this.path||"",n),i=o[0],a=o[1];this.needPax=!!o[2],this.needPax=k(t,r,100,i)||this.needPax,this.needPax=A(t,r+100,8,this.mode)||this.needPax,this.needPax=A(t,r+108,8,this.uid)||this.needPax,this.needPax=A(t,r+116,8,this.gid)||this.needPax,this.needPax=A(t,r+124,12,this.size)||this.needPax,this.needPax=je(t,r+136,12,this.mtime)||this.needPax,t[r+156]=Number(this.#t.codePointAt(0)),this.needPax=k(t,r+157,100,this.linkpath)||this.needPax,t.write("ustar\x0000",r+257,8),this.needPax=k(t,r+265,32,this.uname)||this.needPax,this.needPax=k(t,r+297,32,this.gname)||this.needPax,this.needPax=A(t,r+329,8,this.devmaj)||this.needPax,this.needPax=A(t,r+337,8,this.devmin)||this.needPax,this.needPax=k(t,r+345,n,a)||this.needPax,t[r+475]!==0?this.needPax=k(t,r+345,155,a)||this.needPax:(this.needPax=k(t,r+345,130,a)||this.needPax,this.needPax=je(t,r+476,12,this.atime)||this.needPax,this.needPax=je(t,r+488,12,this.ctime)||this.needPax);let c=256;for(let l=r;l<r+148;l++)c+=t[l];for(let l=r+156;l<r+512;l++)c+=t[l];return this.cksum=c,A(t,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}get type(){return this.#t==="Unsupported"?this.#t:ge.get(this.#t)}get typeKey(){return this.#t}set type(t){let r=String(zt.get(t));if(ve(r)||r==="Unsupported")this.#t=r;else if(ve(t))this.#t=t;else throw new TypeError("invalid entry type: "+t)}},An=(e,t)=>{let n=e,o="",i,a=V.parse(e).root||".";if(Buffer.byteLength(n)<100)i=[n,o,!1];else{o=V.dirname(n),n=V.basename(n);do Buffer.byteLength(n)<=100&&Buffer.byteLength(o)<=t?i=[n,o,!1]:Buffer.byteLength(n)>100&&Buffer.byteLength(o)<=t?i=[n.slice(0,99),o,!0]:(n=V.join(V.basename(o),n),o=V.dirname(o));while(o!==a&&i===void 0);i||(i=[e.slice(0,99),"",!0])}return i},I=(e,t,r)=>e.subarray(t,t+r).toString("utf8").replace(/\0.*/,""),He=(e,t,r)=>Pn(x(e,t,r)),Pn=e=>e===void 0?void 0:new Date(e*1e3),x=(e,t,r)=>Number(e[t])&128?Lt(e.subarray(t,t+r)):_n(e,t,r),Rn=e=>isNaN(e)?void 0:e,_n=(e,t,r)=>Rn(parseInt(e.subarray(t,t+r).toString("utf8").replace(/\0.*$/,"").trim(),8)),In={12:8589934591,8:2097151},A=(e,t,r,n)=>n===void 0?!1:n>In[r]||n<0?($t(n,e.subarray(t,t+r)),!0):(kn(e,t,r,n),!1),kn=(e,t,r,n)=>e.write(Fn(n,r),t,r,"ascii"),Fn=(e,t)=>Cn(Math.floor(e).toString(8),t),Cn=(e,t)=>(e.length===t-1?e:new Array(t-e.length-1).join("0")+e+" ")+"\0",je=(e,t,r,n)=>n===void 0?!1:A(e,t,r,n.getTime()/1e3),Nn=new Array(156).join("\0"),k=(e,t,r,n)=>n===void 0?!1:(e.write(n+Nn,t,r,"utf8"),n.length!==Buffer.byteLength(n)||n.length>r);import{basename as Tn}from"node:path";var Se=class e{atime;mtime;ctime;charset;comment;gid;uid;gname;uname;linkpath;dev;ino;nlink;path;size;mode;global;constructor(t,r=!1){this.atime=t.atime,this.charset=t.charset,this.comment=t.comment,this.ctime=t.ctime,this.dev=t.dev,this.gid=t.gid,this.global=r,this.gname=t.gname,this.ino=t.ino,this.linkpath=t.linkpath,this.mtime=t.mtime,this.nlink=t.nlink,this.path=t.path,this.size=t.size,this.uid=t.uid,this.uname=t.uname}encode(){let t=this.encodeBody();if(t==="")return Buffer.allocUnsafe(0);let r=Buffer.byteLength(t),n=512*Math.ceil(1+r/512),o=Buffer.allocUnsafe(n);for(let i=0;i<512;i++)o[i]=0;new H({path:("PaxHeader/"+Tn(this.path??"")).slice(0,99),mode:this.mode||420,uid:this.uid,gid:this.gid,size:r,mtime:this.mtime,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime,ctime:this.ctime}).encode(o),o.write(t,512,r,"utf8");for(let i=r+512;i<o.length;i++)o[i]=0;return o}encodeBody(){return this.encodeField("path")+this.encodeField("ctime")+this.encodeField("atime")+this.encodeField("dev")+this.encodeField("ino")+this.encodeField("nlink")+this.encodeField("charset")+this.encodeField("comment")+this.encodeField("gid")+this.encodeField("gname")+this.encodeField("linkpath")+this.encodeField("mtime")+this.encodeField("size")+this.encodeField("uid")+this.encodeField("uname")}encodeField(t){if(this[t]===void 0)return"";let r=this[t],n=r instanceof Date?r.getTime()/1e3:r,o=" "+(t==="dev"||t==="ino"||t==="nlink"?"SCHILY.":"")+t+"="+n+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),await Yr(r,e)}catch(n){throw await Xr(r,{force:!0}),n}}import{join as en}from"node:path";var tn=4096,rn=/[\u0000-\u001f\u007f]/u;function O(e){return e.length===0||Buffer.byteLength(e)>tn||e.includes("\\")||rn.test(e)?!1:e.split("/").every(t=>t.length>0&&t!=="."&&t!=="..")}var bt=s.string().refine(O,{message:"Expected a relative POSIX path without '.' or '..' segments"});function Ce(e){let t=new Set;for(let r of e){if(t.has(r))return r;t.add(r)}for(let r of e){let n=r.split("/");for(let o=1;o<n.length;o+=1)if(t.has(n.slice(0,o).join("/")))return r}return null}function h(e,t){return en(e,...t.split("/"))}var xt=["bb.db","config.json","env.json","auth-secret","machine-environment-key","AGENTS.md","telemetry-id"],At=["attachments","skills","theme","secrets"],Pt="plugins",nn=new Set(xt),on=new Set(At),Rt=new Set(["npm","cache","snapshots"]),sn=new Set(["host-data","bridge-data","logs","data.db-wal","data.db-shm","data.db-journal"]),an="toolchain-";function _t(e){return!Rt.has(e)&&!e.startsWith(an)&&mt.safeParse(e).success}function It(e){let t=e.split("/"),r=t[0]??"";if(nn.has(r))return{path:r,kind:"file"};if(on.has(r))return{path:r,kind:"tree"};if(r!==Pt||t.length<2)return null;let n=t[1]??"";if(Rt.has(n))return{path:t.slice(0,2).join("/"),kind:"tree"};let o=t[2]??"";return t.length<3||!_t(n)||sn.has(o)?null:{path:t.slice(0,3).join("/"),kind:"tree"}}function X(e){if(!O(e))return!1;let t=It(e);return t!==null&&(t.kind==="tree"||t.path===e)}var Z="server-moved.json",R="server-import.json",D="server-import-journal.json";var Q="server-connect-hold.json",P=s.string().min(1),ue=s.number().int().nonnegative(),me=s.string().refine(X,{message:"Expected a server-owned path relative to the data directory"}),Ne=s.object({version:s.literal(1),moveId:P,movedAt:ue,fromHostId:P,toHostId:P,toHostName:P,serverUrl:s.string().min(1),mode:K,connectHandle:s.string().min(1).nullable(),oldCopyEntries:s.array(me)}).strict(),dn=s.enum(["move","manual"]),kt=s.object({version:s.literal(1),kind:dn,moveId:P.nullable(),activationToken:s.string().min(1).nullable(),sourceDataDir:s.string().min(1),sourceServerHostId:P.nullable(),targetHostId:P.nullable(),serverUrl:s.string().min(1).nullable(),importedEntries:s.array(me),createdAt:ue,fixupsAppliedAt:ue.nullable()}).strict().superRefine((e,t)=>{e.kind==="move"&&(e.moveId===null&&t.addIssue({code:"custom",message:"A move import requires a moveId",path:["moveId"]}),e.activationToken===null&&t.addIssue({code:"custom",message:"A move import requires an activationToken",path:["activationToken"]}))}),Ft=s.object({version:s.literal(1),entries:s.array(me),preexistingEntries:s.array(me)}).strict(),da=le.extend({version:s.literal(1)}).strict(),un=s.object({version:s.literal(1),reason:s.literal("manual-import"),createdAt:ue}).strict();function B(e){return de(E(e,Z),Ne)}async function Te(e,t){await Y(E(e,Z),Ne.parse(t))}function pe(e){return de(E(e,R),kt)}async function Oe(e,t){await Y(E(e,R),kt.parse(t))}function Ct(e){return de(E(e,D),Ft)}async function Nt(e,t){await Y(E(e,D),Ft.parse(t))}async function $(e){await cn(E(e,D),{force:!0})}async function ee(e){let t=await Ct(e);if(t===null)return{kind:"none"};let r=await pe(e);if(r===null)return{kind:"interrupted",journal:t};let n=new Set(r.importedEntries);return t.entries.every(o=>n.has(o))?{kind:"committed",journal:t}:{kind:"interrupted",journal:t}}async function De(e,t){await Y(E(e,Q),un.parse(t))}async function L(e){try{return await ln(E(e,Q)),!0}catch(t){if(v(t,"ENOENT"))return!1;throw t}}var pn=new Set(["auth.json","bb-app-runtime.json","checkouts","config.json","daemon.lock","env.json","host-id","last-server-move.json","logs","npm","personal-workspaces","runtime","server-moved.json","thread-storage","worktrees"]);async function Be(e,t,r=()=>{}){let n=Ot(e),o=[];for(let i of t.oldCopyEntries){let a=Ot(n,...i.split("/")),c=i.split("/")[0]??i;if(!a.startsWith(`${n}${mn}`)||pn.has(c)){r(i);continue}await Tt(a,{recursive:!0,force:!0}),i.endsWith(".db")&&await Promise.all(["-wal","-shm","-journal"].map(l=>Tt(`${a}${l}`,{force:!0}))),o.push(i)}return await Te(e,{...t,oldCopyEntries:[]}),{dataDir:e,deleted:!0,deletedEntries:o}}import{open as hn}from"node:fs/promises";var $e=Buffer.from([31,139]),Dt=Buffer.from("BBSA","ascii");async function fn(e){let t=await hn(e,"r");try{let r=Buffer.alloc(Dt.length),{bytesRead:n}=await t.read(r,0,r.length,0);return r.subarray(0,n)}finally{await t.close()}}async function te(e){let t=await fn(e);if(t.equals(Dt))throw new d("unsupported_version","This export was encrypted by an older bb; re-export it with bb server export");if(t.length<$e.length||!t.subarray(0,$e.length).equals($e))throw new d("corrupt","File is not a bb server archive")}import{createHash as jn}from"node:crypto";import{createReadStream as zn,createWriteStream as Un}from"node:fs";import{mkdir as Jt,readdir as Jn,rm as Wn}from"node:fs/promises";import{dirname as Gn,join as Wt}from"node:path";import{pipeline as Gt}from"node:stream/promises";import{createGunzip as Kn}from"node:zlib";var Le="bb-server-archive",he=2,fe="manifest.json",_="files",vn=s.object({path:bt,size:s.number().int().nonnegative(),sha256:s.string().regex(/^[0-9a-f]{64}$/u)}).strict(),Ve=s.object({format:s.literal(Le),version:s.literal(he),createdAt:s.number().int().nonnegative(),bbVersion:s.string().min(1),protocolVersion:s.number().int().nonnegative(),migrationCount:s.number().int().nonnegative(),sourceDataDir:s.string().min(1),sourceServerHostId:s.string().min(1).nullable(),serverMoveExperiment:s.boolean(),entries:s.array(vn)}).strict().superRefine((e,t)=>{let r=Ce(e.entries.map(n=>n.path));r!==null&&t.addIssue({code:"custom",message:`Archive path ${r} conflicts with another entry`,path:["entries"]})}),gn=s.object({format:s.literal(Le),version:s.number()});function Bt(e){let t=gn.safeParse(e);if(!t.success)throw new d("corrupt","Archive manifest is not a bb server archive manifest");if(t.data.version!==he)throw new d("unsupported_version",`Unsupported bb server archive version ${String(t.data.version)}`);let r=Ve.safeParse(e);if(!r.success)throw new d("corrupt",`Archive manifest is invalid: ${r.error.message}`);return r.data}import{posix as V}from"node:path";var $t=(e,t)=>{if(Number.isSafeInteger(e))e<0?wn(e,t):Sn(e,t);else throw Error("cannot encode number outside of javascript safe integer range");return t},Sn=(e,t)=>{t[0]=128;for(var r=t.length;r>1;r--)t[r-1]=e&255,e=Math.floor(e/256)},wn=(e,t)=>{t[0]=255;var r=!1;e=e*-1;for(var n=t.length;n>1;n--){var o=e&255;e=Math.floor(e/256),r?t[n-1]=Vt(o):o===0?t[n-1]=0:(r=!0,t[n-1]=Ht(o))}},Lt=e=>{let t=e[0],r=t===128?En(e.subarray(1,e.length)):t===255?yn(e):null;if(r===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(r))throw Error("parsed number outside of javascript safe integer range");return r},yn=e=>{for(var t=e.length,r=0,n=!1,o=t-1;o>-1;o--){var i=Number(e[o]),a;n?a=Vt(i):i===0?a=i:(n=!0,a=Ht(i)),a!==0&&(r-=a*Math.pow(256,t-o-1))}return r},En=e=>{for(var t=e.length,r=0,n=t-1;n>-1;n--){var o=Number(e[n]);o!==0&&(r+=o*Math.pow(256,t-n-1))}return r},Vt=e=>(255^e)&255,Ht=e=>(255^e)+1&255;var ve=e=>ge.has(e);var jt=new Set(["0","","1","2","3","4","5","6","7","D"]),ge=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]),zt=new Map(Array.from(ge).map(e=>[e[1],e[0]]));var xn=e=>e===void 0||e<0?void 0:e,H=class{cksumValid=!1;needPax=!1;nullBlock=!1;block;path;mode;uid;gid;size;cksum;#t="Unsupported";linkpath;uname;gname;devmaj=0;devmin=0;atime;ctime;mtime;charset;comment;constructor(t,r=0,n,o){Buffer.isBuffer(t)?this.decode(t,r||0,n,o):t&&this.#e(t)}decode(t,r,n,o){if(r||(r=0),!t||!(t.length>=r+512))throw new Error("need 512 bytes for header");let i=I(t,r+156,1),a=jt.has(i),c=a?n:void 0,l=a?o:void 0;if(this.path=c?.path??I(t,r,100),this.mode=c?.mode??l?.mode??x(t,r+100,8),this.uid=c?.uid??l?.uid??x(t,r+108,8),this.gid=c?.gid??l?.gid??x(t,r+116,8),this.size=xn(c?.size??l?.size??x(t,r+124,12)),this.mtime=c?.mtime??l?.mtime??He(t,r+136,12),this.cksum=x(t,r+148,12),l&&this.#e(l,!0),c&&this.#e(c),ve(i)&&(this.#t=i||"0"),this.#t==="0"&&this.path.slice(-1)==="/"&&(this.#t="5"),this.#t==="5"&&(this.size=0),this.linkpath=I(t,r+157,100),t.subarray(r+257,r+265).toString()==="ustar\x0000")if(this.uname=c?.uname??l?.uname??I(t,r+265,32),this.gname=c?.gname??l?.gname??I(t,r+297,32),this.devmaj=c?.devmaj??l?.devmaj??x(t,r+329,8)??0,this.devmin=c?.devmin??l?.devmin??x(t,r+337,8)??0,t[r+475]!==0){let m=I(t,r+345,155);this.path=m+"/"+this.path}else{let m=I(t,r+345,130);m&&(this.path=m+"/"+this.path),this.atime=n?.atime??o?.atime??He(t,r+476,12),this.ctime=n?.ctime??o?.ctime??He(t,r+488,12)}let u=256;for(let m=r;m<r+148;m++)u+=t[m];for(let m=r+156;m<r+512;m++)u+=t[m];this.cksumValid=u===this.cksum,this.cksum===void 0&&u===256&&(this.nullBlock=!0)}#e(t,r=!1){Object.assign(this,Object.fromEntries(Object.entries(t).filter(([n,o])=>!(o==null||n==="size"&&Number(o)<0||n==="path"&&r||n==="linkpath"&&r||n==="global"))))}encode(t,r=0){if(t||(t=this.block=Buffer.alloc(512)),this.#t==="Unsupported"&&(this.#t="0"),!(t.length>=r+512))throw new Error("need 512 bytes for header");let n=this.ctime||this.atime?130:155,o=An(this.path||"",n),i=o[0],a=o[1];this.needPax=!!o[2],this.needPax=k(t,r,100,i)||this.needPax,this.needPax=A(t,r+100,8,this.mode)||this.needPax,this.needPax=A(t,r+108,8,this.uid)||this.needPax,this.needPax=A(t,r+116,8,this.gid)||this.needPax,this.needPax=A(t,r+124,12,this.size)||this.needPax,this.needPax=je(t,r+136,12,this.mtime)||this.needPax,t[r+156]=Number(this.#t.codePointAt(0)),this.needPax=k(t,r+157,100,this.linkpath)||this.needPax,t.write("ustar\x0000",r+257,8),this.needPax=k(t,r+265,32,this.uname)||this.needPax,this.needPax=k(t,r+297,32,this.gname)||this.needPax,this.needPax=A(t,r+329,8,this.devmaj)||this.needPax,this.needPax=A(t,r+337,8,this.devmin)||this.needPax,this.needPax=k(t,r+345,n,a)||this.needPax,t[r+475]!==0?this.needPax=k(t,r+345,155,a)||this.needPax:(this.needPax=k(t,r+345,130,a)||this.needPax,this.needPax=je(t,r+476,12,this.atime)||this.needPax,this.needPax=je(t,r+488,12,this.ctime)||this.needPax);let c=256;for(let l=r;l<r+148;l++)c+=t[l];for(let l=r+156;l<r+512;l++)c+=t[l];return this.cksum=c,A(t,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}get type(){return this.#t==="Unsupported"?this.#t:ge.get(this.#t)}get typeKey(){return this.#t}set type(t){let r=String(zt.get(t));if(ve(r)||r==="Unsupported")this.#t=r;else if(ve(t))this.#t=t;else throw new TypeError("invalid entry type: "+t)}},An=(e,t)=>{let n=e,o="",i,a=V.parse(e).root||".";if(Buffer.byteLength(n)<100)i=[n,o,!1];else{o=V.dirname(n),n=V.basename(n);do Buffer.byteLength(n)<=100&&Buffer.byteLength(o)<=t?i=[n,o,!1]:Buffer.byteLength(n)>100&&Buffer.byteLength(o)<=t?i=[n.slice(0,99),o,!0]:(n=V.join(V.basename(o),n),o=V.dirname(o));while(o!==a&&i===void 0);i||(i=[e.slice(0,99),"",!0])}return i},I=(e,t,r)=>e.subarray(t,t+r).toString("utf8").replace(/\0.*/,""),He=(e,t,r)=>Pn(x(e,t,r)),Pn=e=>e===void 0?void 0:new Date(e*1e3),x=(e,t,r)=>Number(e[t])&128?Lt(e.subarray(t,t+r)):_n(e,t,r),Rn=e=>isNaN(e)?void 0:e,_n=(e,t,r)=>Rn(parseInt(e.subarray(t,t+r).toString("utf8").replace(/\0.*$/,"").trim(),8)),In={12:8589934591,8:2097151},A=(e,t,r,n)=>n===void 0?!1:n>In[r]||n<0?($t(n,e.subarray(t,t+r)),!0):(kn(e,t,r,n),!1),kn=(e,t,r,n)=>e.write(Fn(n,r),t,r,"ascii"),Fn=(e,t)=>Cn(Math.floor(e).toString(8),t),Cn=(e,t)=>(e.length===t-1?e:new Array(t-e.length-1).join("0")+e+" ")+"\0",je=(e,t,r,n)=>n===void 0?!1:A(e,t,r,n.getTime()/1e3),Nn=new Array(156).join("\0"),k=(e,t,r,n)=>n===void 0?!1:(e.write(n+Nn,t,r,"utf8"),n.length!==Buffer.byteLength(n)||n.length>r);import{basename as Tn}from"node:path";var Se=class e{atime;mtime;ctime;charset;comment;gid;uid;gname;uname;linkpath;dev;ino;nlink;path;size;mode;global;constructor(t,r=!1){this.atime=t.atime,this.charset=t.charset,this.comment=t.comment,this.ctime=t.ctime,this.dev=t.dev,this.gid=t.gid,this.global=r,this.gname=t.gname,this.ino=t.ino,this.linkpath=t.linkpath,this.mtime=t.mtime,this.nlink=t.nlink,this.path=t.path,this.size=t.size,this.uid=t.uid,this.uname=t.uname}encode(){let t=this.encodeBody();if(t==="")return Buffer.allocUnsafe(0);let r=Buffer.byteLength(t),n=512*Math.ceil(1+r/512),o=Buffer.allocUnsafe(n);for(let i=0;i<512;i++)o[i]=0;new H({path:("PaxHeader/"+Tn(this.path??"")).slice(0,99),mode:this.mode||420,uid:this.uid,gid:this.gid,size:r,mtime:this.mtime,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime,ctime:this.ctime}).encode(o),o.write(t,512,r,"utf8");for(let i=r+512;i<o.length;i++)o[i]=0;return o}encodeBody(){return this.encodeField("path")+this.encodeField("ctime")+this.encodeField("atime")+this.encodeField("dev")+this.encodeField("ino")+this.encodeField("nlink")+this.encodeField("charset")+this.encodeField("comment")+this.encodeField("gid")+this.encodeField("gname")+this.encodeField("linkpath")+this.encodeField("mtime")+this.encodeField("size")+this.encodeField("uid")+this.encodeField("uname")}encodeField(t){if(this[t]===void 0)return"";let r=this[t],n=r instanceof Date?r.getTime()/1e3:r,o=" "+(t==="dev"||t==="ino"||t==="nlink"?"SCHILY.":"")+t+"="+n+`
|
|
4
4
|
`,i=Buffer.byteLength(o),a=Math.floor(Math.log(i)/Math.log(10))+1;return i+a>=Math.pow(10,a)&&(a+=1),a+i+o}static parse(t,r,n=!1){return new e(On(Dn(t),r),n)}},On=(e,t)=>t?Object.assign({},t,e):e,Dn=e=>e.replace(/\n$/,"").split(`
|
|
5
|
-
`).reduce(Bn,Object.create(null)),Bn=(e,t)=>{let r=parseInt(t,10);if(r!==Buffer.byteLength(t)+1)return e;t=t.slice((r+" ").length);let n=t.split("="),o=n.shift();if(!o)return e;let i=o.replace(/^SCHILY\.(dev|ino|nlink)/,"$1"),a=n.join("=").replace(/\0.*/,"");switch(i){case"path":case"linkpath":case"type":case"charset":case"comment":case"gname":case"uname":e[i]=a;break;case"ctime":case"atime":case"mtime":e[i]=new Date(Number(a)*1e3);break;case"size":let c=+a;c>=0&&(e[i]=c);break;case"gid":case"uid":case"dev":case"ino":case"nlink":case"mode":e[i]=+a;break}return e};var re=512,$n=Buffer.alloc(re),Ln=1024*1024,Vn=1024*1024,Hn=Buffer.alloc(re*2);function Ut(e){let t=e%re;return t===0?Buffer.alloc(0):Buffer.alloc(re-t)}function g(e){return new d("corrupt",e)}var we=class{#t;#e=Buffer.alloc(0);#s=!1;#r=0;constructor(t){this.#t=t[Symbol.asyncIterator]()}async#o(){if(this.#s)return!1;let t=await this.#t.next();return t.done===!0?(this.#s=!0,!1):(this.#e=this.#e.length===0?t.value:Buffer.concat([this.#e,t.value]),!0)}async#n(t){for(;this.#e.length<t;)if(!await this.#o()){if(this.#e.length===0)return null;throw g("Archive is truncated")}let r=this.#e.subarray(0,t);return this.#e=this.#e.subarray(t),r}async#i(t){let r=Ut(t).length;if(r>0&&await this.#n(r)===null)throw g("Archive is truncated")}async#a(){let t=0;for(;;){if(t+=this.#e.length,t>Vn||!this.#e.equals(Buffer.alloc(this.#e.length)))throw g("Archive has unexpected trailing data");if(this.#e=Buffer.alloc(0),!await this.#o())return}}async nextEntry(){if(this.#r>0)throw new Error("The previous tar entry body was not consumed");let t;for(;;){let r=await this.#n(re);if(r===null)throw g("Archive ended without an end-of-archive marker");if(r.equals($n)){if(t!==void 0)throw g("Archive ended after an extended header");return await this.#a(),null}let n=new H(r,0,t);if(!n.cksumValid)throw g("Archive entry header checksum is invalid");let o=n.size;if(o===void 0||!Number.isSafeInteger(o))throw g("Archive entry size is invalid");if(n.type==="ExtendedHeader"){if(t!==void 0)throw g("Archive has consecutive extended headers");if(o>Ln)throw g("Archive extended header is too large");let i=await this.#n(o);if(i===null)throw g("Archive is truncated");await this.#i(o),t=Se.parse(i.toString("utf8"),void 0,!1);continue}return this.#r=o,{path:t?.path??n.path??"",type:n.type,size:o,mode:n.mode??null}}}async readBodyBuffer(){let t=this.#r,r=t===0?Buffer.alloc(0):await this.#n(t);if(r===null)throw g("Archive is truncated");return this.#r=0,await this.#i(t),Buffer.from(r)}async*readBody(){let t=this.#r;for(;this.#r>0;){if(this.#e.length===0&&!await this.#o())throw g("Archive is truncated");let r=Math.min(this.#r,this.#e.length),n=this.#e.subarray(0,r);this.#e=this.#e.subarray(r),this.#r-=r,yield n}await this.#i(t)}};var qn=64*1024*1024;async function Yn(e){if(await Jt(e,{recursive:!0}),(await Jn(e)).length>0)throw new Error(`Archive extraction destination ${e} is not empty`)}function Xn(e){return e===null?384:e&493|384}function Zn(e){let t=`${_}/`,r=e.startsWith(t)?e.slice(t.length):null;if(r===null||!O(r))throw new d("unsafe_entry",`Archive entry ${JSON.stringify(e)} is not a safe path under ${t}`);return r}function Qn(e){try{return JSON.parse(e.toString("utf8"))}catch(t){throw new d("corrupt","Archive manifest is not JSON",{cause:t})}}async function eo(e,t,r,n){await Jt(Gn(t),{recursive:!0,mode:448});let o=jn("sha256");try{await Gt(e.readBody(),async function*(i){for await(let a of i)o.update(a),yield a},Un(t,{flags:"wx",mode:r}))}catch(i){throw v(i,"EEXIST")?new d("unsafe_entry",`Archive entry ${n.path} collides with another extracted file`,{cause:i}):i}if(o.digest("hex")!==n.sha256)throw new d("digest_mismatch",`Archive entry ${n.path} does not match its manifest digest`)}async function to(e,t){let r=new we(e),n=await r.nextEntry();if(n===null||n.type!=="File"||n.path!==fe)throw new d("corrupt",`Archive does not start with ${fe}`);if(n.size>qn)throw new d("corrupt","Archive manifest is too large");let o=Bt(Qn(await r.readBodyBuffer())),i=new Map(o.entries.map(c=>[c.path,c])),a=Wt(t,_);for(;;){let c=await r.nextEntry();if(c===null)break;if(c.type!=="File")throw new d("unsafe_entry",`Archive entry ${JSON.stringify(c.path)} has unsupported type ${c.type}`);let l=Zn(c.path),u=i.get(l);if(u===void 0)throw new d("unsafe_entry",`Archive entry ${l} is not listed in the manifest`);if(i.delete(l),c.size!==u.size)throw new d("digest_mismatch",`Archive entry ${l} is ${String(c.size)} bytes but the manifest lists ${String(u.size)}`);await eo(r,h(a,l),Xn(c.mode),u)}if(i.size>0)throw new d("corrupt",`Archive is missing ${String(i.size)} file(s) listed in its manifest`);return o}function ro(e){return e instanceof d?e:e instanceof Error&&"code"in e&&typeof e.code=="string"&&e.code.startsWith("Z_")?new d("corrupt",`Archive data is corrupt: ${e.message}`,{cause:e}):e}async function ze(e){await te(e.archivePath),await Yn(e.destinationDir);let t={manifest:null},r=async n=>{t.manifest=await to(n,e.destinationDir)};try{await Gt(zn(e.archivePath),Kn(),r)}catch(n){throw await Wn(Wt(e.destinationDir,_),{force:!0,recursive:!0}),ro(n)}if(t.manifest===null)throw new d("corrupt","Archive has no manifest");return t.manifest}import{randomBytes as Po}from"node:crypto";import{copyFile as Ro,mkdir as Ee,readdir as ec,rename as Ge,rm as z,rmdir as _o,unlink as Io}from"node:fs/promises";import{basename as Qt,dirname as Me,join as S,posix as Yt,resolve as ye}from"node:path";import{join as no}from"node:path";var oo=["codex","claude-code","pi","acp-cursor"],io="config.json";var so=["BB_INFERENCE","BB_INFERENCE_FALLBACK","BB_TRANSCRIPTION"],ao="BB_INFERENCE, BB_INFERENCE_FALLBACK, and BB_TRANSCRIPTION were removed. Choose AI services in Settings \u2192 AI services or with `bb settings ai-services set <task> <automatic|off|service>`.",co=/^[A-Za-z_][A-Za-z0-9_]*$/u,Ue="customAcpAgents",lo="customAcpAgents in config.json is no longer read. Declare the agents with `bb plugin config provider-acp set customAgents '<json>'`.",uo=s.object({BB_APP_URL:s.string().optional(),BB_LOG_LEVEL:s.string().optional()}).strict(),mo=/^acp-[a-z0-9][a-z0-9-]*$/u,po=s.union([s.enum(oo),s.string().regex(mo)]),ho=s.object({providerId:po,model:s.string().min(1),displayName:s.string().min(1).optional()}).strict(),fo=s.string().regex(co),vo=s.record(fo,s.string()),go=s.object({config:uo.optional(),customModels:s.array(s.unknown()).optional(),sharedSkillRoots:yt.optional(),serverHeaders:s.record(s.string(),s.string()).optional(),machineCredential:s.string().min(1).optional(),connectMachineId:s.string().min(1).optional(),serverUrl:s.string().min(1).optional()}).strict(),Kt=s.object({env:vo.optional()}).strict();function So(e,t){if(e===void 0)return;let r=[];for(let[n,o]of e.entries()){let i=ho.safeParse(o);if(!i.success){t.logger?.warn({error:i.error.message,index:n},"Ignoring invalid custom model config entry");continue}r.push(i.data)}return r}function wo(e,t){if(typeof e!="object"||e===null)return e;let r=Reflect.get(e,"config");if(typeof r!="object"||r===null)return e;let n=so.filter(o=>Object.hasOwn(r,o));return n.length===0?e:(t.logger?.warn({keys:n},ao),{...e,config:Object.fromEntries(Object.entries(r).filter(([o])=>!n.includes(o)))})}function yo(e,t){return typeof e!="object"||e===null||!Object.hasOwn(e,Ue)?e:(t.logger?.warn({key:Ue},lo),Object.fromEntries(Object.entries(e).filter(([r])=>r!==Ue)))}function F(e,t={}){let r=go.parse(yo(wo(e,t),t)),n=So(r.customModels,t),o={};return r.config!==void 0&&(o.config=r.config),n!==void 0&&(o.customModels=n),r.sharedSkillRoots!==void 0&&(o.sharedSkillRoots=r.sharedSkillRoots),r.serverUrl!==void 0&&(o.serverUrl=r.serverUrl),r.serverHeaders!==void 0&&(o.serverHeaders=r.serverHeaders),r.machineCredential!==void 0&&(o.machineCredential=r.machineCredential),r.connectMachineId!==void 0&&(o.connectMachineId=r.connectMachineId),o}function ne(e){return no(e,io)}import{constants as Eo}from"node:fs";import{copyFile as Mo,lstat as bo,rename as xo,rm as Ao}from"node:fs/promises";async function y(e){try{return await bo(e)}catch(t){if(v(t,"ENOENT"))return null;throw t}}async function qt(e,t){try{await xo(e,t)}catch(r){if(!v(r,"EXDEV"))throw r;await Mo(e,t,Eo.COPYFILE_EXCL),await Ao(e,{force:!0})}}var ie="server-import-backup",C="config.json",N="env.json",oe="bb.db",ko=["bb.db","bb.db-wal","bb.db-shm"],Fo=["-wal","-shm","-journal"];function er(e){let{existingConfig:t,importedConfig:r}=e,n={},o={...t.config,...r.config};Object.keys(o).length>0&&(n.config=o);let{customModels:i,sharedSkillRoots:a}=r;return i!==void 0&&i.length>0&&(n.customModels=i),a!==void 0&&(n.sharedSkillRoots=a),e.localServerUrl!==null&&(n.serverUrl=e.localServerUrl),n}function Co(e,t){let r={...t.env,...e.env};return Object.keys(r).length>0?{env:r}:{}}function No(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Je(e){let t={...F(e)};return No(e)&&Array.isArray(e.customModels)&&(t.customModels=e.customModels),t}function We(e){return Kt.parse(e)}async function j(e,t,r){let n=await ke(e);if(n===null)return null;try{return t(Fe(e,n))}catch(o){let i=o instanceof Error?o.message:String(o),a=`Invalid ${r} ${Qt(e)} at ${e}: ${i}`;throw r==="imported"?new d("corrupt",a,{cause:o}):new Error(a,{cause:o})}}async function To(e){for(let t of[...ko,ie,D]){let r=S(e,t);if(await y(r)!==null)throw new d("server_data_exists",`${r} already exists`)}}async function Oo(e,t){for(let r of t.entries){let n=await y(h(e,r.path));if(n?.isFile()!==!0||n.size!==r.size)throw new d("corrupt",`Staged file ${r.path} is missing or does not match the manifest`)}}async function Do(e,t,r){let n=t.split("/"),o=e;for(let a of n.slice(0,-1)){if(o=S(o,a),r.has(o))continue;let c=await y(o);if(c!==null&&!c.isDirectory())throw new d("unsafe_entry",`Cannot import ${t}: ${o} is not a directory`);r.add(o)}if((await y(h(e,t)))?.isDirectory()===!0)throw new d("server_data_exists",`Cannot import ${t}: a directory exists at that path`)}async function Bo(e,t){let r=S(Me(t),`.${Qt(t)}.${Po(6).toString("hex")}.tmp`);try{await Ro(e,r),await Ge(r,t)}catch(n){throw await z(r,{force:!0}),n}}async function tr(e,t,r,n){let o=h(e,t);if(await y(o)===null)return;let i=h(S(e,ie),t);await Ee(Me(i),{recursive:!0}),r==="move"?await Ge(o,i):await Bo(o,i),n.backups.push(t)}async function Xt(e,t,r,n){let o=h(e,r);await tr(e,r,"move",n),await Ee(Me(o),{recursive:!0}),await qt(h(t,r),o),n.importedEntries.push(r)}async function Zt(e){let t=S(e.dataDir,e.relativePath);await pt({path:t,read:async()=>(await tr(e.dataDir,e.relativePath,"copy",e.result),e.readExisting(t)),mutate:e.merge}),e.result.importedEntries.push(e.relativePath)}function $o(e,t){for(let r of e)if(!X(r))throw new d("unsafe_entry",`${t} ${JSON.stringify(r)} is not a server-owned path`)}async function Lo(e,t){let r=[];for(let n of t)await y(h(e,n))!==null&&r.push(n);await Nt(e,{version:1,entries:[...t],preexistingEntries:r})}async function Ke(e){let t=ye(e.dataDir),r=S(ye(e.stagingDir),_);$o(e.manifest.entries.map(p=>p.path),"Archive entry"),await Ee(t,{recursive:!0}),await To(t),await Oo(r,e.manifest);let n=new Set;for(let p of[...e.manifest.entries.map(Ur=>Ur.path),C,N])await Do(t,p,n);let o=new Set(e.manifest.entries.map(p=>p.path)),i=o.has(C)?await j(h(r,C),Je,"imported"):null,a=await j(S(t,C),Je,"existing"),c=i!==null||a!==null||e.localServerUrl!==null,l=o.has(N)?await j(h(r,N),We,"imported"):null;l!==null&&await j(S(t,N),We,"existing");let u=[...o].filter(p=>p!==C&&p!==N&&p!==oe);await z(S(t,R),{force:!0}),await Lo(t,[...u,...c?[C]:[],...l===null?[]:[N],...o.has(oe)?[oe]:[]]);let m={importedEntries:[],backups:[]};try{for(let p of u)await Xt(t,r,p,m);c&&await Zt({dataDir:t,relativePath:C,readExisting:async p=>await j(p,Je,"existing")??{},merge:p=>er({importedConfig:i??{},existingConfig:p,localServerUrl:e.localServerUrl}),result:m}),l!==null&&await Zt({dataDir:t,relativePath:N,readExisting:async p=>await j(p,We,"existing")??{},merge:p=>Co(l,p),result:m}),o.has(oe)&&await Xt(t,r,oe,m)}catch(p){throw await se(t),p}return m}async function Vo(e,t){let r=new Set;for(let o of t)for(let i=Yt.dirname(o);i!==".";i=Yt.dirname(i))r.add(i);let n=[...r].sort((o,i)=>i.split("/").length-o.split("/").length);for(let o of n)try{await _o(h(e,o))}catch(i){if(!v(i,"ENOTEMPTY")&&!v(i,"EEXIST")&&!v(i,"ENOENT")&&!v(i,"ENOTDIR"))throw i}}async function Ho(e,t){let r=h(e,t);if(await z(r,{force:!0,recursive:!0}),t.endsWith(".db"))for(let n of Fo)await z(`${r}${n}`,{force:!0})}async function se(e){let t=ye(e),r=await ee(t);if(r.kind==="none")return null;if(r.kind==="committed")return await $(t),null;let{journal:n}=r,o=S(t,ie),i=new Set(n.preexistingEntries);for(let a of n.entries){let c=h(o,a),l=await y(c)!==null;if(!(!l&&i.has(a))&&(await Ho(t,a),l)){let u=h(t,a);await Ee(Me(u),{recursive:!0}),await Ge(c,u)}}return await z(o,{force:!0,recursive:!0}),await Vo(t,n.entries),await $(t),n}async function qe(e){let t=S(ye(e),ie),r=await y(t);if(r!==null){if(!r.isDirectory()){await Io(t);return}await z(t,{force:!0,recursive:!0})}}var bc=256*1024;var jo=s.enum(["pending","running","done","failed","skipped"]),zo=s.object({id:Ie,status:jo,message:s.string().nullable()}).strict(),Uo=s.enum(["preparing","switching","recovery_required","completed","failed","cancelled"]),Jo=s.object({moveId:s.string().min(1),state:Uo,mode:K,targetHostId:s.string().min(1),targetHostName:s.string().min(1),serverUrl:s.string().min(1),destinationStatusUrl:s.string().min(1).nullable(),startedAt:s.number().int().nonnegative(),finishedAt:s.number().int().nonnegative().nullable(),error:s.object({step:Ie,message:s.string()}).strict().nullable(),steps:s.array(zo),cancellable:s.boolean()}).strict(),Jc=s.object({move:Jo.nullable(),lastMove:le.nullable()}).strict(),Wc=s.object({targetHostId:s.string().min(1),serverUrl:s.string().min(1).nullable()}).strict(),Wo=s.enum(["blocker","warning","info"]),Ye=s.object({id:s.string().min(1),severity:Wo,title:s.string().min(1),detail:s.string().nullable()}).strict(),Gc=s.object({targetHostId:s.string().min(1),targetHostName:s.string().min(1),mode:K,serverUrl:s.string().min(1).nullable(),requiresServerUrl:s.boolean(),targetDataDir:s.string().min(1).nullable(),existingTargetServerData:s.object({path:s.string().min(1),sizeBytes:s.number().int().nonnegative()}).strict().nullable(),items:s.array(Ye),canMove:s.boolean()}).strict(),Kc=s.object({targetHostId:s.string().min(1),serverUrl:s.string().min(1).nullable(),stopRunningWork:s.literal(!0),archiveExistingTargetServerData:s.boolean()}).strict(),qc=s.object({deleted:s.boolean()}).strict();import{randomBytes as si}from"node:crypto";import{lstat as ai,mkdir as ci,mkdtemp as li,readFile as di,rename as ui,rm as J,stat as mi,writeFile as pi}from"node:fs/promises";import{homedir as pr}from"node:os";import{basename as hi,dirname as fi,join as be,resolve as Xe}from"node:path";import{mkdir as el,readFile as Qo,rm as ei,writeFile as tl}from"node:fs/promises";import{basename as ti,join as ri}from"node:path";var Go=100,Ko=6e4;async function qo(e){await new Promise(t=>{setTimeout(t,e.delayMs)})}function U(e){try{return process.kill(e,0),!0}catch{return!1}}async function Yo(e){let t=Date.now()+e.timeoutMs;for(;Date.now()<=t;){if(!U(e.pid))return!0;await qo({delayMs:Go})}return!U(e.pid)}function Xo(){return{isRunning:e=>U(e),kill(e,t){process.kill(e,t)},readIdentity:gt,waitForExit:e=>Yo(e)}}async function Zo(e){let t=await e.processOps.readIdentity(e.pid),r=t?.command??null;if(!(r!==null&&e.verifyTokens.some(a=>a.length>0&&r.includes(a))))return{command:r,reason:"command"};let o=Date.parse(e.startedAt),i=t?.startedAt??null;return Number.isNaN(o)||i===null?{command:r,reason:"start-time"}:Math.abs(i-o)>Ko?{command:r,reason:"start-time"}:null}async function rr(e){let t=e.processOps??Xo();if(!t.isRunning(e.pid))return{kind:"not-running"};let r=await Zo({pid:e.pid,processOps:t,startedAt:e.startedAt,verifyTokens:e.verifyTokens});return r!==null?{command:r.command,kind:"unverified",reason:r.reason}:(t.kill(e.pid,e.signal),await t.waitForExit({pid:e.pid,timeoutMs:e.timeoutMs})||!t.isRunning(e.pid)?{kind:"stopped",usedKill:!1}:(t.kill(e.pid,"SIGKILL"),!await t.waitForExit({pid:e.pid,timeoutMs:e.killTimeoutMs})&&t.isRunning(e.pid)?{kind:"still-running"}:{kind:"stopped",usedKill:!0}))}var ni="bb-app-runtime.json",oi=s.object({entryPath:s.string().min(1),pid:s.number().int().positive(),surface:s.string().min(1),serverUrl:s.string().min(1),startedAt:s.string().min(1),version:s.string().min(1)});function nr(e){return ri(e,ni)}async function ii(e){await ei(nr(e),{force:!0})}async function or(e){let t=await ae(e.dataDir);return t===null||t.pid!==e.pid?!1:(await ii(e.dataDir),!0)}function ir(e){return[e,ti(e)]}async function ae(e){let t;try{t=await Qo(nr(e),"utf8")}catch{return null}try{let r=oi.safeParse(JSON.parse(t));return r.success?r.data:null}catch{return null}}var sr="bb.db",ar=["serverUrl","serverHeaders","machineCredential","connectMachineId"],vi=s.record(s.string(),s.unknown()),hr=5e3,gi=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/u,cr=/^\d+$/u,Si=s.object({ok:s.literal(!0),serverMove:s.object({state:s.string()}).optional()});function lr(e){let t=gi.exec(e.trim());return t===null?null:{core:[Number(t[1]),Number(t[2]),Number(t[3])],prerelease:t[4]===void 0?[]:t[4].split(".")}}function wi(e,t){if(e.length===0||t.length===0)return t.length-e.length;for(let r=0;r<Math.max(e.length,t.length);r+=1){let n=e[r],o=t[r];if(n===void 0)return-1;if(o===void 0)return 1;let i=cr.test(n),a=cr.test(o);if(i&&a){let c=Number(n)-Number(o);if(c!==0)return c;continue}if(i!==a)return i?-1:1;if(n!==o)return n<o?-1:1}return 0}function yi(e,t){let r=lr(e),n=lr(t);if(r===null||n===null)return!1;for(let o=0;o<3;o+=1){let i=(r.core[o]??0)-(n.core[o]??0);if(i!==0)return i>0}return wi(r.prerelease,n.prerelease)>0}async function Ei(e){try{let t=await fetch(`${e}/health`,{signal:AbortSignal.timeout(hr)});if(t.status!==200)return!1;let r=Si.safeParse(await t.json());return r.success&&r.data.serverMove?.state!=="pending"}catch{return!1}}async function Mi(e){let t=ne(e),r=await gr(t);if(r===null)return null;let n=Sr(t,r).config.serverHeaders;return n===void 0||Object.keys(n).length===0?null:n}async function fr(e){let t=e.lock.serverUrl.replace(/\/+$/u,""),r=e.lock.mode==="connect"?await Mi(e.dataDir):null;if(r===null)return await Ei(t)?{kind:"running"}:{kind:"not-running"};let n;try{n=await fetch(`${t}/api/v1/system/version`,{headers:r,signal:AbortSignal.timeout(hr)})}catch{return{kind:"not-running"}}return await n.body?.cancel().catch(()=>{}),n.status===200?{kind:"running"}:n.status===503?{kind:"not-running"}:{kind:"unconfirmed",status:n.status}}function Ze(e,t){return e instanceof Error&&"code"in e&&e.code===t}async function bi(e){try{return await ai(e),!0}catch(t){if(Ze(t,"ENOENT"))return!1;throw t}}function Qe(e){return e===Xe(Pe({homeDir:pr()}))}function W(e){let t=pr();if(e!==void 0){if(e.trim().length===0)throw new Error("--data-dir must not be empty.");return Xe(Re({homeDir:t,rawDataDir:e}))}let r=process.env.BB_DATA_DIR;return Xe(r===void 0||r.trim().length===0?Pe({homeDir:t}):Re({homeDir:t,rawDataDir:r}))}async function dr(e){if(await bi(be(e,sr)))throw new Error(`${e} already has a Moonlet server database (${sr}). Import into a data directory without a server, such as --data-dir ~/.bb-imported.`)}async function xi(e){let t=await ae(e);if(t!==null&&U(t.pid))throw new Error(`Moonlet is running from ${e} (pid ${String(t.pid)}). Stop it with bb-app stop or quit the desktop app, then try again.`)}async function Ai(e){let t;try{t=await mi(e)}catch(r){throw Ze(r,"ENOENT")?new Error(`${e} does not exist.`):r}if(!t.isFile())throw new Error(`${e} is not a file.`)}function ur(e,t){return t instanceof d&&t.code==="unsafe_entry"?new Error(`Refusing to import ${e}: ${t.message}. Nothing was imported.`):t}async function Pi(e){await se(e),await L(e),(await pe(e))?.kind==="manual"&&await J(be(e,R),{force:!0})}async function vr(e){let{archivePath:t,dataDir:r}=e;await Ai(t);let n=(await ee(r)).kind==="interrupted";if(n||await dr(r),await xi(r),await te(t),!await e.confirm(n?`Roll back the interrupted import in ${r}, then import the Moonlet server from ${t}?`:`Import the Moonlet server from ${t} into ${r}?`))return null;n&&(await Pi(r),await dr(r));let o=fi(r);await ci(o,{recursive:!0});let i=await li(be(o,`.${hi(r)}-server-import-`));try{let a=await ze({archivePath:t,destinationDir:i}).catch(l=>{throw ur(t,l)});if(!a.serverMoveExperiment)throw new Error('This export came from a server with the "Server move" experiment off. Turn on the "Server move" experiment in Settings \u2192 Experiments, or run bb settings experiment serverMove true, on that server, then export again.');if(yi(a.bbVersion,e.cliVersion))throw new Error(`This export came from Moonlet ${a.bbVersion}; install that version or newer before importing.`);let c=await Ke({stagingDir:i,dataDir:r,manifest:a,localServerUrl:null}).catch(l=>{throw ur(t,l)});try{await De(r,{version:1,reason:"manual-import",createdAt:e.now()}),await Oe(r,{version:1,kind:"manual",moveId:null,activationToken:null,sourceDataDir:a.sourceDataDir,sourceServerHostId:a.sourceServerHostId,targetHostId:null,serverUrl:null,importedEntries:c.importedEntries,createdAt:e.now(),fixupsAppliedAt:null})}catch(l){throw await L(r),await se(r),l}return await $(r),await qe(r),{dataDir:r,archivePath:t,bbVersion:a.bbVersion,sourceDataDir:a.sourceDataDir,sourceServerHostId:a.sourceServerHostId,importedEntries:c.importedEntries,rolledBackInterruptedImport:n}}finally{await J(i,{force:!0,recursive:!0})}}async function gr(e){try{return await di(e,"utf8")}catch(t){if(Ze(t,"ENOENT"))return null;throw t}}async function mr(e,t){let r=`${e}.${si(6).toString("hex")}.tmp`;try{await pi(r,t,{encoding:"utf8",mode:384}),await ui(r,e)}catch(n){throw await J(r,{force:!0}),n}}function Sr(e,t){let r;try{r=JSON.parse(t)}catch(o){throw new Error(`${e} is not valid JSON. Fix it, then unlock again.`,{cause:o})}let n;try{n=F(r)}catch(o){let i=o instanceof s.ZodError?s.prettifyError(o):String(o);throw new Error(`${e} is not a valid bb-app config. Fix it, then unlock again.
|
|
5
|
+
`).reduce(Bn,Object.create(null)),Bn=(e,t)=>{let r=parseInt(t,10);if(r!==Buffer.byteLength(t)+1)return e;t=t.slice((r+" ").length);let n=t.split("="),o=n.shift();if(!o)return e;let i=o.replace(/^SCHILY\.(dev|ino|nlink)/,"$1"),a=n.join("=").replace(/\0.*/,"");switch(i){case"path":case"linkpath":case"type":case"charset":case"comment":case"gname":case"uname":e[i]=a;break;case"ctime":case"atime":case"mtime":e[i]=new Date(Number(a)*1e3);break;case"size":let c=+a;c>=0&&(e[i]=c);break;case"gid":case"uid":case"dev":case"ino":case"nlink":case"mode":e[i]=+a;break}return e};var re=512,$n=Buffer.alloc(re),Ln=1024*1024,Vn=1024*1024,Hn=Buffer.alloc(re*2);function Ut(e){let t=e%re;return t===0?Buffer.alloc(0):Buffer.alloc(re-t)}function g(e){return new d("corrupt",e)}var we=class{#t;#e=Buffer.alloc(0);#s=!1;#r=0;constructor(t){this.#t=t[Symbol.asyncIterator]()}async#o(){if(this.#s)return!1;let t=await this.#t.next();return t.done===!0?(this.#s=!0,!1):(this.#e=this.#e.length===0?t.value:Buffer.concat([this.#e,t.value]),!0)}async#n(t){for(;this.#e.length<t;)if(!await this.#o()){if(this.#e.length===0)return null;throw g("Archive is truncated")}let r=this.#e.subarray(0,t);return this.#e=this.#e.subarray(t),r}async#i(t){let r=Ut(t).length;if(r>0&&await this.#n(r)===null)throw g("Archive is truncated")}async#a(){let t=0;for(;;){if(t+=this.#e.length,t>Vn||!this.#e.equals(Buffer.alloc(this.#e.length)))throw g("Archive has unexpected trailing data");if(this.#e=Buffer.alloc(0),!await this.#o())return}}async nextEntry(){if(this.#r>0)throw new Error("The previous tar entry body was not consumed");let t;for(;;){let r=await this.#n(re);if(r===null)throw g("Archive ended without an end-of-archive marker");if(r.equals($n)){if(t!==void 0)throw g("Archive ended after an extended header");return await this.#a(),null}let n=new H(r,0,t);if(!n.cksumValid)throw g("Archive entry header checksum is invalid");let o=n.size;if(o===void 0||!Number.isSafeInteger(o))throw g("Archive entry size is invalid");if(n.type==="ExtendedHeader"){if(t!==void 0)throw g("Archive has consecutive extended headers");if(o>Ln)throw g("Archive extended header is too large");let i=await this.#n(o);if(i===null)throw g("Archive is truncated");await this.#i(o),t=Se.parse(i.toString("utf8"),void 0,!1);continue}return this.#r=o,{path:t?.path??n.path??"",type:n.type,size:o,mode:n.mode??null}}}async readBodyBuffer(){let t=this.#r,r=t===0?Buffer.alloc(0):await this.#n(t);if(r===null)throw g("Archive is truncated");return this.#r=0,await this.#i(t),Buffer.from(r)}async*readBody(){let t=this.#r;for(;this.#r>0;){if(this.#e.length===0&&!await this.#o())throw g("Archive is truncated");let r=Math.min(this.#r,this.#e.length),n=this.#e.subarray(0,r);this.#e=this.#e.subarray(r),this.#r-=r,yield n}await this.#i(t)}};var qn=64*1024*1024;async function Yn(e){if(await Jt(e,{recursive:!0}),(await Jn(e)).length>0)throw new Error(`Archive extraction destination ${e} is not empty`)}function Xn(e){return e===null?384:e&493|384}function Zn(e){let t=`${_}/`,r=e.startsWith(t)?e.slice(t.length):null;if(r===null||!O(r))throw new d("unsafe_entry",`Archive entry ${JSON.stringify(e)} is not a safe path under ${t}`);return r}function Qn(e){try{return JSON.parse(e.toString("utf8"))}catch(t){throw new d("corrupt","Archive manifest is not JSON",{cause:t})}}async function eo(e,t,r,n){await Jt(Gn(t),{recursive:!0,mode:448});let o=jn("sha256");try{await Gt(e.readBody(),async function*(i){for await(let a of i)o.update(a),yield a},Un(t,{flags:"wx",mode:r}))}catch(i){throw v(i,"EEXIST")?new d("unsafe_entry",`Archive entry ${n.path} collides with another extracted file`,{cause:i}):i}if(o.digest("hex")!==n.sha256)throw new d("digest_mismatch",`Archive entry ${n.path} does not match its manifest digest`)}async function to(e,t){let r=new we(e),n=await r.nextEntry();if(n===null||n.type!=="File"||n.path!==fe)throw new d("corrupt",`Archive does not start with ${fe}`);if(n.size>qn)throw new d("corrupt","Archive manifest is too large");let o=Bt(Qn(await r.readBodyBuffer())),i=new Map(o.entries.map(c=>[c.path,c])),a=Wt(t,_);for(;;){let c=await r.nextEntry();if(c===null)break;if(c.type!=="File")throw new d("unsafe_entry",`Archive entry ${JSON.stringify(c.path)} has unsupported type ${c.type}`);let l=Zn(c.path),u=i.get(l);if(u===void 0)throw new d("unsafe_entry",`Archive entry ${l} is not listed in the manifest`);if(i.delete(l),c.size!==u.size)throw new d("digest_mismatch",`Archive entry ${l} is ${String(c.size)} bytes but the manifest lists ${String(u.size)}`);await eo(r,h(a,l),Xn(c.mode),u)}if(i.size>0)throw new d("corrupt",`Archive is missing ${String(i.size)} file(s) listed in its manifest`);return o}function ro(e){return e instanceof d?e:e instanceof Error&&"code"in e&&typeof e.code=="string"&&e.code.startsWith("Z_")?new d("corrupt",`Archive data is corrupt: ${e.message}`,{cause:e}):e}async function ze(e){await te(e.archivePath),await Yn(e.destinationDir);let t={manifest:null},r=async n=>{t.manifest=await to(n,e.destinationDir)};try{await Gt(zn(e.archivePath),Kn(),r)}catch(n){throw await Wn(Wt(e.destinationDir,_),{force:!0,recursive:!0}),ro(n)}if(t.manifest===null)throw new d("corrupt","Archive has no manifest");return t.manifest}import{randomBytes as Po}from"node:crypto";import{copyFile as Ro,mkdir as Ee,readdir as ec,rename as Ge,rm as z,rmdir as _o,unlink as Io}from"node:fs/promises";import{basename as Qt,dirname as Me,join as S,posix as Yt,resolve as ye}from"node:path";import{join as no}from"node:path";var oo=["codex","claude-code","pi","acp-cursor"],io="config.json";var so=["BB_INFERENCE","BB_INFERENCE_FALLBACK","BB_TRANSCRIPTION"],ao="BB_INFERENCE, BB_INFERENCE_FALLBACK, and BB_TRANSCRIPTION were removed. Choose AI services in Settings \u2192 AI services or with `bb settings ai-services set <task> <automatic|off|service>`.",co=/^[A-Za-z_][A-Za-z0-9_]*$/u,Ue="customAcpAgents",lo="customAcpAgents in config.json is no longer read. Declare the agents with `bb plugin config provider-acp set customAgents '<json>'`.",uo=s.object({BB_APP_URL:s.string().optional(),BB_LOG_LEVEL:s.string().optional()}).strict(),mo=/^acp-[a-z0-9][a-z0-9-]*$/u,po=s.union([s.enum(oo),s.string().regex(mo)]),ho=s.object({providerId:po,model:s.string().min(1),displayName:s.string().min(1).optional()}).strict(),fo=s.string().regex(co),vo=s.record(fo,s.string()),go=s.object({config:uo.optional(),customModels:s.array(s.unknown()).optional(),sharedSkillRoots:yt.optional(),serverHeaders:s.record(s.string(),s.string()).optional(),machineCredential:s.string().min(1).optional(),connectMachineId:s.string().min(1).optional(),serverUrl:s.string().min(1).optional()}).strict(),Kt=s.object({env:vo.optional()}).strict();function So(e,t){if(e===void 0)return;let r=[];for(let[n,o]of e.entries()){let i=ho.safeParse(o);if(!i.success){t.logger?.warn({error:i.error.message,index:n},"Ignoring invalid custom model config entry");continue}r.push(i.data)}return r}function wo(e,t){if(typeof e!="object"||e===null)return e;let r=Reflect.get(e,"config");if(typeof r!="object"||r===null)return e;let n=so.filter(o=>Object.hasOwn(r,o));return n.length===0?e:(t.logger?.warn({keys:n},ao),{...e,config:Object.fromEntries(Object.entries(r).filter(([o])=>!n.includes(o)))})}function yo(e,t){return typeof e!="object"||e===null||!Object.hasOwn(e,Ue)?e:(t.logger?.warn({key:Ue},lo),Object.fromEntries(Object.entries(e).filter(([r])=>r!==Ue)))}function F(e,t={}){let r=go.parse(yo(wo(e,t),t)),n=So(r.customModels,t),o={};return r.config!==void 0&&(o.config=r.config),n!==void 0&&(o.customModels=n),r.sharedSkillRoots!==void 0&&(o.sharedSkillRoots=r.sharedSkillRoots),r.serverUrl!==void 0&&(o.serverUrl=r.serverUrl),r.serverHeaders!==void 0&&(o.serverHeaders=r.serverHeaders),r.machineCredential!==void 0&&(o.machineCredential=r.machineCredential),r.connectMachineId!==void 0&&(o.connectMachineId=r.connectMachineId),o}function ne(e){return no(e,io)}import{constants as Eo}from"node:fs";import{copyFile as Mo,lstat as bo,rename as xo,rm as Ao}from"node:fs/promises";async function y(e){try{return await bo(e)}catch(t){if(v(t,"ENOENT"))return null;throw t}}async function qt(e,t){try{await xo(e,t)}catch(r){if(!v(r,"EXDEV"))throw r;await Mo(e,t,Eo.COPYFILE_EXCL),await Ao(e,{force:!0})}}var ie="server-import-backup",C="config.json",N="env.json",oe="bb.db",ko=["bb.db","bb.db-wal","bb.db-shm"],Fo=["-wal","-shm","-journal"];function er(e){let{existingConfig:t,importedConfig:r}=e,n={},o={...t.config,...r.config};Object.keys(o).length>0&&(n.config=o);let{customModels:i,sharedSkillRoots:a}=r;return i!==void 0&&i.length>0&&(n.customModels=i),a!==void 0&&(n.sharedSkillRoots=a),e.localServerUrl!==null&&(n.serverUrl=e.localServerUrl),n}function Co(e,t){let r={...t.env,...e.env};return Object.keys(r).length>0?{env:r}:{}}function No(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Je(e){let t={...F(e)};return No(e)&&Array.isArray(e.customModels)&&(t.customModels=e.customModels),t}function We(e){return Kt.parse(e)}async function j(e,t,r){let n=await ke(e);if(n===null)return null;try{return t(Fe(e,n))}catch(o){let i=o instanceof Error?o.message:String(o),a=`Invalid ${r} ${Qt(e)} at ${e}: ${i}`;throw r==="imported"?new d("corrupt",a,{cause:o}):new Error(a,{cause:o})}}async function To(e){for(let t of[...ko,ie,D]){let r=S(e,t);if(await y(r)!==null)throw new d("server_data_exists",`${r} already exists`)}}async function Oo(e,t){for(let r of t.entries){let n=await y(h(e,r.path));if(n?.isFile()!==!0||n.size!==r.size)throw new d("corrupt",`Staged file ${r.path} is missing or does not match the manifest`)}}async function Do(e,t,r){let n=t.split("/"),o=e;for(let a of n.slice(0,-1)){if(o=S(o,a),r.has(o))continue;let c=await y(o);if(c!==null&&!c.isDirectory())throw new d("unsafe_entry",`Cannot import ${t}: ${o} is not a directory`);r.add(o)}if((await y(h(e,t)))?.isDirectory()===!0)throw new d("server_data_exists",`Cannot import ${t}: a directory exists at that path`)}async function Bo(e,t){let r=S(Me(t),`.${Qt(t)}.${Po(6).toString("hex")}.tmp`);try{await Ro(e,r),await Ge(r,t)}catch(n){throw await z(r,{force:!0}),n}}async function tr(e,t,r,n){let o=h(e,t);if(await y(o)===null)return;let i=h(S(e,ie),t);await Ee(Me(i),{recursive:!0}),r==="move"?await Ge(o,i):await Bo(o,i),n.backups.push(t)}async function Xt(e,t,r,n){let o=h(e,r);await tr(e,r,"move",n),await Ee(Me(o),{recursive:!0,mode:r.startsWith("secrets/")?448:511}),await qt(h(t,r),o),n.importedEntries.push(r)}async function Zt(e){let t=S(e.dataDir,e.relativePath);await pt({path:t,read:async()=>(await tr(e.dataDir,e.relativePath,"copy",e.result),e.readExisting(t)),mutate:e.merge}),e.result.importedEntries.push(e.relativePath)}function $o(e,t){for(let r of e)if(!X(r))throw new d("unsafe_entry",`${t} ${JSON.stringify(r)} is not a server-owned path`)}async function Lo(e,t){let r=[];for(let n of t)await y(h(e,n))!==null&&r.push(n);await Nt(e,{version:1,entries:[...t],preexistingEntries:r})}async function Ke(e){let t=ye(e.dataDir),r=S(ye(e.stagingDir),_);$o(e.manifest.entries.map(p=>p.path),"Archive entry"),await Ee(t,{recursive:!0}),await To(t),await Oo(r,e.manifest);let n=new Set;for(let p of[...e.manifest.entries.map(Ur=>Ur.path),C,N])await Do(t,p,n);let o=new Set(e.manifest.entries.map(p=>p.path)),i=o.has(C)?await j(h(r,C),Je,"imported"):null,a=await j(S(t,C),Je,"existing"),c=i!==null||a!==null||e.localServerUrl!==null,l=o.has(N)?await j(h(r,N),We,"imported"):null;l!==null&&await j(S(t,N),We,"existing");let u=[...o].filter(p=>p!==C&&p!==N&&p!==oe);await z(S(t,R),{force:!0}),await Lo(t,[...u,...c?[C]:[],...l===null?[]:[N],...o.has(oe)?[oe]:[]]);let m={importedEntries:[],backups:[]};try{for(let p of u)await Xt(t,r,p,m);c&&await Zt({dataDir:t,relativePath:C,readExisting:async p=>await j(p,Je,"existing")??{},merge:p=>er({importedConfig:i??{},existingConfig:p,localServerUrl:e.localServerUrl}),result:m}),l!==null&&await Zt({dataDir:t,relativePath:N,readExisting:async p=>await j(p,We,"existing")??{},merge:p=>Co(l,p),result:m}),o.has(oe)&&await Xt(t,r,oe,m)}catch(p){throw await se(t),p}return m}async function Vo(e,t){let r=new Set;for(let o of t)for(let i=Yt.dirname(o);i!==".";i=Yt.dirname(i))r.add(i);let n=[...r].sort((o,i)=>i.split("/").length-o.split("/").length);for(let o of n)try{await _o(h(e,o))}catch(i){if(!v(i,"ENOTEMPTY")&&!v(i,"EEXIST")&&!v(i,"ENOENT")&&!v(i,"ENOTDIR"))throw i}}async function Ho(e,t){let r=h(e,t);if(await z(r,{force:!0,recursive:!0}),t.endsWith(".db"))for(let n of Fo)await z(`${r}${n}`,{force:!0})}async function se(e){let t=ye(e),r=await ee(t);if(r.kind==="none")return null;if(r.kind==="committed")return await $(t),null;let{journal:n}=r,o=S(t,ie),i=new Set(n.preexistingEntries);for(let a of n.entries){let c=h(o,a),l=await y(c)!==null;if(!(!l&&i.has(a))&&(await Ho(t,a),l)){let u=h(t,a);await Ee(Me(u),{recursive:!0,mode:a.startsWith("secrets/")?448:511}),await Ge(c,u)}}return await z(o,{force:!0,recursive:!0}),await Vo(t,n.entries),await $(t),n}async function qe(e){let t=S(ye(e),ie),r=await y(t);if(r!==null){if(!r.isDirectory()){await Io(t);return}await z(t,{force:!0,recursive:!0})}}var bc=256*1024;var jo=s.enum(["pending","running","done","failed","skipped"]),zo=s.object({id:Ie,status:jo,message:s.string().nullable()}).strict(),Uo=s.enum(["preparing","switching","recovery_required","completed","failed","cancelled"]),Jo=s.object({moveId:s.string().min(1),state:Uo,mode:K,targetHostId:s.string().min(1),targetHostName:s.string().min(1),serverUrl:s.string().min(1),destinationStatusUrl:s.string().min(1).nullable(),startedAt:s.number().int().nonnegative(),finishedAt:s.number().int().nonnegative().nullable(),error:s.object({step:Ie,message:s.string()}).strict().nullable(),steps:s.array(zo),cancellable:s.boolean()}).strict(),Jc=s.object({move:Jo.nullable(),lastMove:le.nullable()}).strict(),Wc=s.object({targetHostId:s.string().min(1),serverUrl:s.string().min(1).nullable()}).strict(),Wo=s.enum(["blocker","warning","info"]),Ye=s.object({id:s.string().min(1),severity:Wo,title:s.string().min(1),detail:s.string().nullable()}).strict(),Gc=s.object({targetHostId:s.string().min(1),targetHostName:s.string().min(1),mode:K,serverUrl:s.string().min(1).nullable(),requiresServerUrl:s.boolean(),targetDataDir:s.string().min(1).nullable(),existingTargetServerData:s.object({path:s.string().min(1),sizeBytes:s.number().int().nonnegative()}).strict().nullable(),items:s.array(Ye),canMove:s.boolean()}).strict(),Kc=s.object({targetHostId:s.string().min(1),serverUrl:s.string().min(1).nullable(),stopRunningWork:s.literal(!0),archiveExistingTargetServerData:s.boolean()}).strict(),qc=s.object({deleted:s.boolean()}).strict();import{randomBytes as si}from"node:crypto";import{lstat as ai,mkdir as ci,mkdtemp as li,readFile as di,rename as ui,rm as J,stat as mi,writeFile as pi}from"node:fs/promises";import{homedir as pr}from"node:os";import{basename as hi,dirname as fi,join as be,resolve as Xe}from"node:path";import{mkdir as el,readFile as Qo,rm as ei,writeFile as tl}from"node:fs/promises";import{basename as ti,join as ri}from"node:path";var Go=100,Ko=6e4;async function qo(e){await new Promise(t=>{setTimeout(t,e.delayMs)})}function U(e){try{return process.kill(e,0),!0}catch{return!1}}async function Yo(e){let t=Date.now()+e.timeoutMs;for(;Date.now()<=t;){if(!U(e.pid))return!0;await qo({delayMs:Go})}return!U(e.pid)}function Xo(){return{isRunning:e=>U(e),kill(e,t){process.kill(e,t)},readIdentity:gt,waitForExit:e=>Yo(e)}}async function Zo(e){let t=await e.processOps.readIdentity(e.pid),r=t?.command??null;if(!(r!==null&&e.verifyTokens.some(a=>a.length>0&&r.includes(a))))return{command:r,reason:"command"};let o=Date.parse(e.startedAt),i=t?.startedAt??null;return Number.isNaN(o)||i===null?{command:r,reason:"start-time"}:Math.abs(i-o)>Ko?{command:r,reason:"start-time"}:null}async function rr(e){let t=e.processOps??Xo();if(!t.isRunning(e.pid))return{kind:"not-running"};let r=await Zo({pid:e.pid,processOps:t,startedAt:e.startedAt,verifyTokens:e.verifyTokens});return r!==null?{command:r.command,kind:"unverified",reason:r.reason}:(t.kill(e.pid,e.signal),await t.waitForExit({pid:e.pid,timeoutMs:e.timeoutMs})||!t.isRunning(e.pid)?{kind:"stopped",usedKill:!1}:(t.kill(e.pid,"SIGKILL"),!await t.waitForExit({pid:e.pid,timeoutMs:e.killTimeoutMs})&&t.isRunning(e.pid)?{kind:"still-running"}:{kind:"stopped",usedKill:!0}))}var ni="bb-app-runtime.json",oi=s.object({entryPath:s.string().min(1),pid:s.number().int().positive(),surface:s.string().min(1),serverUrl:s.string().min(1),startedAt:s.string().min(1),version:s.string().min(1)});function nr(e){return ri(e,ni)}async function ii(e){await ei(nr(e),{force:!0})}async function or(e){let t=await ae(e.dataDir);return t===null||t.pid!==e.pid?!1:(await ii(e.dataDir),!0)}function ir(e){return[e,ti(e)]}async function ae(e){let t;try{t=await Qo(nr(e),"utf8")}catch{return null}try{let r=oi.safeParse(JSON.parse(t));return r.success?r.data:null}catch{return null}}var sr="bb.db",ar=["serverUrl","serverHeaders","machineCredential","connectMachineId"],vi=s.record(s.string(),s.unknown()),hr=5e3,gi=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/u,cr=/^\d+$/u,Si=s.object({ok:s.literal(!0),serverMove:s.object({state:s.string()}).optional()});function lr(e){let t=gi.exec(e.trim());return t===null?null:{core:[Number(t[1]),Number(t[2]),Number(t[3])],prerelease:t[4]===void 0?[]:t[4].split(".")}}function wi(e,t){if(e.length===0||t.length===0)return t.length-e.length;for(let r=0;r<Math.max(e.length,t.length);r+=1){let n=e[r],o=t[r];if(n===void 0)return-1;if(o===void 0)return 1;let i=cr.test(n),a=cr.test(o);if(i&&a){let c=Number(n)-Number(o);if(c!==0)return c;continue}if(i!==a)return i?-1:1;if(n!==o)return n<o?-1:1}return 0}function yi(e,t){let r=lr(e),n=lr(t);if(r===null||n===null)return!1;for(let o=0;o<3;o+=1){let i=(r.core[o]??0)-(n.core[o]??0);if(i!==0)return i>0}return wi(r.prerelease,n.prerelease)>0}async function Ei(e){try{let t=await fetch(`${e}/health`,{signal:AbortSignal.timeout(hr)});if(t.status!==200)return!1;let r=Si.safeParse(await t.json());return r.success&&r.data.serverMove?.state!=="pending"}catch{return!1}}async function Mi(e){let t=ne(e),r=await gr(t);if(r===null)return null;let n=Sr(t,r).config.serverHeaders;return n===void 0||Object.keys(n).length===0?null:n}async function fr(e){let t=e.lock.serverUrl.replace(/\/+$/u,""),r=e.lock.mode==="connect"?await Mi(e.dataDir):null;if(r===null)return await Ei(t)?{kind:"running"}:{kind:"not-running"};let n;try{n=await fetch(`${t}/api/v1/system/version`,{headers:r,signal:AbortSignal.timeout(hr)})}catch{return{kind:"not-running"}}return await n.body?.cancel().catch(()=>{}),n.status===200?{kind:"running"}:n.status===503?{kind:"not-running"}:{kind:"unconfirmed",status:n.status}}function Ze(e,t){return e instanceof Error&&"code"in e&&e.code===t}async function bi(e){try{return await ai(e),!0}catch(t){if(Ze(t,"ENOENT"))return!1;throw t}}function Qe(e){return e===Xe(Pe({homeDir:pr()}))}function W(e){let t=pr();if(e!==void 0){if(e.trim().length===0)throw new Error("--data-dir must not be empty.");return Xe(Re({homeDir:t,rawDataDir:e}))}let r=process.env.BB_DATA_DIR;return Xe(r===void 0||r.trim().length===0?Pe({homeDir:t}):Re({homeDir:t,rawDataDir:r}))}async function dr(e){if(await bi(be(e,sr)))throw new Error(`${e} already has a Moonlet server database (${sr}). Import into a data directory without a server, such as --data-dir ~/.bb-imported.`)}async function xi(e){let t=await ae(e);if(t!==null&&U(t.pid))throw new Error(`Moonlet is running from ${e} (pid ${String(t.pid)}). Stop it with bb-app stop or quit the desktop app, then try again.`)}async function Ai(e){let t;try{t=await mi(e)}catch(r){throw Ze(r,"ENOENT")?new Error(`${e} does not exist.`):r}if(!t.isFile())throw new Error(`${e} is not a file.`)}function ur(e,t){return t instanceof d&&t.code==="unsafe_entry"?new Error(`Refusing to import ${e}: ${t.message}. Nothing was imported.`):t}async function Pi(e){await se(e),await L(e),(await pe(e))?.kind==="manual"&&await J(be(e,R),{force:!0})}async function vr(e){let{archivePath:t,dataDir:r}=e;await Ai(t);let n=(await ee(r)).kind==="interrupted";if(n||await dr(r),await xi(r),await te(t),!await e.confirm(n?`Roll back the interrupted import in ${r}, then import the Moonlet server from ${t}?`:`Import the Moonlet server from ${t} into ${r}?`))return null;n&&(await Pi(r),await dr(r));let o=fi(r);await ci(o,{recursive:!0});let i=await li(be(o,`.${hi(r)}-server-import-`));try{let a=await ze({archivePath:t,destinationDir:i}).catch(l=>{throw ur(t,l)});if(!a.serverMoveExperiment)throw new Error('This export came from a server with the "Server move" experiment off. Turn on the "Server move" experiment in Settings \u2192 Experiments, or run bb settings experiment serverMove true, on that server, then export again.');if(yi(a.bbVersion,e.cliVersion))throw new Error(`This export came from Moonlet ${a.bbVersion}; install that version or newer before importing.`);let c=await Ke({stagingDir:i,dataDir:r,manifest:a,localServerUrl:null}).catch(l=>{throw ur(t,l)});try{await De(r,{version:1,reason:"manual-import",createdAt:e.now()}),await Oe(r,{version:1,kind:"manual",moveId:null,activationToken:null,sourceDataDir:a.sourceDataDir,sourceServerHostId:a.sourceServerHostId,targetHostId:null,serverUrl:null,importedEntries:c.importedEntries,createdAt:e.now(),fixupsAppliedAt:null})}catch(l){throw await L(r),await se(r),l}return await $(r),await qe(r),{dataDir:r,archivePath:t,bbVersion:a.bbVersion,sourceDataDir:a.sourceDataDir,sourceServerHostId:a.sourceServerHostId,importedEntries:c.importedEntries,rolledBackInterruptedImport:n}}finally{await J(i,{force:!0,recursive:!0})}}async function gr(e){try{return await di(e,"utf8")}catch(t){if(Ze(t,"ENOENT"))return null;throw t}}async function mr(e,t){let r=`${e}.${si(6).toString("hex")}.tmp`;try{await pi(r,t,{encoding:"utf8",mode:384}),await ui(r,e)}catch(n){throw await J(r,{force:!0}),n}}function Sr(e,t){let r;try{r=JSON.parse(t)}catch(o){throw new Error(`${e} is not valid JSON. Fix it, then unlock again.`,{cause:o})}let n;try{n=F(r)}catch(o){let i=o instanceof s.ZodError?s.prettifyError(o):String(o);throw new Error(`${e} is not a valid bb-app config. Fix it, then unlock again.
|
|
6
6
|
${i}`)}return{raw:vi.parse(r),config:n}}async function wr(e){let t=be(e,Z),r=ne(e),n=await gr(r);if(n===null)return await J(t,{force:!0}),[];let o=Sr(r,n).raw,i=ar.filter(c=>Object.hasOwn(o,c));if(i.length===0)return await J(t,{force:!0}),[];let a=Object.fromEntries(Object.entries(o).filter(([c])=>!ar.includes(c)));F(a),await mr(r,`${JSON.stringify(a,null,2)}
|
|
7
7
|
`);try{await J(t,{force:!0})}catch(c){throw await mr(r,n),c}return i}import{execFile as Ui,spawn as Ji}from"node:child_process";var Ri="@halcyonlabs/app";function yr(e,t="bb-app"){return`npx -y -p ${Ri}@${e} ${t}`}import{access as Wi,readFile as Gi}from"node:fs/promises";import{homedir as Ki}from"node:os";import{basename as qi,join as Yi}from"node:path";function _i(e){return e.exitCode!==null||e.signalCode!==null}function Er(e){return _i(e)?Promise.resolve({code:e.exitCode,signal:e.signalCode}):new Promise(t=>{e.once("exit",(r,n)=>{t({code:r,signal:n})})})}import{readdir as Ii,readFile as ki,realpath as Fi}from"node:fs/promises";import{join as xe,resolve as Ci}from"node:path";var br="BB_MACHINE_INSTALLER";var Ni="app.getbb.host-daemon.",Ti=".plist",Oi="bb-host-daemon-",Di=".service",Bi=/<key>BB_DATA_DIR<\/key>\s*<string>([^<]*)<\/string>/u,$i=/^Environment="BB_DATA_DIR=((?:[^"\\]|\\.)*)"\s*$/mu,Li={"&":"&","'":"'",">":">","<":"<",""":'"'};function Vi(e){let t=Bi.exec(e);return t?.[1]===void 0?null:t[1].replace(/&(?:amp|apos|gt|lt|quot);/gu,r=>Li[r]??r)}function Hi(e){let t=$i.exec(e);return t?.[1]===void 0?null:t[1].replace(/\\(.)|%%/gu,(r,n)=>n??"%")}function ji(e){return e.platform==="darwin"?[{directory:xe(e.homeDir,"Library","LaunchAgents"),parseDataDir:Vi,prefix:Ni,suffix:Ti}]:e.platform==="linux"?[xe(e.homeDir,".config","systemd","user"),xe(e.dataDir,"systemd")].map(t=>({directory:t,parseDataDir:Hi,prefix:Oi,suffix:Di})):[]}function et(e){return e instanceof Error&&"code"in e&&(e.code==="ENOENT"||e.code==="ENOTDIR")}async function Mr(e){try{return await Fi(e)}catch(t){if(et(t))return Ci(e);throw t}}async function zi(e){let t;try{t=await Ii(e.directory)}catch(r){if(et(r))return[];throw r}return t.filter(r=>r.startsWith(e.prefix)&&r.endsWith(e.suffix)).sort().map(r=>xe(e.directory,r))}async function xr(e){let t=await Mr(e.dataDir);for(let r of ji(e))for(let n of await zi(r)){let o;try{o=await ki(n,"utf8")}catch(a){if(et(a))continue;throw a}let i=r.parseDataDir(o);if(i!==null&&await Mr(i)===t)return n}return null}var Ar="Node.js 22.19 or newer",Xi=1e4,Zi=15e3,Qi=3e3,es=`${yr("latest","bb")} server install-machine-service`;async function Pr(e){try{return await Wi(e),!0}catch{return!1}}async function ts(e){if(!await Pr(Yi(e,"auth.json")))throw new Error(`${e} has no machine credentials (auth.json), so there is no machine to keep connected.`);let t=ne(e),r;try{r=await Gi(t,"utf8")}catch{throw new Error(`${e} has no server address (${t} is missing).`)}if(F(JSON.parse(r)).serverUrl===void 0)throw new Error(`${t} has no server address.`)}async function rs(){let e=process.env[br]?.trim()??"";if(e.length===0||!await Pr(e))throw new Error(`This Moonlet installation doesn't include the machine installer. Run ${es} instead.`);return e}function ns(){return new Promise(e=>{Ui("node",["-p","process.versions.node"],{timeout:Xi},(t,r)=>{e(t===null?r.trim():null)})})}function os(e){let[t=0,r=0]=e.split(".").map(Number);return t>22||t===22&&r>=19}async function is(){let e=await ns();if(e===null)throw new Error(`The background service runs Moonlet with the node on your PATH, and none was found. Install ${Ar}, then run this command again.`);if(!os(e))throw new Error(`The background service runs Moonlet with the node on your PATH, which is Node.js ${e}. Install ${Ar}, then run this command again.`)}async function ss(e,t){let r=await ae(e);if(r===null)return;let n=await rr({killTimeoutMs:Qi,pid:r.pid,signal:"SIGTERM",startedAt:r.startedAt,timeoutMs:Zi,verifyTokens:ir(r.entryPath)});if(n.kind==="unverified")throw new Error(`Moonlet on this computer is recorded as pid ${String(r.pid)}, but that process doesn't look like it, so it was left alone. Quit the Moonlet desktop app or stop Moonlet, then run this command again.`);if(n.kind==="still-running")throw new Error(`Moonlet (pid ${String(r.pid)}) did not stop, even after SIGKILL.`);await or({dataDir:e,pid:r.pid}),n.kind==="stopped"&&t(`Stopped Moonlet on this computer (pid ${String(r.pid)}).`)}async function as(e){let t=Ji("sh",[e.installerPath,"--adopt","--data-dir",e.dataDir],{stdio:["ignore",e.output==="stderr"?2:"inherit","inherit"]});return(await Er(t)).code===0}function Rr(e){return e.endsWith(".plist")?`launchctl bootout gui/$(id -u) '${e}' && rm '${e}'`:`systemctl --user disable --now ${qi(e)} && rm '${e}'`}function tt(e){return xr({dataDir:e,homeDir:Ki(),platform:process.platform})}async function _r(e){let{dataDir:t}=e,r=await B(t);if(r===null)throw new Error(`${t} is not locked by a server move. This command keeps a computer connected as a machine after its Moonlet server moved to another machine.`);if(process.platform==="win32")throw new Error("Moonlet cannot install the background machine service on Windows. It is available on macOS and Linux.");await ts(t);let n=await rs();if(await is(),!await e.confirm(`Stop Moonlet on this computer and install a background service that keeps it connected to ${r.toHostName}?`))return null;if(await ss(t,e.report),!await as({dataDir:t,installerPath:n,output:e.installerOutput}))throw new Error("The background service install failed; see the installer output above. Until it succeeds, this computer stays connected only while the Moonlet desktop app or npx bb-app runs, so start one of them to reconnect it now.");return{dataDir:t,serverUrl:r.serverUrl,serviceFile:await tt(t),toHostName:r.toHostName}}import{setTimeout as cs}from"node:timers/promises";var ls=1e3,rt=2,ds=5,us="server_moved",ms="server_move_blocked",ps="server_move_experiment_disabled",hs=s.object({message:s.string().min(1)});async function Ae(e){try{return await e()}catch(t){if(t instanceof ce&&t.code===ps){let r=hs.safeParse(t.body);throw new b(r.success?r.data.message:t.message,1)}throw t}}var fs=[["blocker","Blockers"],["warning","Warnings"],["info","Notes"]],vs=s.object({details:s.object({items:s.array(Ye)})});function nt(e,t){switch(e){case"stop-work":return"Stop running work";case"update-target":return`Update Moonlet on ${t}`;case"export":return"Export server data";case"transfer":return`Send data to ${t}`;case"start-target":return"Start the new server";case"verify-address":return"Check that machines can reach the new address";case"switch":return"Switch machines over"}}function Ir(e){return e==="connect"?"Moonlet Connect":"direct address"}function ot(e){for(let[t,r]of fs){let n=e.filter(o=>o.severity===t);if(n.length!==0){console.log(""),console.log(r);for(let o of n)console.log(` - ${o.title}`),o.detail!==null&&console.log(` ${o.detail}`)}}}function kr(e){console.log(`Moving the Moonlet server to ${e.targetHostName} (${Ir(e.mode)})`),e.serverUrl!==null&&console.log(`New address: ${e.serverUrl}`),e.targetDataDir!==null&&console.log(`Target data directory: ${e.targetDataDir}`),e.existingTargetServerData!==null&&console.log(`Existing Moonlet server data on ${e.targetHostName}: ${e.existingTargetServerData.path} (${q(e.existingTargetServerData.sizeBytes)})`),ot(e.items),console.log("")}function Fr(e){return`This Moonlet server uses a direct address, so the new server needs one too. Re-run with --address <url>: the URL every machine and app will use to reach Moonlet on ${e.targetHostName}, such as a Tailscale Serve URL.`}function it(e){let t=e.existingTargetServerData,r=t===null?"":` at ${t.path} (${q(t.sizeBytes)})`;return`${e.targetHostName} already has Moonlet server data${r}. Re-run with --archive-existing-data to move it aside to a .before-move-<date> directory; it is never merged.`}function Cr(e){if(!(e instanceof ce)||e.code!==ms)return null;let t=vs.safeParse(e.body);return t.success?t.data.details.items:null}function gs(e){return e instanceof ce&&e.status===410&&e.code===us}function Nr(e){return e.message===null?"":`: ${e.message}`}var Tr={pending:"pending",running:"running",done:"done",failed:"failed",skipped:"skipped"},Ss={preparing:"preparing",switching:"switching",recovery_required:"recovery required",completed:"completed",failed:"failed",cancelled:"cancelled"};function ws(e){let t=e.targetHostName,r=e.error===null?"":` (${e.error.message})`;return[`Moonlet couldn't confirm that ${t} took over${r}.`,`This server stays up but read-only, and Moonlet finishes the move on its own as soon as ${t} answers.`,`If ${t} isn't running the server, run bb server move cancel --yes to abandon the move and keep the server here.`,"If this server stops, run bb server unlock on this computer."]}function st(e){for(let t of ws(e))console.log(t)}function at(e){return`The move to ${e.targetHostName} wasn't confirmed and needs recovery.`}function Or(e){let t=e.targetHostName;return[`The move to ${t} wasn't confirmed. Abandoning rolls back the switch and keeps the server on this computer.`,`If ${t} already took over, two servers will run with the same data and Moonlet Connect credential. Stop the server on ${t} first.`]}function ys(e,t,r){for(let n of e.steps){if(n.status==="pending")continue;let o=`${n.status}
|
|
8
8
|
${n.message??""}`;t.get(n.id)!==o&&(t.set(n.id,o),r(`[${Tr[n.status]}] ${nt(n.id,e.targetHostName)}${Nr(n)}`))}}async function Dr(e){let t=new Map,r=e.initial,n=0;for(;;){if(ys(r,t,e.report),r.state==="completed")return{kind:"moved",status:r};if(r.state==="recovery_required")return{kind:"recovery",status:r};if(r.state==="failed"||r.state==="cancelled")return{kind:"ended",status:r};await cs(ls,void 0,{signal:e.signal});let o;try{o=await e.sdk.experimental_server.moveStatus({signal:e.signal})}catch(i){if(e.signal.aborted)throw i;if(r.state==="switching"||gs(i))return{kind:"moved",status:r};if(n+=1,n>=ds)throw new Error(`Lost contact with the Moonlet server before the switch (${ht(i)}). Run bb server move status once it answers again.`);continue}if(n=0,o.move?.moveId===r.moveId){r=o.move;continue}if(o.lastMove?.moveId===r.moveId)return{kind:"moved",status:r};throw new Error("The Moonlet server no longer reports this move. A server restart before the switch abandons the move and keeps the server where it was.")}}function Br(e){return`The server moved to ${e.targetHostName}: ${e.serverUrl}`}function ct(e){return e.state==="cancelled"?"The server move was cancelled.":e.error===null?"The server move failed.":`The server move failed at "${nt(e.error.step,e.targetHostName)}": ${e.error.message}`}function lt(e){console.log(`Moving the Moonlet server to ${e.targetHostName} (${Ss[e.state]})`),console.log(`Address: ${e.serverUrl} (${Ir(e.mode)})`),console.log(`Started: ${new Date(e.startedAt).toLocaleString()}`),e.finishedAt!==null&&console.log(`Finished: ${new Date(e.finishedAt).toLocaleString()}`),console.log("");for(let t of e.steps)console.log(` ${Tr[t.status].padEnd(8)} ${nt(t.id,e.targetHostName)}${Nr(t)}`);if(e.state==="recovery_required"){console.log(""),st(e);return}e.error!==null&&(console.log(""),console.log(ct(e))),e.cancellable&&(console.log(""),console.log("Cancel it with bb server move cancel."))}function $r(e){if(e.move!==null){lt(e.move);return}let{lastMove:t}=e;if(t===null){console.log("No server move in progress.");return}console.log(`No server move in progress. The server last moved from ${t.fromHostName} to ${t.toHostName} on ${new Date(t.completedAt).toLocaleString()}.`)}var Vr="This export is not encrypted and holds the server's credentials and plugin secrets. Keep it private; Moonlet wrote it with mode 0600.";function Hr(e){return Qe(e)?"npx bb-app or the desktop app":`npx bb-app --data-dir ${e}`}function Is(e){return Qe(e)?"bb server allow-connect":`bb server allow-connect --data-dir ${e}`}var ks="Stopped following; the move continues. Run bb server move status to check on it or bb server move cancel to cancel it.";function Fs(e){if(e===void 0)return null;let t=e.trim();if(t.length===0)throw new Error("--address must not be empty.");return t}async function Cs(e){let t=jr(e),r=await dt(t).catch(()=>null);if(r===null||!r.isDirectory())throw new Error(`Directory ${t} does not exist.`);if((await dt(e).catch(()=>null))?.isDirectory()===!0)throw new Error(`${e} is a directory.`)}async function Ns(e){let{outPath:t}=e,r=ut(jr(t),`.${Rs(t)}.${Ms(6).toString("hex")}.tmp`),n=Es("sha256");async function*o(){let a=e.body.getReader();try{for(;;){let c=await a.read();if(c.done)return;n.update(c.value),yield c.value}}finally{await a.cancel().catch(()=>{})}}let i=await xs(r,"wx",384).catch(async a=>{throw await e.body.cancel().catch(()=>{}),a});try{let a=i.createWriteStream(),c=new Promise(l=>a.once("close",l));if(await _s(o,a).finally(()=>c),n.digest("hex")!==e.expectedSha256)throw new Error(`The downloaded export does not match the SHA-256 digest the server sent, so ${t} was not written. Try the export again.`);await As(r,t)}catch(a){throw await i.close(),await Ps(r,{force:!0}),a}return(await dt(t)).size}async function zr(e,t){let r=new AbortController,n=()=>r.abort();process.once("SIGINT",n);try{return await e(r.signal)}catch(o){throw r.signal.aborted?new b(t,130):o}finally{process.off("SIGINT",n)}}async function Ts(e,t){if(t.to===void 0||t.to.trim().length===0)throw new Error("Pass --to <machine> with the ID or name of the machine that should run the server. Run bb server move status to check on a move in progress.");let r=Fs(t.address),n=G(e()),o=await vt({serverUrl:e(),target:t.to}),i=await Ae(()=>n.experimental_server.checkMove({targetHostId:o,serverUrl:r})),a=u=>{throw f(t,i),new b(u,1)};if(t.json||kr(i),i.requiresServerUrl&&r===null&&a(Fr(i)),i.canMove||a(`The server can't move to ${i.targetHostName} yet. Resolve the blockers above and try again.`),t.check){f(t,i)||(console.log(`The server can move to ${i.targetHostName}.`),i.existingTargetServerData!==null&&console.log(it(i)));return}if(i.existingTargetServerData!==null&&!t.archiveExistingData&&a(it(i)),!t.yes&&!await M(`Stop all running work and move the Moonlet server to ${i.targetHostName}?`))return;let c;try{c=await Ae(()=>n.experimental_server.startMove({targetHostId:o,serverUrl:r,stopRunningWork:!0,archiveExistingTargetServerData:t.archiveExistingData===!0}))}catch(u){let m=Cr(u);throw m!==null&&!t.json&&ot(m),u}let l=await zr(u=>Dr({sdk:n,initial:c,signal:u,report:m=>console.error(m)}),ks);if(f(t,l.status),l.kind==="recovery")throw t.json||st(l.status),new b(at(l.status),rt);if(l.kind==="ended")throw new b(ct(l.status),1);t.json||console.log(Br(l.status))}function nd(e,t){let r=e.command("server").description("Move, export, and import the Moonlet server"),n=r.command("move").description("Move the Moonlet server to another machine (experimental)").option("--to <machine>","Machine ID or name that should run the server").option("--address <url>","Address machines and apps use to reach the new server (direct-address setups)").option("--check","Print the checklist without moving").option("--archive-existing-data","Move existing Moonlet server data on the target aside before the move").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async o=>Ts(t,o)));n.command("status").description("Show the server move in progress or the last completed move").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=await G(t()).experimental_server.moveStatus();if(f(o,i)||$r(i),i.move?.state==="recovery_required")throw new b(at(i.move),rt)})),n.command("cancel").description("Cancel the server move before the switch starts, or abandon a move that needs recovery").option("--yes","Skip the confirmation before abandoning a move that needs recovery").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=G(t()),{move:a}=await i.experimental_server.moveStatus();if(a?.state==="recovery_required"){for(let l of Or(a))console.error(l);if(!o.yes&&!await M(`Abandon the server move to ${a.targetHostName}?`))return}let c=await i.experimental_server.cancelMove();if(!f(o,c)){if(c.state==="cancelled"){console.log(c.error?.step==="switch"?`Abandoned the server move to ${c.targetHostName}. The server stays on this computer.`:`Cancelled the server move to ${c.targetHostName}. The server stays where it is.`);return}lt(c)}})),r.command("export").description("Export the Moonlet server's data to an archive").requiredOption("--out <file>","Write the archive to this file").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=Lr(o.out);await Cs(i);let a=await zr(async l=>{let u=await Ae(()=>G(t()).experimental_server.export({signal:l}));return{sizeBytes:await Ns({body:u.body,outPath:i,expectedSha256:u.sha256}),sha256:u.sha256}},"Stopped the export."),c={path:i,sizeBytes:a.sizeBytes,sha256:a.sha256,warning:Vr};f(o,c)||(console.log(`Exported the Moonlet server to ${i} (${q(a.sizeBytes)})`),console.error(Vr))})),r.command("import <file>").description("Install an export into a local data directory (does not call a server)").option("--data-dir <dir>","Data directory to import into (default: BB_DATA_DIR or ~/.bb)").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async(o,i)=>{let a=W(i.dataDir),c=await vr({archivePath:Lr(o),dataDir:a,confirm:l=>i.yes?Promise.resolve(!0):M(l),now:()=>Date.now(),cliVersion:ft()});c!==null&&(f(i,c)||(c.rolledBackInterruptedImport&&console.log(`Rolled back an interrupted import in ${a}.`),console.log(`Imported the Moonlet server into ${a} (${String(c.importedEntries.length)} files from ${c.sourceDataDir}, exported by Moonlet ${c.bbVersion}).`),console.log(""),console.log("Stop the original Moonlet server before you start this one. Two servers holding the same Moonlet Connect credential take each other's tunnel."),console.log(`Moonlet Connect stays off in this copy until you run ${Is(a)}.`),console.log(`Then start it with ${Hr(a)}.`)))})),r.command("unlock").description("Let an old server copy left by a move start again (does not call a server)").option("--data-dir <dir>","Data directory of the old server copy (default: BB_DATA_DIR or ~/.bb)").option("--force","Unlock even when the new server still answers at its address").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=W(o.dataDir),a=await B(i);if(a===null){f(o,{dataDir:i,unlocked:!1,removedConfigKeys:[]})||console.log(`${i} is not locked by a server move.`);return}if(a.oldCopyEntries.length===0)throw new Error(`The old server copy in ${i} was deleted, so there is nothing to unlock. Unlocking would start an empty Moonlet server.`);let c=await tt(i);if(c!==null)throw new Error(`A background service (${c}) runs this computer as a machine from ${i}. Unlocking would start a second host daemon on the same data. Remove the service first: ${Rr(c)}`);if(!o.force){let u=await fr({dataDir:i,lock:a});if(u.kind==="running")throw new Error(`The server at ${a.serverUrl} is running. Unlocking now would run two servers with the same data and Moonlet Connect credential. Stop it first, or pass --force.`);u.kind==="unconfirmed"&&console.error(`Couldn't confirm whether the server at ${a.serverUrl} is running (HTTP ${String(u.status)}). Make sure it is stopped before this old copy starts.`)}if(console.error(`This Moonlet server moved to ${a.toHostName} (${a.serverUrl}) on ${new Date(a.movedAt).toLocaleString()}.`),console.error(`Unlocking starts this old copy again. Everything since the move is lost here: threads, settings, and plugin data changed on ${a.toHostName} stay there.`),console.error(`Stop the Moonlet server on ${a.toHostName} first. Two servers holding the same Moonlet Connect credential take each other's tunnel.`),!o.yes&&!await M(`Unlock the old Moonlet server copy in ${i}?`))return;let l=await wr(i);f(o,{dataDir:i,unlocked:!0,removedConfigKeys:l})||(l.length>0&&console.log(`Removed the new server's address from ${ut(i,"config.json")} (${l.join(", ")}).`),console.log(`Unlocked ${i}. Moonlet on this computer starts the old server again within a few seconds; if Moonlet isn't running, start it with ${Hr(i)}.`))})),r.command("install-machine-service").description("Keep this computer connected as a machine with a background service after its server moved away").option("--data-dir <dir>","Data directory the server moved away from (default: BB_DATA_DIR or ~/.bb)").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=await _r({confirm:a=>o.yes?Promise.resolve(!0):M(a),dataDir:W(o.dataDir),installerOutput:o.json?"stderr":"stdout",report:a=>console.error(a)});i!==null&&(f(o,i)||console.log(`This computer now stays connected to ${i.toHostName} as a machine, even when Moonlet is closed. The service updates Moonlet whenever the server does.`))})),r.command("allow-connect").description("Let Moonlet account and Moonlet Connect start from an imported server copy (does not call a server)").option("--data-dir <dir>","Data directory of the imported server (default: BB_DATA_DIR or ~/.bb)").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=W(o.dataDir);if(!bs(ut(i,Q))){f(o,{dataDir:i,connectHoldRemoved:!1})||console.log(`${i} has no Moonlet Connect hold.`);return}if(console.error("Stop the original Moonlet server first. Two servers holding the same Moonlet account credential take each other's tunnel and spend the same hosted quota."),!o.yes&&!await M(`Let Moonlet account and Moonlet Connect start from the imported Moonlet server in ${i}?`))return;let a=await L(i);f(o,{dataDir:i,connectHoldRemoved:a})||console.log(`Removed the Moonlet Connect hold from ${i}. Moonlet account and Moonlet Connect start the next time this server starts; restart Moonlet if it's already running.`)})),r.command("delete-old-copy").description("Delete the old server copy left by a move (does not call a server)").option("--data-dir <dir>","Data directory of the old server copy (default: BB_DATA_DIR or ~/.bb)").option("--yes","Skip the confirmation prompt").option("--json","Print machine-readable JSON output").action(w(async o=>{let i=W(o.dataDir),a=await B(i);if(a===null||a.oldCopyEntries.length===0){f(o,{dataDir:i,deleted:!1,deletedEntries:[]})||console.log(a===null?`No old server copy here: ${i} is not locked by a server move.`:`The old server copy in ${i} was already deleted.`);return}if(!o.yes&&!await M(`Delete the old Moonlet server copy in ${i} (${String(a.oldCopyEntries.length)} entries)? The server now runs on ${a.toHostName}; this cannot be undone.`))return;let c=await Be(i,a);f(o,c)||console.log(`Deleted the old Moonlet server copy from ${i} (${String(c.deletedEntries.length)} entries). This computer keeps running as a regular machine.`)}))}export{nd as registerServerCommands};
|