windows-development-sandbox 1.14.0 → 1.15.0
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/config.example.json +2 -1
- package/dist/app/features/defs.d.ts +1 -1
- package/dist/app/features/projects/projects.def.d.ts +1 -1
- package/dist/app/features/projects/projects.run.d.ts +1 -1
- package/dist/app/features/projects/projects.run.js +10 -2
- package/dist/app/features/sandbox/sandbox.def.js +3 -1
- package/dist/app/features/settings/categories.def.js +1 -0
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-BQ23GBLC.js → chunk-D7CM63BS.js} +1893 -1405
- package/dist/bin/{chunk-F7IMME5G.js → chunk-HTQT5SBY.js} +1 -1
- package/dist/bin/{chunk-LQHEUN2A.js → chunk-RQ4BWBYX.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/projects/here.js +2 -0
- package/dist/cli/services/health-service.js +15 -3
- package/dist/cli/services/projects-service.d.ts +8 -3
- package/dist/cli/services/projects-service.js +21 -4
- package/dist/core/config/defaults.js +1 -0
- package/dist/core/schema/config.d.ts +4 -0
- package/dist/core/schema/projects.d.ts +4 -0
- package/dist/core/schema/projects.js +3 -0
- package/dist/guest/boot/boot.js +8 -2
- package/dist/guest/daemon/daemon.js +3 -0
- package/dist/guest/daemon/live-folders.d.ts +48 -0
- package/dist/guest/daemon/live-folders.js +245 -0
- package/dist/guest/daemon/live.d.ts +4 -0
- package/dist/guest/daemon/live.js +57 -0
- package/dist/guest/entries/daemon.js +4 -2
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/runtime/secrets.d.ts +5 -2
- package/dist/guest/runtime/secrets.js +12 -5
- package/dist/host/engines/hcs/live-folders.d.ts +117 -0
- package/dist/host/engines/hcs/live-folders.js +347 -0
- package/dist/host/engines/index.d.ts +1 -0
- package/dist/host/engines/index.js +1 -0
- package/dist/host/launch/generate.js +8 -1
- package/dist/host/projects/join.d.ts +4 -0
- package/dist/host/projects/join.js +11 -3
- package/dist/host/projects/mapper.d.ts +34 -5
- package/dist/host/projects/mapper.js +88 -20
- package/dist/host/projects/registry.d.ts +2 -0
- package/dist/host/projects/registry.js +1 -1
- package/dist/host/secrets/launch-secrets.js +2 -1
- package/dist/runtime/agent.js +14 -0
- package/dist/runtime/daemon.js +466 -132
- package/dist/runtime/db.js +14 -0
- package/dist/runtime/main.js +26 -3
- package/dist/runtime/netproxy.js +14 -0
- package/dist/runtime/view.js +14 -0
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/layout.test.js +1 -0
- package/dist/selftest/live-folders.test.d.ts +2 -0
- package/dist/selftest/live-folders.test.js +588 -0
- package/dist/selftest/projects.test.js +7 -7
- package/dist/selftest/support/engine-golden.js +1 -0
- package/dist/selftest/support/fixtures.d.ts +1 -0
- package/dist/selftest/support/live.js +2 -0
- package/dist/shared/channel/index.d.ts +1 -0
- package/dist/shared/channel/index.js +1 -0
- package/dist/shared/channel/live.d.ts +53 -0
- package/dist/shared/channel/live.js +92 -0
- package/dist/shared/channel/run-dir.d.ts +5 -0
- package/dist/shared/channel/run-dir.js +11 -0
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +5 -0
- package/dist/shared/paths/projects.d.ts +6 -1
- package/dist/shared/paths/projects.js +21 -1
- package/dist/sync/watcher.js +9 -0
- package/dist/web/index.html +1 -1
- package/dist/web/{main-6XNBTJLT.js → main-7DJZ2M27.js} +1 -1
- package/native/csharp/HcsHost/AssemblyInfo.cs +4 -4
- package/native/csharp/HcsHost/FolderAccess.cs +361 -0
- package/native/csharp/HcsHost/Hcs.cs +31 -3
- package/native/csharp/HcsHost/Program.cs +54 -6
- package/native/csharp/HcsHost/Share.cs +64 -11
- package/native/csharp/HcsHost/WsbGuard.cs +130 -0
- package/native/csharp/HcsHost/WsbShare.cs +295 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/native/scripts/contained-common.ps1 +4 -0
- package/native/scripts/hcs-live-share.ps1 +191 -0
- package/package.json +1 -1
- package/sandbox/csharp/BindMount.cs +120 -0
- package/schemas/config.schema.json +8 -0
|
@@ -124,7 +124,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
124
124
|
`),cli:{name:"storage",action:"contained status",json:!0,shapeJson:({fixes:e,...t})=>t}}),Y1=_e({id:"storage.containedOn",title:"Turn contained storage on\u2026",summary:"(beta) keep tools, state and logs in a disk image",input:h.object({}),output:h.object({message:h.string().describe("What happened")}),text:e=>e.message,cli:{name:"storage",action:"contained on"}}),J1=_e({id:"storage.containedOff",title:"Turn contained storage off\u2026",summary:"(beta) move tools, state and logs back into plain folders",danger:!0,input:h.object({}),output:h.object({message:h.string().describe("What happened")}),text:e=>e.message,cli:{name:"storage",action:"contained off"}});function Sve(e,t){let r={id:"folder",title:"Data folder",description:"Where your tools, logins, history and logs are kept between sandboxes.",facts:[{id:"folder",label:"Folder",value:e.root},{id:"size",label:"Size",value:e.size},{id:"default",label:"Default folder",value:e.defaultRoot+(e.defaultInUse?" (in use)":"")},...e.otherFoldersWithData.map((o,i)=>({id:"other:"+i,label:"Other folder with data",value:o}))],actions:[le(X1,{}),le(Q1,{})]},n={id:"contained",title:"Contained storage (beta)",description:"Beta, and not yet tested on a real PC: keeps the sandbox tools, state and logs in one disk image file.",facts:[{id:"setting",label:"Turned on",value:t.setting==="vhdx"?"yes":"no",tone:t.setting==="vhdx"?"ok":"muted"},{id:"pc",label:"This PC",value:t.available?"can use it":"cannot use it",tone:t.available?"ok":"warn",...t.available?{}:{description:[...t.reasons,...t.fixes].join(" ")}},{id:"image",label:"Image",value:t.imageExists?Wu(t.imageBytes??0)+" on disk":"not made yet",description:t.image},{id:"mount",label:"Mount folder",value:t.mountFolder},{id:"mounted",label:"Mounted now",value:t.mountedNow===null?"not checked":t.mountedNow?"yes":"no"}],actions:t.setting==="off"?[le(Y1,{})]:[le(J1,{})]};return{title:"Storage",sections:[r,n]}}var aQ=lt({id:"storage",title:"Storage",summary:"Where your saved data lives: move it, switch folders, (beta) a disk image.",queries:{storage:KO,contained:qO},operations:[nh,X1,Q1,Y1,J1],pickers:[oh],inputs:()=>({storage:{measure:!0}}),build:({storage:e,contained:t})=>Sve(e,t)});var ek=h.enum(["user","project"]).describe("Your own settings (all projects) or this folder's .sandbox-config.json (this project)"),XO=h.string().regex(/^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+)*$/).max(200).describe("The setting, e.g. sandbox.memoryMb"),kve=h.object({id:h.string().describe("The setting, e.g. sandbox.memoryMb"),key:h.array(h.string()),label:h.string(),category:h.string(),section:h.string().optional(),field:Zc,value:h.unknown(),set:h.boolean(),yours:h.unknown(),yoursSet:h.boolean(),inProject:h.unknown().optional(),default:h.unknown().optional(),locked:h.boolean()}),Cve=h.object({scope:ek,file:h.string().describe("The file this scope edits"),exists:h.boolean(),dataFolder:h.string().optional(),exportFile:h.string().optional().describe("Where an export goes by default (full path; your own settings only)"),categories:h.array(h.object({id:h.string(),label:h.string(),description:h.string()})),rows:h.array(kve)}),QO=Ge({id:"settings.list",title:"Settings",summary:"every setting with its value, by category",input:h.object({scope:ek.default("user")}),output:Cve,cli:{name:"config",action:"list",json:!0}}),lQ=Ge({id:"settings.get",title:"Get a setting",summary:"show one setting (secrets as ***)",input:h.object({key:XO}),output:h.object({key:h.string(),value:h.unknown()}),text:e=>typeof e.value=="string"?e.value:JSON.stringify(e.value,null,2),surfaces:{except:{menu:"Settings shows every value",web:"the Settings page shows every value"}},cli:{name:"config",action:"get",positional:["key"]}}),Pve=["attach.","resume."];function cQ(e){let t=e??{},r=typeof t.key=="string"?t.key:"";return(t.scope===void 0||t.scope==="user")&&Pve.some(o=>r.startsWith(o)&&r.length>o.length)?"control":"owner"}var Qn=_e({id:"settings.set",access:cQ,title:"Change a setting",summary:"change one setting (text is read like the command line: true/on, numbers, JSON)",input:h.object({scope:ek.default("user"),key:XO,value:h.unknown().describe("The new value")}),output:h.object({key:h.string(),changed:h.boolean(),message:h.string()}),text:e=>e.message,cli:{name:"config",action:"set",positional:["key","value"]}}),tk=_e({id:"settings.reset",access:cQ,title:"Reset a setting",summary:"put one setting back to its default (in a project file: remove it)",input:h.object({scope:ek.default("user"),key:XO}),output:h.object({key:h.string(),changed:h.boolean(),message:h.string()}),text:e=>e.message,cli:{name:"config",action:"reset",positional:["key"]}}),dQ=h.string().max(2e3).regex(/\.json$/i,"The file name should end in .json."),Qx=_e({id:"settings.export",title:"Export settings\u2026",summary:"write the settings you changed to a .json file to share (no secrets, no data folder, no paths of this PC)",input:h.object({settingsFile:dQ.optional().describe("(export, import) the .json file; default sandbox-settings.json in the current folder"),withPaths:h.boolean().default(!1).describe("(export) keep folders and files of this PC in the file")}),output:h.object({file:h.string().describe("The file written (full path)"),leftOut:h.array(h.string()).describe('What was left out, one "<key> (<why>)" each'),pathsLeftOut:h.boolean().describe("A folder or file of this PC was left out (and --with-paths was not given)")}),text:e=>["Wrote "+e.file+" (only what differs from the defaults).",...e.leftOut.length?["Left out:",...e.leftOut.map(t=>" "+t)]:[],...e.pathsLeftOut?["Keep this PC's folders and files in the file with --with-paths."]:[]].join(`
|
|
125
125
|
`),cli:{name:"config",action:"export",positional:["settingsFile"],flags:{withPaths:{flag:"--with-paths"}}}}),Yx=_e({id:"settings.import",title:"Import settings\u2026",summary:"read a shared settings file, show what it would change, and apply it after one yes",input:h.object({settingsFile:dQ.optional().describe("(export, import) the .json file")}),output:h.object({changed:h.number().describe("How many settings changed"),message:h.string().describe("What happened")}),text:e=>e.message,cli:{name:"config",action:"import",positional:["settingsFile"]}});function sQ(e,t){return{...ns(new ha(e.input).child("settingsFile"),["settingsFile"]),label:t,optional:!1}}function Dve(e,t){let r=n=>B1(n,e.field,40).text;return["Setting "+e.id,"All projects "+r(e.yours)+(e.yoursSet?" (your file)":" (built-in default)"),"This project "+(e.inProject===void 0?"not set":r(e.inProject)),...t==="user"?["Default "+r(e.default)]:[],...t==="project"&&e.locked?["A project can only make this stricter than your own setting."]:[]]}function Rve(e,t){let r=t==="project"&&!e.set?"all projects: "+B1(e.yours,e.field,40).text:B1(e.value,e.field).text,n=e.field.kind==="secret"?"":e.value;return{id:e.id,label:e.label,hint:r,...e.set?{tone:t==="project"?"accent":"ok",badges:[{text:"changed",tone:"accent"}]}:{},description:e.field.help,group:e.section,details:Dve(e,t),keywords:e.id,code:e.id,cells:{setting:e.id,value:r},primary:le(Qn,{scope:t,key:e.id},{label:"Change",verb:"edit",inline:!0,fields:[{...e.field,name:"value",label:e.label}],initial:{value:n}}),actions:e.set?[le(tk,{scope:t,key:e.id},{label:t==="project"?"Remove":"Reset to default",verb:"reset",key:"r"})]:[]}}function Tve(e){return{id:"@data-folder",label:"Data folder",hint:e,cells:{setting:"storage.root",value:e},description:"Where your tools, logins, history and logs are kept between sandboxes. Move it with sandbox storage move <folder>.",primary:le(nh,{},{label:"Data folder",verb:"change"})}}function Eve(e){let t=e.categories.map(r=>({id:r.id,title:r.label,description:r.description,columns:[{key:"setting",label:"SETTING"},{key:"value",label:"VALUE"}],columnsOn:"cli",items:[...e.rows.filter(n=>n.category===r.id).map(n=>Rve(n,e.scope)),...r.id==="general"&&e.dataFolder?[Tve(e.dataFolder)]:[]]}));return{title:"Settings",categories:!0,notice:{text:"Editing "+e.file+(e.exists?"":" (created when you save)")+(e.scope==="project"?": only what a project may set; needs your approval at the next launch":""),tone:e.scope==="project"?"accent":"muted"},sections:t,actions:e.scope==="user"?[le(Qx,{},{verb:"export",fields:[sQ(Qx,"Where to write the settings file")],initial:{settingsFile:e.exportFile},description:"Write the settings you changed to a .json file you can share with a team. Secrets, the data folder and folders or files of this PC are left out."}),le(Yx,{},{verb:"import",fields:[sQ(Yx,"Which settings file")],description:"Read a settings file someone shared, see what it would change, and apply it once you say yes. Secrets, the data folder and paths in it are never taken."})]:[]}}var uQ=lt({id:"settings",title:"Settings",summary:"Every setting, for all projects or just this project, with its value, default and description.",queries:{settings:QO},operations:[Qn,tk,Qx,Yx,nh],pickers:[oh],tabs:{param:"scope",choices:[{value:"user",label:"All projects"},{value:"project",label:"This project"}]},inputs:e=>({settings:{scope:e.scope}}),build:({settings:e})=>Eve(e)});var rk=h.enum(["user","project"]).describe("Your own settings (all projects) or this folder's .sandbox-config.json (this project)"),$ve=[{id:"agents",label:"Agent add-ons",description:"Plug-ins for the agents: rtk and Headroom save tokens, claude-mem gives Claude a memory, ccusage reports token use, Playwright, Context7 and REA add MCP servers. Only your own settings turn them on (except REA).",members:["agents"]},{id:"editors",label:"Editors & docs",description:"Code and text editors (VS Code is on by default), plus diagrams and document conversion.",members:["editors","diagrams"]},{id:"clients",label:"DB & API clients",description:"GUIs for the sandbox databases, tools to send HTTP, REST and GraphQL requests, and to inspect traffic.",members:["databases","api","network"]},{id:"tools",label:"Git & utilities",description:"Git GUIs and terminal UIs, archives, file search and comparing, process tools, and decompilers.",members:["git","utilities","reversing"]},{id:"cli",label:"Command-line & cloud",description:"Small developer tools (JSON, search, builds, media ...) and tools for clouds and Kubernetes.",members:["cli","cloud"]},{id:"play",label:"Browsers & games",description:"Browsers for testing web apps, and game engines and editors (they draw with OpenGL on the CPU).",members:["browsers","gamedev"]}];var Ave=h.object({id:h.string().describe("The app"),name:h.string().describe("Its name"),about:h.string().describe("What it is for"),group:h.string().describe("The group it is listed under (APP_GROUPS id)"),size:h.string().describe("Its download size"),cli:h.boolean().describe("A command-line tool (on PATH), not a desktop app"),mesa:h.boolean().describe("Needs OpenGL on the CPU (Mesa)"),fullGitOnly:h.boolean().describe("Only with full git access"),plugsInto:h.string().optional().describe("Which agents an add-on plugs into, and how"),service:h.boolean().optional().describe("Started by the sandbox or the agent (a proxy, an MCP server)"),setting:h.string().optional().describe("The setting it stands for (VS Code, Windows Terminal)"),settingField:Zc.optional(),settingValue:h.unknown().optional(),installed:h.boolean().describe("Downloaded already into the data folder"),on:h.boolean().describe("Installed in every sandbox of this scope")}),Ove=h.object({id:h.string().describe("Its key in apps.custom"),name:h.string().describe("Its name"),from:h.string().describe('"From the latest <repo> release." or "From <url>"'),cli:h.boolean().describe("A command-line tool")}),zve=h.object({scope:rk,file:h.string().describe("The file this scope edits"),exists:h.boolean().describe("The file exists already"),apps:h.array(Ave).describe("The catalogue entries this scope can change"),custom:h.array(Ove).describe("Your own programs (your own scope only)"),customValue:h.unknown().optional().describe("apps.custom as saved, to edit (your own scope only)"),customField:Zc.optional().describe("The Field of apps.custom (your own scope only)")}),YO=Ge({id:"apps.list",title:"Apps",summary:"the apps catalogue: what every sandbox installs",input:h.object({scope:rk.default("user")}),output:zve,surfaces:{except:{cli:"apps are settings: sandbox config set apps.install / apps.custom"}}}),ok=_e({id:"apps.toggle",title:"Install in every sandbox",summary:"turn an app of the catalogue on or off for this scope",input:h.object({scope:rk.default("user"),id:h.string().max(100).describe("The app"),on:h.boolean().describe("Install it (true) or not (false)")}),output:h.object({message:h.string().describe("What changed")}),text:e=>e.message,surfaces:{except:{cli:"apps are settings: sandbox config set apps.install / apps.custom"}}}),nk=_e({id:"apps.setCustom",title:"Your own programs",summary:"change your own programs (apps.custom)",input:h.object({scope:rk.default("user"),value:h.unknown().describe("Programs of your own: a GitHub release or a download link, and the program to start.")}),output:h.object({message:h.string().describe("What changed")}),text:e=>e.message,surfaces:{except:{cli:"apps are settings: sandbox config set apps.custom"}}}),ik=_e({id:"apps.request",access:"control",title:"Request an app\u2026",summary:"open a prefilled GitHub request for an app that is not in the list",input:h.object({}),output:h.object({url:h.string().describe("The request page")}),text:e=>"Opened the request form in your browser: "+e.url,surfaces:{except:{cli:"a request is filed on GitHub; the address is in docs"}}});function Nve(e){return[...e.size!==""?[{label:"Download",text:"~"+e.size+" once, kept in C:\\AgentData\\tools\\"+(e.setting?"":"apps\\")+e.id+(e.installed?" (downloaded already)":"")},{label:"Starts",text:e.service?"by the sandbox or the agent (no shortcut, not on PATH)":e.cli?"from a terminal (on PATH)":"from the desktop or Start > Sandbox apps"}]:[],...e.plugsInto?[{label:"Plugs in",text:e.plugsInto}]:[],...e.mesa?[{label:"Graphics",text:"OpenGL on the CPU (Mesa) is added for it"}]:[],...e.fullGitOnly?[{label:"",text:"Needs full git access (Settings > Projects & setup > Git): it pushes with its own git.",warn:!0}]:[],...e.setting?[{label:"Setting",text:e.setting}]:[]]}function Fve(e){return Nve(e).map(t=>(t.label?t.label.padEnd(10):"")+t.text)}function Lve(e){return{name:"on",key:["apps","install"],kind:"boolean",label:e.name,optional:!1}}function Mve(e,t){let r=e.setting&&e.settingField?le(Qn,{scope:"user",key:e.setting},{label:"Change",verb:"change",inline:!0,fields:[{...e.settingField,name:"value",label:e.name}],initial:{value:e.settingValue}}):le(ok,{scope:t,id:e.id},{label:e.on?"Turn off":"Turn on",verb:"tick",inline:!0,fields:[Lve(e)],initial:{on:e.on}});return{id:e.id,label:e.name,description:e.about,code:e.id,keywords:e.id,details:Fve(e),...e.on?{tone:"ok"}:{},primary:r}}function Bve(e){return{id:"custom-"+e.id,label:e.name,description:e.from,hint:e.cli?"command line":"desktop",disabled:"Your own programs are always installed; change or remove them with Your own programs."}}function jve(e){let t=$ve.map(n=>({id:n.id,title:n.label,description:n.description,items:e.apps.filter(o=>o.group===n.id).map(o=>Mve(o,e.scope))})).filter(n=>(n.items?.length??0)>0);e.scope==="user"&&t.push({id:"custom",title:"Your own programs",description:"Programs you added yourself, from a GitHub release or a download link.",items:e.custom.map(Bve)});let r=e.scope==="user";return{title:"Apps",categories:!0,notice:{text:"Editing "+e.file+(e.exists?"":" (created when you save)")+(e.scope==="project"?": only apps from the list; needs your approval at the next launch":""),tone:e.scope==="project"?"accent":"muted"},sections:t,actions:r?[...e.customField?[le(nk,{scope:"user"},{key:"c",verb:"your own programs",fields:[{...e.customField,name:"value",label:"Your own programs"}],initial:{value:e.customValue}})]:[],le(ik,{},{key:"r",verb:"request an app"})]:[]}}var fQ=lt({id:"apps",title:"Apps",summary:"Tick the apps every sandbox should have. Each downloads once and is kept.",queries:{apps:YO},operations:[ok,nk,ik,Qn],tabs:{param:"scope",choices:[{value:"user",label:"All projects"},{value:"project",label:"This project"}]},inputs:e=>({apps:{scope:e.scope}}),build:({apps:e})=>jve(e)});var Ti={desktop:"desktop window",gpu:"GPU",clipboard:"clipboard",audio:"audio",video:"camera",printers:"printers",liveFolderAdd:"add folders while running",attachedDisks:"attached disks",multipleInstances:"several at once",hvsocket:"Hyper-V sockets"},Uve=Object.keys(Ti),Vve="see docs/design/engines.md",mQ=h.enum(["windows-sandbox","hcs"]).describe("The engine"),Hve=h.object({desktop:h.boolean().describe(Ti.desktop),gpu:h.boolean().describe(Ti.gpu),clipboard:h.boolean().describe(Ti.clipboard),audio:h.boolean().describe(Ti.audio),video:h.boolean().describe(Ti.video),printers:h.boolean().describe(Ti.printers),liveFolderAdd:h.boolean().describe(Ti.liveFolderAdd),attachedDisks:h.boolean().describe(Ti.attachedDisks),multipleInstances:h.boolean().describe(Ti.multipleInstances),hvsocket:h.boolean().describe(Ti.hvsocket)}),Wve=h.object({available:h.boolean().describe("This PC can run it"),reasons:h.array(h.string()).describe("Why not, in plain words"),fixes:h.array(h.string()).describe("The command that fixes each reason (never run for you)")}).describe("Whether this PC can run it"),pQ=h.object({id:mQ,inUse:h.boolean().describe("The setting sandbox.engine names it"),capabilities:Hve.describe("What it can do"),check:Wve}),Zve=h.object({engine:mQ.describe("The engine in use (the setting sandbox.engine)"),engines:h.array(pQ).describe("Every engine")});function Gve(e){if(e.check.available){let r=[e.id+" can be used on this PC."];return e.id==="hcs"&&r.push("HCS is in alpha: starting it is not enabled yet (docs/design/engines.md)."),r.join(`
|
|
126
126
|
`)}let t=[e.id+" cannot be used on this PC yet:"];return e.check.reasons.forEach((r,n)=>{t.push(""," "+(n+1)+". "+r," To fix: "+(e.check.fixes[n]??Vve))}),t.push("","Nothing was changed. These commands change Windows, so they are yours to run (or not)."),t.join(`
|
|
127
|
-
`)}var JO=Ge({id:"engine.status",title:"Engine",summary:"the engine in use and what each engine can do on this PC",input:h.object({}),output:Zve,cli:{name:"engine",action:"show",json:!0}}),hQ=Ge({id:"engine.check",title:"Check an engine",summary:"what this PC lacks for an engine, and the commands that would fix it",input:h.object({engine:h.string().default("hcs").describe("the engine to check")}),output:pQ,surfaces:{except:{menu:"the Engine category shows every engine and its check with the fixes (engine.status)",web:"the Engine page shows every engine and its check with the fixes (engine.status)"}},text:Gve,cli:{name:"engine",action:"check",positional:["engine"],json:!0,exitCode:e=>e.check.available?0:1}}),Kve=h.object({id:h.string().describe("The compute system"),kind:h.string().describe("Container or VirtualMachine (the utility VM)"),state:h.string().describe("What it is doing"),since:h.string().nullable().describe("When it was created (ISO time), when HCS says")}),qve=h.object({available:h.boolean().describe("HCS could be asked"),message:h.string().describe("What was found, or why nothing is listed"),systems:h.array(Kve).describe("Ours that are running now")}),ez=Ge({id:"engine.leftovers",title:"HCS systems left running",summary:"list the HCS compute systems this tool left running (a crashed command can leave one up)",input:h.object({}),output:qve,cli:{name:"engine",action:"leftovers",json:!0}}),ak=_e({id:"engine.clean",title:"Stop the leftover systems\u2026",summary:"stop the HCS compute systems this tool left running (frees their memory; nothing else is touched)",input:h.object({}),output:h.object({available:h.boolean().describe("HCS could be asked"),stopped:h.number().describe("How many were stopped"),failed:h.number().describe("How many could not be stopped"),message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,cli:{name:"engine",action:"clean"}});function Xve(e){return{id:"leftover:"+e.id,label:e.id,hint:e.state+(e.since?" started "+_o(e.since):""),tone:"warn",details:["System "+e.id,"Kind "+e.kind,"State "+e.state,...e.since?["Created "+e.since]:[]]}}function Qve(e){return e.systems.length?[{id:"leftovers",title:"HCS systems left running",summary:Br(e.systems.length,"system")+" (they hold memory; a sandbox running on purpose is listed too)",items:e.systems.map(Xve),actions:[le(ak,{},{key:"x",verb:"stop them",importance:1})]}]:[]}function Yve(e){let t=Uve.map(n=>{let o=e.capabilities[n];return{id:n,label:Ti[n],value:o?"yes":"no",...o?{}:{tone:"muted"}}}),r=[...e.check.reasons.map((n,o)=>({id:"reason:"+o,label:n,tone:"warn"})),...e.check.fixes.map((n,o)=>({id:"fix:"+o,label:"Fix: "+n}))];return{id:e.id,title:e.id+(e.id==="hcs"?" (alpha)":"")+(e.inUse?" (in use)":""),summary:e.check.available?"can be used on this PC":"cannot be used yet",facts:t,items:r}}function Jve(e,t){return{title:"Engine",notice:{text:"Engine in use: "+e.engine+" (setting: sandbox.engine)"},sections:[...e.engines.map(Yve),...t?Qve(t):[]]}}var gQ=lt({id:"engine",title:"Engine",summary:"What runs your sandbox, and what each engine can do on this PC.",queries:{engines:JO,leftovers:ez},operations:[ak],build:({engines:e,leftovers:t})=>Jve(e,t)});var xQ="sandbox doctor and sandbox repair are hand-written renderers of this run (lines redrawn in place, --json alone, repair before the settings load)",exe=h.enum(["ok","fixed","needs-you","warn","skipped"]).describe("What the check found"),txe=h.object({id:h.string().describe("The check"),group:h.string().describe("Its heading (This PC, Install ...)"),name:h.string().describe("What was checked"),status:exe,detail:h.string().describe("What was found"),means:h.string().optional().describe("What it means for you"),fix:h.string().optional().describe("What to do yourself"),plan:h.string().optional().describe("What repair would change"),lines:h.array(h.string()).optional().describe("More lines (a diff, folders)"),fixable:h.boolean().describe("Repair can mend it"),timedOut:h.boolean().optional().describe("It took too long"),applied:h.object({done:h.string(),before:h.string(),after:h.string()}).optional().describe("What a fix changed"),error:h.string().optional().describe("Why a fix did not work")}),bQ=h.object({total:h.number().describe("Checks that ran"),ok:h.number().describe("Checks that are fine"),fixed:h.number().describe("Problems repair fixed"),warn:h.number().describe("Warnings"),needsYou:h.number().describe("Problems you need to fix"),skipped:h.number().describe("Checks that did not run"),fixable:h.number().describe("Problems repair can still mend")}).describe("How many checks ended how"),rxe=h.object({name:h.string().describe("What was looked at"),status:h.enum(["ok","warn","action"]).describe("OK, a warning, or something to do"),detail:h.string().describe("What was found")}),oxe=h.object({at:h.string().describe("When it ran (ISO time)"),mode:h.enum(["check","repair"]).describe("A check or a repair"),checks:h.array(txe).describe("The results"),summary:bQ,details:h.array(h.tuple([h.string(),h.string()])).describe("The doctor details: name and value"),setup:h.object({checks:h.array(rxe),canEnable:h.boolean().describe("Windows Sandbox can be turned on from here"),error:h.string().nullable().describe("Why the setup could not be read")}).nullable().describe("What sandbox setup found"),log:h.string().nullable().describe("The repair log, if one was written")});function yQ(e){return[e.ok+" ok",e.fixed&&e.fixed+" fixed",e.needsYou&&e.needsYou+" "+(e.needsYou===1?"needs":"need")+" you",e.warn&&e.warn+(e.warn===1?" warning":" warnings"),e.skipped&&e.skipped+" skipped"].filter(Boolean).join(", ")}var nxe={ok:"[ok]",fixed:"[fixed]",warn:"[!]","needs-you":"[x]",skipped:"[-]"},ih={ok:void 0,fixed:"accent",warn:"warn","needs-you":"danger",skipped:"muted"},tz=6;function ixe(e){let t={text:" "+nxe[e.status]+" "+e.name+": "+e.detail+(e.timedOut?" (took too long)":""),...ih[e.status]?{tone:ih[e.status]}:{}};if(e.status==="ok")return[t];let r=[t];e.means&&r.push({text:" What it means: "+e.means}),e.fixable&&e.plan?r.push({text:" Fix: sandbox repair will "+e.plan}):e.fix&&r.push({text:" Fix: "+e.fix});let n=e.lines??[];for(let o of n.slice(0,tz))r.push({text:" "+o});return n.length>tz&&r.push({text:" ... and "+(n.length-tz)+" more"}),r}var vQ={ok:"OK",fixed:"FIXED","needs-you":"NEEDS YOU",warn:"WARNING",skipped:"SKIPPED"};function axe(e,t){return e.length<=t?e:e.slice(0,t-1)+"\u2026"}var _Q=h.object({summary:bQ,changed:h.boolean().describe("Fixes were applied"),log:h.string().nullable().describe("The repair log, if one was written")}),rz=Ge({id:"health.last",title:"Health",summary:"the last check or repair of this PC and the sandbox",input:h.object({}),output:h.object({last:oxe.nullable().describe("Nothing yet: no check has run")}),surfaces:{except:{cli:"the command line prints results as it checks (sandbox doctor)"}}}),Jx=_e({id:"health.check",access:"control",title:"Check this PC",summary:"check this PC, the install, your settings and the sandbox (changes nothing)",input:h.object({harness:h.string().optional().describe("agent to check")}),output:_Q,text:e=>"Summary: "+yQ(e.summary),surfaces:{except:{cli:xQ}}}),eb=_e({id:"health.repair",title:"Run the checks and fix what can be fixed",summary:"find and fix problems (install, data folder, settings, stale state, half-installed tools)",input:h.object({}),output:_Q,danger:!0,text:e=>"Summary: "+yQ(e.summary)+(e.log?". Log: "+e.log:". No log was written (the storage folder does not exist yet)."),surfaces:{except:{cli:xQ}}}),sk=_e({id:"health.enableSandbox",title:"Turn on Windows Sandbox",summary:"turn on the Windows Sandbox feature (Windows asks for admin permission; restart to finish)",input:h.object({}),output:h.object({message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,surfaces:{except:{cli:"sandbox setup asks and turns it on (hand-written: it also offers to restart Windows)",web:"Windows asks for admin permission on this PC; use the menu or sandbox setup"}}});function sxe(e){return e.checks.map((t,r)=>{let n=t.detail+(t.timedOut?" (took too long)":""),o=ixe(t).slice(1).map(a=>a.text.trim()).filter(a=>!a.startsWith("What it means: ")),i=t.status==="ok"?[]:["Found: "+n,...o];return{id:"repair:"+r,label:t.name,hint:vQ[t.status],...ih[t.status]?{tone:ih[t.status]}:{},badges:[{text:vQ[t.status],...ih[t.status]?{tone:ih[t.status]}:{}}],description:t.means??(i.length?void 0:n),...i.length?{details:i}:{}}})}var lxe={ok:"OK",warn:"WARNING",action:"NEEDS YOU"};function cxe(e){let t=e.last,r=le(Jx,{},{verb:"check"}),n=le(eb,{},{verb:"check and fix"});if(!t)return{title:"Health",sections:[{id:"doctor",title:"Doctor",cards:!0,items:[{id:"health:check",label:"Check this PC",description:"Looks at this PC: Windows features, the install, the folders and the sandbox. It takes a few seconds, so it only runs when you ask.",primary:r}]},{id:"repair",title:"Repair",cards:!0,items:[{id:"repair:run",label:"Run the checks and fix what can be fixed",description:"Checks the install, data folder, settings and sandbox, lists what it would change, and asks before it fixes anything.",primary:n}]}]};let o=!!t.setup?.canEnable,i=[{id:"status",summary:(t.mode==="repair"?"Last repair ":"Last check ")+_o(t.at),...t.log?{notes:[{text:"Log: "+t.log,tone:"muted"}]}:{}},{id:"doctor",title:"Doctor",items:t.details.map(([a,s],l)=>({id:"doctor:"+l,label:a,hint:axe(s,50),...s.length>50?{description:s}:{}}))},{id:"repair",title:"Repair",items:sxe(t)}];if(t.setup){let a=t.setup;i.push({id:"setup",title:"Set up this PC",items:a.error?[{id:"setup:error",label:a.error}]:a.checks.map((s,l)=>({id:"setup:"+l,label:s.name,hint:s.detail,tone:s.status==="ok"?"ok":s.status==="warn"?"warn":"danger",badges:[{text:lxe[s.status],tone:s.status==="ok"?"ok":s.status==="warn"?"warn":"danger"}]})),notes:o?[{text:"Turn Windows Sandbox on from the menu or with sandbox setup.",tone:"muted",only:"web"}]:[]})}return{title:"Health",sections:i,actions:[le(eb,{},{key:"f",verb:"check and fix",importance:1}),le(Jx,{},{key:"l",verb:t?"check again":"check",importance:2}),...o?[le(sk,{},{key:"e",verb:"turn on Windows Sandbox",importance:3})]:[]]}}var IQ=lt({id:"health",title:"Health",summary:"Checks this PC and your settings, repairs problems, and sets up Windows Sandbox.",queries:{last:rz},operations:[Jx,eb,sk],build:({last:e})=>cxe(e)});var wQ=["tools","databases","state","logs","data","host"],dxe={tools:"Toolchains",databases:"Databases",state:"Agent state",logs:"Logs",data:"Other",host:"On this PC"},uxe=h.object({area:h.enum(wQ).describe("Which kind of data it is"),name:h.string().describe("The folder as listed (tools: its name; others: area/name)"),path:h.string().describe("Its full path on this PC"),bytes:h.number().describe("Its size in bytes (links count 0)"),size:h.string().describe("Its size in words, e.g. 1.5 KB"),target:h.string().nullable().describe("What sandbox data clean calls it; null when it is kept on purpose")}),fxe=h.object({drive:h.string().describe("The drive, e.g. C:\\"),totalBytes:h.number().describe("Its size in bytes"),freeBytes:h.number().describe("Free bytes"),usedBytes:h.number().describe("Used bytes"),holdsStorage:h.boolean().describe("The sandbox keeps its files on this drive"),used:h.string().describe("Used, in words"),usedPercent:h.number().describe("Used, in percent of the size (rounded)"),free:h.string().describe("Free, in words"),total:h.string().describe("Size, in words")}),mxe=h.object({dataPath:h.string().describe("The data folder (C:\\AgentData inside the sandbox)"),storageRoot:h.string().describe("The storage folder that holds it"),totalBytes:h.number().describe("Everything listed, in bytes"),total:h.string().describe("Everything listed, in words"),storageShare:h.string().describe('"<- sandbox storage (<total> of it)": the note on the storage drive'),areaTotals:h.record(h.string(),h.string()).describe("Each area's total in words"),entries:h.array(uxe).describe("What is stored, by area, biggest first"),disks:h.array(fxe).describe("This PC's drives")}),oz=Ge({id:"data.show",title:"Stored data",summary:"show what is kept between sandboxes (tools, databases, logins, logs), or delete some of it",input:h.object({}),output:mxe,cli:{name:"data",action:"show",json:!0,shapeJson:e=>({dataPath:e.dataPath,storageRoot:e.storageRoot,totalBytes:e.totalBytes,entries:e.entries.map(({area:t,name:r,path:n,bytes:o})=>({area:t,name:r,path:n,bytes:o})),disks:e.disks.map(({drive:t,totalBytes:r,freeBytes:n,usedBytes:o,holdsStorage:i})=>({drive:t,totalBytes:r,freeBytes:n,usedBytes:o,holdsStorage:i}))})}}),SQ=h.object({message:h.string().describe("What happened")}),lk=_e({id:"data.clean",title:"Delete stored data\u2026",summary:"delete chosen parts of what is kept between sandboxes",input:h.object({targets:h.array(h.string()).default([]).describe("what to clean, e.g. tools/go databases logs")}),output:SQ.extend({freedBytes:h.number().describe("Bytes freed (0 when nothing was removed)")}),danger:!0,text:e=>e.message,next:e=>e.freedBytes>0?"sandbox data (see what is left)":void 0,cli:{name:"data",action:"clean",positional:["targets"]}}),kQ=h.object({days:h.number().int().min(1).default(7).describe("launch folders older than this many days")}),ck=_e({id:"data.prune",title:"Clean up\u2026",summary:"delete old launch folders, logs and leftovers",input:kQ,output:SQ.extend({removed:h.boolean().describe("Something was deleted")}),text:e=>e.message,next:e=>e.removed?"sandbox data (see what else is saved, and clean it)":void 0,cli:{name:"clean",group:"Data",flags:{days:{flag:"--days",value:"n"}},yes:"do not ask before deleting"}}),pxe=ns(new ha(kQ).child("days"),["days"]);function hxe(e){let t={id:"disks",title:"Disks",columns:[{key:"drive",label:"DRIVE"},{key:"used",label:"USED"},{key:"free",label:"FREE"},{key:"size",label:"SIZE"},{key:"note",label:""}],columnsOn:"cli",items:e.disks.map(i=>({id:"disk:"+i.drive,label:i.drive,hint:i.used+" used \xB7 "+i.free+" free of "+i.total,...i.holdsStorage?{description:"The sandbox keeps its files on this drive."}:{},cells:{drive:i.drive,used:i.used+" ("+i.usedPercent+"%)",free:i.free,size:i.total,note:i.holdsStorage?e.storageShare:""}})),notes:[{text:"Persistent data for the sandbox: "+e.dataPath+" (C:\\AgentData inside)"}]},r=i=>wQ.indexOf(i),n=[...e.entries].sort((i,a)=>r(i.area)-r(a.area)||a.bytes-i.bytes),o={id:"kept",title:"What the sandbox keeps",summary:e.total+" in all",columns:[{key:"kind",label:"KIND"},{key:"name",label:"NAME"},{key:"size",label:"SIZE"},{key:"folder",label:"FOLDER"}],items:n.map(i=>{let a=i.target?le(lk,{targets:[i.target]},{label:"Delete",key:"x",verb:"delete"}):void 0;return{id:"entry:"+i.name,label:i.name,hint:i.size,cells:{kind:dxe[i.area],name:i.name,size:i.size,folder:i.path},...a?{primary:a}:{}}}),actions:[le(ck,{},{label:"Clean up\u2026",verb:"choose what",description:"Delete caches, old sandboxes and other leftovers (the clean command, with its options).",fields:[pxe]})],notes:[...e.entries.length?[]:[{text:"Nothing stored yet. Toolchains, databases and agent logins appear here after the first start."}],...gxe(e),{text:"Free space with: sandbox data clean <target...> (e.g. tools/go, databases/postgres-18, logs, launches)",tone:"muted",only:"cli"}]};return{title:"Data",sections:[t,o]}}function gxe(e){let t=e.entries.filter(r=>!r.target).map(r=>r.name);return t.length?[{text:"Kept on this PC on purpose, not deleted here: "+t.join(", ")+"."}]:[]}var CQ=lt({id:"data",title:"Data",summary:"What the sandbox keeps between runs, and deleting parts of it.",queries:{data:oz},operations:[lk,ck],build:({data:e})=>hxe(e)});var vxe=h.object({name:h.string().describe("The project"),host:h.string().describe("Its folder on this PC"),guest:h.string().describe("Its folder in the sandbox"),mechanism:h.string().describe("How it got into the sandbox (launch, root, boot or share)"),here:h.boolean().describe("The project of the current folder"),setup:h.object({phase:h.string(),message:h.string()}).describe("How far its setup is"),databases:h.array(h.object({database:h.string(),port:h.number(),state:h.string()})),sessions:h.array(h.object({id:h.string(),harness:h.string(),viewers:h.string(),started:h.string()})),repoGuard:h.array(h.string()).describe("Repo guard findings in its folder")}),xxe=h.object({running:h.boolean().describe("A Windows Sandbox is running"),phase:h.string().describe("What it is doing (ready, provisioning ...)"),message:h.string().optional().describe("Its last message"),headless:h.boolean().optional().describe("Its window is hidden"),startedAt:h.number().nullable().describe("When it started (ms), if known"),daemon:h.string().describe("The sandbox helper's answer"),account:h.string().nullable().describe("The Claude login it uses"),syncWatcher:h.boolean().describe("The background history sync runs")}),bxe=h.object({shared:h.object({line:h.string().describe('"Running, started by alice (shared with you)"'),limited:h.boolean().describe("Not shared with you: nothing more is shown"),startedBy:h.string().nullable().describe("Whose it is")}).optional(),sandbox:xxe,here:h.object({folder:h.string(),project:h.string().nullable(),guest:h.string().nullable()}),roots:h.array(h.object({host:h.string(),guest:h.string()})),projects:h.array(vxe),otherSessions:h.array(h.object({id:h.string(),harness:h.string(),cwd:h.string()})),repoGuard:h.object({guarded:h.number(),findings:h.array(h.string())})}),PQ=h.object({message:h.string().describe("What happened")});function yxe(e){let t=/^pong \((\d+) session/.exec(e);return t?"responding, "+Br(Number(t[1]),"session")+" running":e}function DQ(e){return e.running&&e.startedAt?_o(e.startedAt).replace(" ago",""):null}var nz=Ge({id:"sandbox.status",title:"Sandbox status",summary:"show what the sandbox is doing",input:h.object({}),output:bxe,live:{everyMs:2500},cli:{name:"status",group:"Sessions",json:!0,shapeJson:e=>{if(e.shared?.limited)return{sandbox:{running:!0,shared:!1,startedBy:e.shared.startedBy}};let t=e.sandbox;return{sandbox:{...e.shared?.startedBy?{startedBy:e.shared.startedBy,shared:!0}:{},running:t.running,phase:t.phase,message:t.message,headless:t.headless,uptime:DQ(t),daemon:t.daemon,account:t.account,syncWatcher:t.syncWatcher},here:e.here,roots:e.roots,projects:e.projects,otherSessions:e.otherSessions,repoGuard:e.repoGuard}}}}),dk=_e({id:"sandbox.showWindow",access:"control",title:"Show the window",summary:"show the sandbox window",input:h.object({}),output:PQ,text:e=>e.message,cli:{name:"show",group:"Sessions"}}),uk=_e({id:"sandbox.hideWindow",access:"control",title:"Hide the window",summary:"hide the sandbox window (it keeps running)",input:h.object({}),output:PQ,text:e=>e.message,cli:{name:"hide",group:"Sessions"}}),fk=_e({id:"sandbox.stop",access:"control",title:"Stop the sandbox\u2026",summary:"shut the sandbox down (every project's sessions end)",input:h.object({}),output:h.object({stopped:h.boolean().describe("It was asked to shut down"),message:h.string()}),danger:!0,text:e=>e.message,cli:{name:"stop",group:"Agents",yes:"do not ask when other projects' sessions would end"}}),_xe={launch:"started from here",root:"in a project root",boot:"mapped at start"};function Ixe(e){return{id:"project:"+e.name,label:e.name,icon:"project",hint:e.host+" -> "+e.guest+" ("+(_xe[e.mechanism]??"wsb share")+")",marked:e.here,details:["Setup: "+e.setup.phase+(e.setup.phase==="ready"?"":" - "+e.setup.message),...e.databases.length?["Databases: "+e.databases.map(t=>t.database+" :"+t.port+" "+t.state).join(", ")]:[],...e.sessions.map(t=>"Session: "+t.harness+" "+t.id+", "+t.viewers+", started "+_o(t.started)),...e.repoGuard.map(t=>"Guard: "+t)]}}function wxe(e){let t=e.sandbox,r=e.projects.reduce((o,i)=>o+i.sessions.length,0)+e.otherSessions.length,n=(o,i,a,s={})=>({id:o,label:i,value:a,...s});return[...e.shared?.startedBy?[n("owner","Started by",e.shared.startedBy)]:[],n("state","State",t.running?t.message||t.phase:"not running",{tone:t.running?t.phase==="ready"?"ok":"warn":"muted"}),...t.running?[n("window","Window",t.headless?"hidden (sandbox show opens it)":"shown"),n("uptime","Uptime",DQ(t)??"-"),n("helper","Helper",t.daemon==="-"?"-":yxe(t.daemon)),n("sessions","Sessions",String(r))]:[],n("account","Account",t.account??"none selected (sandbox account use)"),n("sync","Background sync",t.syncWatcher?"on":"off")]}function Sxe(e){let t=e.roots.map(n=>({id:"root:"+n.host,label:"root",icon:"folder",hint:n.host+" -> "+n.guest+" (every project in it opens without a restart)"})),r=e.projects.some(n=>n.here);return{id:"projects",title:"Projects",items:[...e.projects.map(Ixe),...t],notes:[r?{text:"* = the project of this folder",tone:"muted"}:{text:e.here.folder+" is not in this sandbox (start it here: sandbox claude)",tone:"muted"}]}}function kxe(e){let t=e.repoGuard.findings;return{id:"guard",title:"Repo guard",summary:e.repoGuard.guarded+" folder(s) guarded; "+(t.length?t.length+" change(s) neutralised:":"nothing from the sandbox needed neutralising"),items:t.slice(-10).map((r,n)=>({id:"guard:"+n,label:r,tone:"warn"}))}}function Cxe(e){let t=e.shared?{text:e.shared.line+(e.shared.limited?"":". Its window is on their desktop; use its agents here."),tone:"accent"}:void 0;if(e.shared?.limited)return{title:"Sandbox",notice:t,sections:[]};let r=e.sandbox.running,n={id:"status",title:"Status",facts:wxe(e),actions:r?[e.sandbox.headless?le(dk,{},{key:"w",verb:"show",importance:3}):le(uk,{},{key:"h",verb:"hide",importance:3}),le(fk,{},{key:"x",verb:"stop",importance:1})]:[]},o={id:"other-sessions",title:"Other sessions",items:e.otherSessions.map(i=>({id:"session:"+i.id,label:"session "+i.id,hint:i.harness+" "+i.cwd}))};return{title:"Sandbox",notice:t,sections:[n,...r?[Sxe(e)]:[],...o.items?.length?[o]:[],kxe(e)]}}var RQ=lt({id:"sandbox",title:"Sandbox",summary:"What the sandbox is doing, its window, and stopping it.",queries:{status:nz},operations:[dk,uk,fk],build:({status:e})=>Cxe(e)});var Pxe=h.object({folder:h.string().describe("The project folder on this PC"),here:h.boolean().describe("The folder you are in is inside it"),known:h.boolean().describe("Started with this tool before"),root:h.string().nullable().describe("The project root it is in, if any"),excluded:h.boolean().describe("Excluded from the projects mapped at every start"),mappedAtStart:h.boolean().describe("Mapped at every start"),running:h.string().nullable().describe("Its name and how it got into the running sandbox, if it is there")}),Dxe=h.object({all:h.boolean().describe("Every project is mapped at every start (except excluded ones)"),roots:h.array(h.string()).describe("Folders of projects, each opened without a restart"),exclude:h.array(h.string()).describe("Folders left out of the projects mapped at every start"),projects:h.array(Pxe).describe("Every project worth listing")}),ah=h.object({message:h.string().describe("What happened")}),mk=e=>h.string().optional().describe(e+" (. = this folder; asked when left out)"),iz=Ge({id:"projects.list",title:"Projects",summary:"list your projects, roots and the all-projects setting",input:h.object({}),output:Dxe,cli:{name:"projects",action:"list",json:!0}}),pk=_e({id:"projects.choose",title:"Choose the projects mapped at every start\u2026",summary:"tick the projects mapped at every start; the rest are excluded",input:h.object({}),output:ah,text:e=>e.message,cli:{name:"projects",action:"choose"}}),tb=_e({id:"projects.add",title:"Add a project\u2026",summary:"remember a project folder",input:h.object({projectFolder:mk("The project folder")}),output:h.object({message:h.string().describe("What happened"),next:h.string().optional().describe("What to do next, when mapping all projects is off")}),text:e=>e.next?e.message+`
|
|
127
|
+
`)}var JO=Ge({id:"engine.status",title:"Engine",summary:"the engine in use and what each engine can do on this PC",input:h.object({}),output:Zve,cli:{name:"engine",action:"show",json:!0}}),hQ=Ge({id:"engine.check",title:"Check an engine",summary:"what this PC lacks for an engine, and the commands that would fix it",input:h.object({engine:h.string().default("hcs").describe("the engine to check")}),output:pQ,surfaces:{except:{menu:"the Engine category shows every engine and its check with the fixes (engine.status)",web:"the Engine page shows every engine and its check with the fixes (engine.status)"}},text:Gve,cli:{name:"engine",action:"check",positional:["engine"],json:!0,exitCode:e=>e.check.available?0:1}}),Kve=h.object({id:h.string().describe("The compute system"),kind:h.string().describe("Container or VirtualMachine (the utility VM)"),state:h.string().describe("What it is doing"),since:h.string().nullable().describe("When it was created (ISO time), when HCS says")}),qve=h.object({available:h.boolean().describe("HCS could be asked"),message:h.string().describe("What was found, or why nothing is listed"),systems:h.array(Kve).describe("Ours that are running now")}),ez=Ge({id:"engine.leftovers",title:"HCS systems left running",summary:"list the HCS compute systems this tool left running (a crashed command can leave one up)",input:h.object({}),output:qve,cli:{name:"engine",action:"leftovers",json:!0}}),ak=_e({id:"engine.clean",title:"Stop the leftover systems\u2026",summary:"stop the HCS compute systems this tool left running (frees their memory; nothing else is touched)",input:h.object({}),output:h.object({available:h.boolean().describe("HCS could be asked"),stopped:h.number().describe("How many were stopped"),failed:h.number().describe("How many could not be stopped"),message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,cli:{name:"engine",action:"clean"}});function Xve(e){return{id:"leftover:"+e.id,label:e.id,hint:e.state+(e.since?" started "+_o(e.since):""),tone:"warn",details:["System "+e.id,"Kind "+e.kind,"State "+e.state,...e.since?["Created "+e.since]:[]]}}function Qve(e){return e.systems.length?[{id:"leftovers",title:"HCS systems left running",summary:Br(e.systems.length,"system")+" (they hold memory; a sandbox running on purpose is listed too)",items:e.systems.map(Xve),actions:[le(ak,{},{key:"x",verb:"stop them",importance:1})]}]:[]}function Yve(e){let t=Uve.map(n=>{let o=e.capabilities[n];return{id:n,label:Ti[n],value:o?"yes":"no",...o?{}:{tone:"muted"}}}),r=[...e.check.reasons.map((n,o)=>({id:"reason:"+o,label:n,tone:"warn"})),...e.check.fixes.map((n,o)=>({id:"fix:"+o,label:"Fix: "+n}))];return{id:e.id,title:e.id+(e.id==="hcs"?" (alpha)":"")+(e.inUse?" (in use)":""),summary:e.check.available?"can be used on this PC":"cannot be used yet",facts:t,items:r}}function Jve(e,t){return{title:"Engine",notice:{text:"Engine in use: "+e.engine+" (setting: sandbox.engine)"},sections:[...e.engines.map(Yve),...t?Qve(t):[]]}}var gQ=lt({id:"engine",title:"Engine",summary:"What runs your sandbox, and what each engine can do on this PC.",queries:{engines:JO,leftovers:ez},operations:[ak],build:({engines:e,leftovers:t})=>Jve(e,t)});var xQ="sandbox doctor and sandbox repair are hand-written renderers of this run (lines redrawn in place, --json alone, repair before the settings load)",exe=h.enum(["ok","fixed","needs-you","warn","skipped"]).describe("What the check found"),txe=h.object({id:h.string().describe("The check"),group:h.string().describe("Its heading (This PC, Install ...)"),name:h.string().describe("What was checked"),status:exe,detail:h.string().describe("What was found"),means:h.string().optional().describe("What it means for you"),fix:h.string().optional().describe("What to do yourself"),plan:h.string().optional().describe("What repair would change"),lines:h.array(h.string()).optional().describe("More lines (a diff, folders)"),fixable:h.boolean().describe("Repair can mend it"),timedOut:h.boolean().optional().describe("It took too long"),applied:h.object({done:h.string(),before:h.string(),after:h.string()}).optional().describe("What a fix changed"),error:h.string().optional().describe("Why a fix did not work")}),bQ=h.object({total:h.number().describe("Checks that ran"),ok:h.number().describe("Checks that are fine"),fixed:h.number().describe("Problems repair fixed"),warn:h.number().describe("Warnings"),needsYou:h.number().describe("Problems you need to fix"),skipped:h.number().describe("Checks that did not run"),fixable:h.number().describe("Problems repair can still mend")}).describe("How many checks ended how"),rxe=h.object({name:h.string().describe("What was looked at"),status:h.enum(["ok","warn","action"]).describe("OK, a warning, or something to do"),detail:h.string().describe("What was found")}),oxe=h.object({at:h.string().describe("When it ran (ISO time)"),mode:h.enum(["check","repair"]).describe("A check or a repair"),checks:h.array(txe).describe("The results"),summary:bQ,details:h.array(h.tuple([h.string(),h.string()])).describe("The doctor details: name and value"),setup:h.object({checks:h.array(rxe),canEnable:h.boolean().describe("Windows Sandbox can be turned on from here"),error:h.string().nullable().describe("Why the setup could not be read")}).nullable().describe("What sandbox setup found"),log:h.string().nullable().describe("The repair log, if one was written")});function yQ(e){return[e.ok+" ok",e.fixed&&e.fixed+" fixed",e.needsYou&&e.needsYou+" "+(e.needsYou===1?"needs":"need")+" you",e.warn&&e.warn+(e.warn===1?" warning":" warnings"),e.skipped&&e.skipped+" skipped"].filter(Boolean).join(", ")}var nxe={ok:"[ok]",fixed:"[fixed]",warn:"[!]","needs-you":"[x]",skipped:"[-]"},ih={ok:void 0,fixed:"accent",warn:"warn","needs-you":"danger",skipped:"muted"},tz=6;function ixe(e){let t={text:" "+nxe[e.status]+" "+e.name+": "+e.detail+(e.timedOut?" (took too long)":""),...ih[e.status]?{tone:ih[e.status]}:{}};if(e.status==="ok")return[t];let r=[t];e.means&&r.push({text:" What it means: "+e.means}),e.fixable&&e.plan?r.push({text:" Fix: sandbox repair will "+e.plan}):e.fix&&r.push({text:" Fix: "+e.fix});let n=e.lines??[];for(let o of n.slice(0,tz))r.push({text:" "+o});return n.length>tz&&r.push({text:" ... and "+(n.length-tz)+" more"}),r}var vQ={ok:"OK",fixed:"FIXED","needs-you":"NEEDS YOU",warn:"WARNING",skipped:"SKIPPED"};function axe(e,t){return e.length<=t?e:e.slice(0,t-1)+"\u2026"}var _Q=h.object({summary:bQ,changed:h.boolean().describe("Fixes were applied"),log:h.string().nullable().describe("The repair log, if one was written")}),rz=Ge({id:"health.last",title:"Health",summary:"the last check or repair of this PC and the sandbox",input:h.object({}),output:h.object({last:oxe.nullable().describe("Nothing yet: no check has run")}),surfaces:{except:{cli:"the command line prints results as it checks (sandbox doctor)"}}}),Jx=_e({id:"health.check",access:"control",title:"Check this PC",summary:"check this PC, the install, your settings and the sandbox (changes nothing)",input:h.object({harness:h.string().optional().describe("agent to check")}),output:_Q,text:e=>"Summary: "+yQ(e.summary),surfaces:{except:{cli:xQ}}}),eb=_e({id:"health.repair",title:"Run the checks and fix what can be fixed",summary:"find and fix problems (install, data folder, settings, stale state, half-installed tools)",input:h.object({}),output:_Q,danger:!0,text:e=>"Summary: "+yQ(e.summary)+(e.log?". Log: "+e.log:". No log was written (the storage folder does not exist yet)."),surfaces:{except:{cli:xQ}}}),sk=_e({id:"health.enableSandbox",title:"Turn on Windows Sandbox",summary:"turn on the Windows Sandbox feature (Windows asks for admin permission; restart to finish)",input:h.object({}),output:h.object({message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,surfaces:{except:{cli:"sandbox setup asks and turns it on (hand-written: it also offers to restart Windows)",web:"Windows asks for admin permission on this PC; use the menu or sandbox setup"}}});function sxe(e){return e.checks.map((t,r)=>{let n=t.detail+(t.timedOut?" (took too long)":""),o=ixe(t).slice(1).map(a=>a.text.trim()).filter(a=>!a.startsWith("What it means: ")),i=t.status==="ok"?[]:["Found: "+n,...o];return{id:"repair:"+r,label:t.name,hint:vQ[t.status],...ih[t.status]?{tone:ih[t.status]}:{},badges:[{text:vQ[t.status],...ih[t.status]?{tone:ih[t.status]}:{}}],description:t.means??(i.length?void 0:n),...i.length?{details:i}:{}}})}var lxe={ok:"OK",warn:"WARNING",action:"NEEDS YOU"};function cxe(e){let t=e.last,r=le(Jx,{},{verb:"check"}),n=le(eb,{},{verb:"check and fix"});if(!t)return{title:"Health",sections:[{id:"doctor",title:"Doctor",cards:!0,items:[{id:"health:check",label:"Check this PC",description:"Looks at this PC: Windows features, the install, the folders and the sandbox. It takes a few seconds, so it only runs when you ask.",primary:r}]},{id:"repair",title:"Repair",cards:!0,items:[{id:"repair:run",label:"Run the checks and fix what can be fixed",description:"Checks the install, data folder, settings and sandbox, lists what it would change, and asks before it fixes anything.",primary:n}]}]};let o=!!t.setup?.canEnable,i=[{id:"status",summary:(t.mode==="repair"?"Last repair ":"Last check ")+_o(t.at),...t.log?{notes:[{text:"Log: "+t.log,tone:"muted"}]}:{}},{id:"doctor",title:"Doctor",items:t.details.map(([a,s],l)=>({id:"doctor:"+l,label:a,hint:axe(s,50),...s.length>50?{description:s}:{}}))},{id:"repair",title:"Repair",items:sxe(t)}];if(t.setup){let a=t.setup;i.push({id:"setup",title:"Set up this PC",items:a.error?[{id:"setup:error",label:a.error}]:a.checks.map((s,l)=>({id:"setup:"+l,label:s.name,hint:s.detail,tone:s.status==="ok"?"ok":s.status==="warn"?"warn":"danger",badges:[{text:lxe[s.status],tone:s.status==="ok"?"ok":s.status==="warn"?"warn":"danger"}]})),notes:o?[{text:"Turn Windows Sandbox on from the menu or with sandbox setup.",tone:"muted",only:"web"}]:[]})}return{title:"Health",sections:i,actions:[le(eb,{},{key:"f",verb:"check and fix",importance:1}),le(Jx,{},{key:"l",verb:t?"check again":"check",importance:2}),...o?[le(sk,{},{key:"e",verb:"turn on Windows Sandbox",importance:3})]:[]]}}var IQ=lt({id:"health",title:"Health",summary:"Checks this PC and your settings, repairs problems, and sets up Windows Sandbox.",queries:{last:rz},operations:[Jx,eb,sk],build:({last:e})=>cxe(e)});var wQ=["tools","databases","state","logs","data","host"],dxe={tools:"Toolchains",databases:"Databases",state:"Agent state",logs:"Logs",data:"Other",host:"On this PC"},uxe=h.object({area:h.enum(wQ).describe("Which kind of data it is"),name:h.string().describe("The folder as listed (tools: its name; others: area/name)"),path:h.string().describe("Its full path on this PC"),bytes:h.number().describe("Its size in bytes (links count 0)"),size:h.string().describe("Its size in words, e.g. 1.5 KB"),target:h.string().nullable().describe("What sandbox data clean calls it; null when it is kept on purpose")}),fxe=h.object({drive:h.string().describe("The drive, e.g. C:\\"),totalBytes:h.number().describe("Its size in bytes"),freeBytes:h.number().describe("Free bytes"),usedBytes:h.number().describe("Used bytes"),holdsStorage:h.boolean().describe("The sandbox keeps its files on this drive"),used:h.string().describe("Used, in words"),usedPercent:h.number().describe("Used, in percent of the size (rounded)"),free:h.string().describe("Free, in words"),total:h.string().describe("Size, in words")}),mxe=h.object({dataPath:h.string().describe("The data folder (C:\\AgentData inside the sandbox)"),storageRoot:h.string().describe("The storage folder that holds it"),totalBytes:h.number().describe("Everything listed, in bytes"),total:h.string().describe("Everything listed, in words"),storageShare:h.string().describe('"<- sandbox storage (<total> of it)": the note on the storage drive'),areaTotals:h.record(h.string(),h.string()).describe("Each area's total in words"),entries:h.array(uxe).describe("What is stored, by area, biggest first"),disks:h.array(fxe).describe("This PC's drives")}),oz=Ge({id:"data.show",title:"Stored data",summary:"show what is kept between sandboxes (tools, databases, logins, logs), or delete some of it",input:h.object({}),output:mxe,cli:{name:"data",action:"show",json:!0,shapeJson:e=>({dataPath:e.dataPath,storageRoot:e.storageRoot,totalBytes:e.totalBytes,entries:e.entries.map(({area:t,name:r,path:n,bytes:o})=>({area:t,name:r,path:n,bytes:o})),disks:e.disks.map(({drive:t,totalBytes:r,freeBytes:n,usedBytes:o,holdsStorage:i})=>({drive:t,totalBytes:r,freeBytes:n,usedBytes:o,holdsStorage:i}))})}}),SQ=h.object({message:h.string().describe("What happened")}),lk=_e({id:"data.clean",title:"Delete stored data\u2026",summary:"delete chosen parts of what is kept between sandboxes",input:h.object({targets:h.array(h.string()).default([]).describe("what to clean, e.g. tools/go databases logs")}),output:SQ.extend({freedBytes:h.number().describe("Bytes freed (0 when nothing was removed)")}),danger:!0,text:e=>e.message,next:e=>e.freedBytes>0?"sandbox data (see what is left)":void 0,cli:{name:"data",action:"clean",positional:["targets"]}}),kQ=h.object({days:h.number().int().min(1).default(7).describe("launch folders older than this many days")}),ck=_e({id:"data.prune",title:"Clean up\u2026",summary:"delete old launch folders, logs and leftovers",input:kQ,output:SQ.extend({removed:h.boolean().describe("Something was deleted")}),text:e=>e.message,next:e=>e.removed?"sandbox data (see what else is saved, and clean it)":void 0,cli:{name:"clean",group:"Data",flags:{days:{flag:"--days",value:"n"}},yes:"do not ask before deleting"}}),pxe=ns(new ha(kQ).child("days"),["days"]);function hxe(e){let t={id:"disks",title:"Disks",columns:[{key:"drive",label:"DRIVE"},{key:"used",label:"USED"},{key:"free",label:"FREE"},{key:"size",label:"SIZE"},{key:"note",label:""}],columnsOn:"cli",items:e.disks.map(i=>({id:"disk:"+i.drive,label:i.drive,hint:i.used+" used \xB7 "+i.free+" free of "+i.total,...i.holdsStorage?{description:"The sandbox keeps its files on this drive."}:{},cells:{drive:i.drive,used:i.used+" ("+i.usedPercent+"%)",free:i.free,size:i.total,note:i.holdsStorage?e.storageShare:""}})),notes:[{text:"Persistent data for the sandbox: "+e.dataPath+" (C:\\AgentData inside)"}]},r=i=>wQ.indexOf(i),n=[...e.entries].sort((i,a)=>r(i.area)-r(a.area)||a.bytes-i.bytes),o={id:"kept",title:"What the sandbox keeps",summary:e.total+" in all",columns:[{key:"kind",label:"KIND"},{key:"name",label:"NAME"},{key:"size",label:"SIZE"},{key:"folder",label:"FOLDER"}],items:n.map(i=>{let a=i.target?le(lk,{targets:[i.target]},{label:"Delete",key:"x",verb:"delete"}):void 0;return{id:"entry:"+i.name,label:i.name,hint:i.size,cells:{kind:dxe[i.area],name:i.name,size:i.size,folder:i.path},...a?{primary:a}:{}}}),actions:[le(ck,{},{label:"Clean up\u2026",verb:"choose what",description:"Delete caches, old sandboxes and other leftovers (the clean command, with its options).",fields:[pxe]})],notes:[...e.entries.length?[]:[{text:"Nothing stored yet. Toolchains, databases and agent logins appear here after the first start."}],...gxe(e),{text:"Free space with: sandbox data clean <target...> (e.g. tools/go, databases/postgres-18, logs, launches)",tone:"muted",only:"cli"}]};return{title:"Data",sections:[t,o]}}function gxe(e){let t=e.entries.filter(r=>!r.target).map(r=>r.name);return t.length?[{text:"Kept on this PC on purpose, not deleted here: "+t.join(", ")+"."}]:[]}var CQ=lt({id:"data",title:"Data",summary:"What the sandbox keeps between runs, and deleting parts of it.",queries:{data:oz},operations:[lk,ck],build:({data:e})=>hxe(e)});var vxe=h.object({name:h.string().describe("The project"),host:h.string().describe("Its folder on this PC"),guest:h.string().describe("Its folder in the sandbox"),mechanism:h.string().describe("How it got into the sandbox (launch, root, boot, wsb or hcs)"),here:h.boolean().describe("The project of the current folder"),setup:h.object({phase:h.string(),message:h.string()}).describe("How far its setup is"),databases:h.array(h.object({database:h.string(),port:h.number(),state:h.string()})),sessions:h.array(h.object({id:h.string(),harness:h.string(),viewers:h.string(),started:h.string()})),repoGuard:h.array(h.string()).describe("Repo guard findings in its folder")}),xxe=h.object({running:h.boolean().describe("A Windows Sandbox is running"),phase:h.string().describe("What it is doing (ready, provisioning ...)"),message:h.string().optional().describe("Its last message"),headless:h.boolean().optional().describe("Its window is hidden"),startedAt:h.number().nullable().describe("When it started (ms), if known"),daemon:h.string().describe("The sandbox helper's answer"),account:h.string().nullable().describe("The Claude login it uses"),syncWatcher:h.boolean().describe("The background history sync runs")}),bxe=h.object({shared:h.object({line:h.string().describe('"Running, started by alice (shared with you)"'),limited:h.boolean().describe("Not shared with you: nothing more is shown"),startedBy:h.string().nullable().describe("Whose it is")}).optional(),sandbox:xxe,here:h.object({folder:h.string(),project:h.string().nullable(),guest:h.string().nullable()}),roots:h.array(h.object({host:h.string(),guest:h.string()})),projects:h.array(vxe),otherSessions:h.array(h.object({id:h.string(),harness:h.string(),cwd:h.string()})),repoGuard:h.object({guarded:h.number(),findings:h.array(h.string())})}),PQ=h.object({message:h.string().describe("What happened")});function yxe(e){let t=/^pong \((\d+) session/.exec(e);return t?"responding, "+Br(Number(t[1]),"session")+" running":e}function DQ(e){return e.running&&e.startedAt?_o(e.startedAt).replace(" ago",""):null}var nz=Ge({id:"sandbox.status",title:"Sandbox status",summary:"show what the sandbox is doing",input:h.object({}),output:bxe,live:{everyMs:2500},cli:{name:"status",group:"Sessions",json:!0,shapeJson:e=>{if(e.shared?.limited)return{sandbox:{running:!0,shared:!1,startedBy:e.shared.startedBy}};let t=e.sandbox;return{sandbox:{...e.shared?.startedBy?{startedBy:e.shared.startedBy,shared:!0}:{},running:t.running,phase:t.phase,message:t.message,headless:t.headless,uptime:DQ(t),daemon:t.daemon,account:t.account,syncWatcher:t.syncWatcher},here:e.here,roots:e.roots,projects:e.projects,otherSessions:e.otherSessions,repoGuard:e.repoGuard}}}}),dk=_e({id:"sandbox.showWindow",access:"control",title:"Show the window",summary:"show the sandbox window",input:h.object({}),output:PQ,text:e=>e.message,cli:{name:"show",group:"Sessions"}}),uk=_e({id:"sandbox.hideWindow",access:"control",title:"Hide the window",summary:"hide the sandbox window (it keeps running)",input:h.object({}),output:PQ,text:e=>e.message,cli:{name:"hide",group:"Sessions"}}),fk=_e({id:"sandbox.stop",access:"control",title:"Stop the sandbox\u2026",summary:"shut the sandbox down (every project's sessions end)",input:h.object({}),output:h.object({stopped:h.boolean().describe("It was asked to shut down"),message:h.string()}),danger:!0,text:e=>e.message,cli:{name:"stop",group:"Agents",yes:"do not ask when other projects' sessions would end"}}),_xe={launch:"started from here",root:"in a project root",boot:"mapped at start",wsb:"wsb share",hcs:"live folder through HCS, alpha"};function Ixe(e){return{id:"project:"+e.name,label:e.name,icon:"project",hint:e.host+" -> "+e.guest+" ("+(_xe[e.mechanism]??"wsb share")+")",marked:e.here,details:["Setup: "+e.setup.phase+(e.setup.phase==="ready"?"":" - "+e.setup.message),...e.databases.length?["Databases: "+e.databases.map(t=>t.database+" :"+t.port+" "+t.state).join(", ")]:[],...e.sessions.map(t=>"Session: "+t.harness+" "+t.id+", "+t.viewers+", started "+_o(t.started)),...e.repoGuard.map(t=>"Guard: "+t)]}}function wxe(e){let t=e.sandbox,r=e.projects.reduce((o,i)=>o+i.sessions.length,0)+e.otherSessions.length,n=(o,i,a,s={})=>({id:o,label:i,value:a,...s});return[...e.shared?.startedBy?[n("owner","Started by",e.shared.startedBy)]:[],n("state","State",t.running?t.message||t.phase:"not running",{tone:t.running?t.phase==="ready"?"ok":"warn":"muted"}),...t.running?[n("window","Window",t.headless?"hidden (sandbox show opens it)":"shown"),n("uptime","Uptime",DQ(t)??"-"),n("helper","Helper",t.daemon==="-"?"-":yxe(t.daemon)),n("sessions","Sessions",String(r))]:[],n("account","Account",t.account??"none selected (sandbox account use)"),n("sync","Background sync",t.syncWatcher?"on":"off")]}function Sxe(e){let t=e.roots.map(n=>({id:"root:"+n.host,label:"root",icon:"folder",hint:n.host+" -> "+n.guest+" (every project in it opens without a restart)"})),r=e.projects.some(n=>n.here);return{id:"projects",title:"Projects",items:[...e.projects.map(Ixe),...t],notes:[r?{text:"* = the project of this folder",tone:"muted"}:{text:e.here.folder+" is not in this sandbox (start it here: sandbox claude)",tone:"muted"}]}}function kxe(e){let t=e.repoGuard.findings;return{id:"guard",title:"Repo guard",summary:e.repoGuard.guarded+" folder(s) guarded; "+(t.length?t.length+" change(s) neutralised:":"nothing from the sandbox needed neutralising"),items:t.slice(-10).map((r,n)=>({id:"guard:"+n,label:r,tone:"warn"}))}}function Cxe(e){let t=e.shared?{text:e.shared.line+(e.shared.limited?"":". Its window is on their desktop; use its agents here."),tone:"accent"}:void 0;if(e.shared?.limited)return{title:"Sandbox",notice:t,sections:[]};let r=e.sandbox.running,n={id:"status",title:"Status",facts:wxe(e),actions:r?[e.sandbox.headless?le(dk,{},{key:"w",verb:"show",importance:3}):le(uk,{},{key:"h",verb:"hide",importance:3}),le(fk,{},{key:"x",verb:"stop",importance:1})]:[]},o={id:"other-sessions",title:"Other sessions",items:e.otherSessions.map(i=>({id:"session:"+i.id,label:"session "+i.id,hint:i.harness+" "+i.cwd}))};return{title:"Sandbox",notice:t,sections:[n,...r?[Sxe(e)]:[],...o.items?.length?[o]:[],kxe(e)]}}var RQ=lt({id:"sandbox",title:"Sandbox",summary:"What the sandbox is doing, its window, and stopping it.",queries:{status:nz},operations:[dk,uk,fk],build:({status:e})=>Cxe(e)});var Pxe=h.object({folder:h.string().describe("The project folder on this PC"),here:h.boolean().describe("The folder you are in is inside it"),known:h.boolean().describe("Started with this tool before"),root:h.string().nullable().describe("The project root it is in, if any"),excluded:h.boolean().describe("Excluded from the projects mapped at every start"),mappedAtStart:h.boolean().describe("Mapped at every start"),running:h.string().nullable().describe("Its name and how it got into the running sandbox, if it is there")}),Dxe=h.object({all:h.boolean().describe("Every project is mapped at every start (except excluded ones)"),roots:h.array(h.string()).describe("Folders of projects, each opened without a restart"),exclude:h.array(h.string()).describe("Folders left out of the projects mapped at every start"),projects:h.array(Pxe).describe("Every project worth listing")}),ah=h.object({message:h.string().describe("What happened")}),mk=e=>h.string().optional().describe(e+" (. = this folder; asked when left out)"),iz=Ge({id:"projects.list",title:"Projects",summary:"list your projects, roots and the all-projects setting",input:h.object({}),output:Dxe,cli:{name:"projects",action:"list",json:!0}}),pk=_e({id:"projects.choose",title:"Choose the projects mapped at every start\u2026",summary:"tick the projects mapped at every start; the rest are excluded",input:h.object({}),output:ah,text:e=>e.message,cli:{name:"projects",action:"choose"}}),tb=_e({id:"projects.add",title:"Add a project\u2026",summary:"remember a project folder",input:h.object({projectFolder:mk("The project folder")}),output:h.object({message:h.string().describe("What happened"),next:h.string().optional().describe("What to do next, when mapping all projects is off")}),text:e=>e.next?e.message+`
|
|
128
128
|
`+e.next:e.message,cli:{name:"projects",action:"add",positional:["projectFolder"]}}),hk=_e({id:"projects.remove",title:"Forget project",summary:"forget a project (nothing in the folder is touched)",input:h.object({projectFolder:mk("The project folder")}),output:ah,danger:!0,text:e=>e.message,cli:{name:"projects",action:"remove",positional:["projectFolder"]}}),gk=_e({id:"projects.include",title:"Include",summary:"map a project at every start again",input:h.object({projectFolder:mk("The project folder")}),output:ah,text:e=>e.message,cli:{name:"projects",action:"include",positional:["projectFolder"]}}),vk=_e({id:"projects.exclude",title:"Exclude",summary:"leave a project out of the projects mapped at every start",input:h.object({projectFolder:mk("The project folder")}),output:ah,text:e=>e.message,cli:{name:"projects",action:"exclude",positional:["projectFolder"]}}),xk=_e({id:"projects.all",title:"Map all projects at every start",summary:"map every project at every start, or not",input:h.object({state:h.enum(["on","off"]).optional().describe("on or off (left out: say which it is)")}),output:ah,text:e=>e.message,cli:{name:"projects",action:"all",positional:["state"]}}),Zu=_e({id:"projects.roots",title:"Project roots",summary:"list, add or remove project roots",input:h.object({change:h.enum(["list","add","remove"]).default("list").describe("list, add or remove"),rootFolder:h.string().optional().describe("(add, remove) the folder that holds your projects")}),output:ah,text:e=>e.message,cli:{name:"projects",action:"roots",positional:["change","rootFolder"]}}),TQ=M1(Zu.input).find(e=>e.name==="rootFolder"),Rxe=M1(tb.input).find(e=>e.name==="projectFolder"),Txe="Every project in this folder (also new ones) opens without a restart.";function EQ(e){return e.root?"root":e.excluded?"excluded":e.mappedAtStart?"mapped":"-"}function Exe(e){return{id:"project:"+e.folder,label:e.folder,marked:e.here,icon:"project",hint:e.running??(e.root?"in a root":e.excluded?"excluded":e.mappedAtStart?"mapped":"-"),description:e.here?"This is the folder you started the menu in.":void 0,details:["At start: "+EQ(e),"In the sandbox: "+(e.running??"not open")],cells:{here:e.here?"*":"",folder:e.folder,atStart:EQ(e),running:e.running??"-"},actions:[le(hk,{projectFolder:e.folder},{key:"f",verb:"forget project",importance:1}),e.excluded?le(gk,{projectFolder:e.folder}):le(vk,{projectFolder:e.folder})]}}function $xe(e){return{id:"root:"+e,label:e,hint:"root",icon:"folder",description:Txe,keys:"f removes the root.",actions:[le(Zu,{change:"remove",rootFolder:e},{label:"Remove the root",key:"f",verb:"remove root",importance:1})]}}function Axe(e){let t={id:"settings",facts:[{id:"all",label:"All projects",value:e.all?"on (every project below is mapped at every start, except excluded ones)":"off"},{id:"roots",label:"Roots",value:e.roots.length?e.roots.join(", "):"none (sandbox projects roots add <folder>)"}],actions:[le(xk,{state:e.all?"off":"on"},{label:e.all?"Stop mapping all projects":"Map all projects at every start"})],notes:[{text:"sandbox projects all on|off",tone:"muted",only:"cli"}]},r={id:"roots",title:"Project roots",items:[{id:"@add-root",label:"+ Add a project root\u2026",description:"Pick a folder that holds your projects: every project in it (also new ones) opens without a restart.",primary:le(Zu,{change:"add"},{label:"Choose the folder\u2026",verb:"choose folder",fields:[TQ]})},...e.roots.map($xe)]},n={id:"projects",title:"Projects",columns:[{key:"here",label:""},{key:"folder",label:"FOLDER"},{key:"atStart",label:"AT START"},{key:"running",label:"RUNNING SANDBOX"}],columnsOn:"cli",items:e.projects.map(Exe),notes:e.projects.length===0?[{text:"No projects yet: start one with sandbox claude in its folder.",tone:"muted"}]:[{text:"* = this folder. Choose with: sandbox projects choose",tone:"muted",only:"cli"}]};return{title:"Projects",sections:[t,r,n],actions:[le(pk,{},{label:"Choose\u2026"}),le(tb,{},{fields:[Rxe]}),le(Zu,{change:"add"},{label:"Add a project root\u2026",key:"a",verb:"add root",importance:1,fields:[TQ]})]}}var $Q=lt({id:"projects",title:"Projects",summary:"The projects a sandbox opens without a restart: roots, your projects, all or chosen.",queries:{projects:iz},operations:[pk,tb,hk,gk,vk,xk,Zu],build:({projects:e})=>Axe(e)});var bk="@crash",Oxe=1e3,OQ="sandbox logs is hand-written: --follow prints new lines until Ctrl+C; it reads this same query (readQuery)",zxe=h.object({name:h.string().describe("The log file"),path:h.string().describe("Where it is on this PC"),bytes:h.number().describe("Its size in bytes"),modified:h.number().describe("When it was last written (ms)")}),Nxe=h.object({folder:h.string().describe("The folder the logs are in"),files:h.array(zxe).describe("The log files, newest first"),crash:h.boolean().describe("A crash report exists")}),Fxe=h.object({name:h.string().describe("The log shown, or @crash for the last crash report (empty: there are no logs)"),file:h.string().describe("Its full path (empty: there are no logs)"),text:h.string().describe("The text read, made safe for a terminal"),next:h.number().describe("Where to read on from next time (bytes)")}),az=Ge({id:"logs.list",title:"Logs",summary:"list the sandbox's own logs",input:h.object({}),output:Nxe,surfaces:{except:{cli:OQ}}}),sz=Ge({id:"logs.tail",title:"Log",summary:"the end of one log, followed as it grows",input:h.object({name:h.string().max(200).optional().describe("The log to show (default: the newest), or @crash for the last crash report"),from:h.number().int().min(0).default(0).describe("Read on from this byte (0: the end of the log)"),lines:h.number().int().min(1).max(1e3).default(120).describe("How many lines of the end to show")}),output:Fxe,live:{everyMs:1e3},surfaces:{except:{cli:OQ}}}),AQ={text:"showing",tone:"accent"};function Lxe(e){let t=e.split(`
|
|
129
129
|
`);return t.length&&t[t.length-1]===""&&t.pop(),t.slice(-Oxe)}function Mxe(e,t){let r=t?.file?t:void 0,n=e.files.map(i=>({id:"log:"+i.name,label:i.name,hint:Wu(i.bytes)+" "+_o(i.modified),keys:"Enter shows the end of this log in the terminal.",primary:An({kind:"view",view:"logs",params:{name:i.name}},"Show",{verb:"show"}),...r?.name===i.name?{badges:[AQ]}:{}}));e.crash&&n.push({id:"log:"+bk,label:"Last crash report",description:"What Windows logged, this PC and the sandbox memory when the sandbox last ended in a crash.",primary:An({kind:"view",view:"logs",params:{name:bk}},"Show",{verb:"show"}),...r?.name===bk?{badges:[AQ]}:{}});let o=r?[{id:"tail",title:r.name===bk?"Last crash report":r.name,summary:r.file,text:Lxe(r.text)}]:[];return{title:"Logs",sections:[{id:"files",items:n},...o],actions:[An({kind:"command",argv:["logs","--follow"]},"Follow the newest log",{key:"f",verb:"follow in the terminal",importance:2})],empty:{title:"No logs yet",text:"Logs appear after the first start.",cliText:"No sandbox logs yet."}}}var zQ=lt({id:"logs",title:"Logs",summary:"The sandbox's own logs: pick one to see its end as it grows.",queries:{files:az,tail:sz},operations:[],params:["name"],inputs:e=>({tail:e.name?{name:e.name}:{}}),build:({files:e,tail:t})=>Mxe(e,t)});var Bxe=["proc","file","commit","session","guard","note","remote"],uz=["all","proc","file","commit","session","guard","remote"],NQ=[1,3,7,14,30],yk="none",jxe=240,Uxe={proc:"command",file:"file",commit:"commit",session:"session",guard:"GUARD",note:"note",remote:"remote"},Vxe=h.object({time:h.string().describe("When it happened (ISO time)"),kind:h.enum(Bxe).describe("proc: a program started; file: changed in a project; commit; session; guard: the repo guard; note; remote: what another Windows user or a paired device did in the web UI"),what:h.string().describe("The program, the file, the commit message, the agent, or what happened"),command:h.string().optional().describe("A program's command line (secrets hidden)"),parent:h.string().optional().describe("The program that started it"),action:h.string().optional().describe("file: change or rename; session: start or end; commit: commit, amend, merge, cherry-pick ..."),folder:h.string().optional().describe("The project folder on this PC"),project:h.string().optional().describe("The project"),session:h.string().optional().describe("The agent session it belongs to (missing: not known)"),agent:h.string().optional().describe("That session's agent"),linked:h.enum(["process","only-session"]).optional().describe("How it was linked: process = by the programs the session started; only-session = the only session running in that project then (likely, not proven)"),count:h.number().int().describe("How many times it happened in that minute"),sha:h.string().optional().describe("A commit's id"),author:h.string().optional().describe("A commit's author; for remote: who did it")}),_k=h.object({commands:h.number().int().describe("Programs started"),files:h.number().int().describe("Files changed (each file once)"),commits:h.number().int().describe("Commits")}),Hxe=_k.extend({id:h.string().describe("The session"),agent:h.string().describe("Its agent"),project:h.string().describe("Its project"),started:h.string().describe("Its first event (ISO time)"),ended:h.string().optional().describe("When it ended, if that was recorded"),last:h.string().optional().describe("The last command it ran")}),Wxe=_k.extend({agent:h.string().describe("The agent"),sessions:h.number().int().describe("Its sessions")}),Zxe=h.object({enabled:h.boolean().describe("The audit log is on (audit.enabled)"),keepDays:h.number().int().describe("Days it is kept (audit.days)"),maxMb:h.number().int().describe("Most space it may take (audit.maxMb)"),bytes:h.number().describe("Space it takes now"),folder:h.string().describe("Where it is on this PC"),filter:h.object({days:h.number().int(),kind:h.enum(uz),session:h.string().optional(),agent:h.string().optional(),project:h.string().optional(),grep:h.string().optional()}),matched:h.number().int(),events:h.array(Vxe).describe("The events, newest first"),totals:_k.extend({events:h.number().int(),sessions:h.number().int()}),agents:h.array(Wxe),sessions:h.array(Hxe).describe("The sessions in the period, newest first"),unlinked:_k}),fz=Ge({id:"audit.list",title:"Activity",summary:"what your agents did: programs started, files changed, commits, sessions, repo guard",input:h.object({days:h.number().int().min(1).max(30).default(1).describe("the last n days (1: the last 24 hours)"),kind:h.enum(uz).default("all").describe("only proc, file, commit, session or guard events"),session:h.string().max(64).optional().describe("only the events of this session (its id or the start of it; none: not linked to a session)"),agent:h.string().max(64).optional().describe("only this agent's events"),project:h.string().max(128).optional().describe("only this project's events"),grep:h.string().max(200).optional().describe("only events containing this text"),limit:h.number().int().min(1).max(5e3).default(300).describe("show at most this many events (the newest)")}),output:Zxe,live:{everyMs:15e3},cli:{name:"audit",group:"Health",json:!0,flags:{days:{flag:"--days",value:"n"},kind:{flag:"--kind",value:"kind"},session:{flag:"--session",value:"id"},agent:{flag:"--agent",value:"name"},project:{flag:"--project",value:"name"},grep:{flag:"--grep",value:"text"},limit:{flag:"--limit",value:"n",advanced:!0}},shapeJson:e=>[...e.events].reverse(),examples:["sandbox audit --days 7 --kind commit",'sandbox audit --session 4f2c --grep "git push"']}});function cz(e,t=Date.now()){let r=new Date(e);if(Number.isNaN(r.getTime()))return e;let n=a=>String(a).padStart(2,"0");return new Date(t).toDateString()===r.toDateString()?n(r.getHours())+":"+n(r.getMinutes())+":"+n(r.getSeconds()):["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][r.getMonth()]+" "+r.getDate()+" "+n(r.getHours())+":"+n(r.getMinutes())}function LQ(e){return e.slice(0,8)}function Gxe(e){switch(e.kind){case"proc":return e.command||e.what;case"file":return(e.action==="rename"?"added/removed ":"changed ")+e.what;case"commit":return(e.sha?e.sha.slice(0,7)+" ":"")+e.what+(e.action&&e.action!=="commit"?" ("+e.action+")":"");case"session":return e.what+(e.action==="end"?" ended":" started")+(e.project?" in "+e.project:"");case"remote":return(e.author??"someone")+": "+e.what+(e.action&&e.action!=="ok"?" ("+e.action+")":"");default:return e.what}}function FQ(e){return e.agent?e.agent+(e.linked==="only-session"?"?":""):"-"}function dz(e,t=jxe){return e.length>t?e.slice(0,t-1)+"\u2026":e}function Kxe(e,t){let r=Gxe(e)+(e.count>1?" \xD7"+e.count:""),n=[...e.session?["Session "+e.session+(e.linked==="only-session"?" (likely)":"")]:[],...e.project?["Project "+e.project]:[],...e.kind==="proc"&&e.command&&e.what!==e.command?["Program "+e.what]:[],...e.parent?["Started by "+e.parent]:[],...e.author?["Author "+e.author]:[],...e.sha?["Commit "+e.sha]:[],...e.folder&&e.kind!=="session"?["Folder "+e.folder]:[]];return{id:"event:"+t,label:dz(r),hint:cz(e.time)+" "+FQ(e),tone:e.kind==="guard"?"warn":void 0,details:n,keywords:[e.session,e.project,e.agent,e.kind,e.author].filter(Boolean).join(" "),cells:{time:cz(e.time),agent:FQ(e),kind:Uxe[e.kind],what:dz(r)}}}function mz(e,t){return{days:String(e.filter.days),kind:e.filter.kind,...t}}function MQ(e){return Br(e.commands,"command")+", "+Br(e.files,"file")+", "+Br(e.commits,"commit")}function qxe(e,t){return{id:"session:"+t.id,label:t.agent+" "+t.project,icon:t.agent,hint:"started "+_o(t.started)+(t.ended?", ended "+_o(t.ended):""),badges:[...t.commits?[{text:Br(t.commits,"commit"),tone:"accent"}]:[],...t.ended?[{text:"ended",tone:"muted"}]:[]],details:["Did "+MQ(t),...t.last?["Last "+dz(t.last,120)]:[],"Session "+t.id],keywords:t.id,cells:{session:LQ(t.id),agent:t.agent,project:t.project,started:cz(t.started),commands:String(t.commands),files:String(t.files),commits:String(t.commits)},primary:An({kind:"view",view:"audit",params:mz(e,{session:t.id})},"Show",{verb:"show",description:"Only what this session did."})}}function Xxe(e){let t=e.unlinked;return{id:"session:"+yk,label:"Not linked to a session",icon:"session",description:"What the sandbox ran itself (setup, services), and changes made while no session or several ran in that project.",details:["Did "+MQ(t)],cells:{session:yk,agent:"-",project:"-",started:"",commands:String(t.commands),files:String(t.files),commits:String(t.commits)},primary:An({kind:"view",view:"audit",params:mz(e,{session:yk})},"Show",{verb:"show",description:"Only what no session can be linked to."})}}function lz(e){let t=e.filter,r=t.session?e.sessions.find(n=>n.id===t.session):void 0;return[t.session===yk?"not linked to a session":t.session?"session "+LQ(t.session)+(r?" ("+r.agent+", "+r.project+")":""):"",t.agent?"agent "+t.agent:"",t.project?"project "+t.project:"",t.grep?'containing "'+t.grep+'"':""].filter(Boolean).join(", ")}function Qxe(e,t,r){return t.length?[{id:"sessions",title:"Sessions",summary:Br(e.sessions.length,"session")+" "+r,cards:!0,columnsOn:"cli",columns:[{key:"session",label:"SESSION"},{key:"agent",label:"AGENT"},{key:"project",label:"PROJECT"},{key:"started",label:"STARTED"},{key:"commands",label:"COMMANDS"},{key:"files",label:"FILES"},{key:"commits",label:"COMMITS"}],items:t,notes:[{text:"Only one session: sandbox audit --session <id>",tone:"muted",only:"cli"}]}]:[]}function Yxe(e){let t=e.filter,r=t.days===1?"in the last 24 hours":"in the last "+t.days+" days",n=!!(t.session||t.agent||t.project||t.grep),o=An({kind:"view",view:"audit",params:mz(e,{})},"Show everything",{verb:"show"}),i=le(Qn,{key:"audit.enabled",value:!0},{label:"Turn the audit log on",verb:"start",key:"o",importance:1}),a=e.totals,s=a.events?[{id:"events",label:"Events",value:String(a.events)},{id:"commands",label:"Commands",value:String(a.commands)},{id:"files",label:"Files changed",value:String(a.files)},{id:"commits",label:"Commits",value:String(a.commits),...a.commits?{tone:"accent"}:{}},{id:"sessions",label:"Sessions",value:String(a.sessions)}]:[],l=t.session||e.agents.length<1?[]:e.agents.map(p=>({id:"agent:"+p.agent,label:p.agent,value:Br(p.commands,"command"),details:[Br(p.files,"file")+", "+Br(p.commits,"commit"),Br(p.sessions,"session")]})),c={text:"The log takes "+Wu(e.bytes)+" of "+e.maxMb+" MB and keeps "+Br(e.keepDays,"day")+", on this PC where the sandbox cannot reach it ("+e.folder+").",tone:"muted"},d=t.session!==void 0?[]:[...e.sessions.map(p=>qxe(e,p)),...e.unlinked.commands||e.unlinked.files||e.unlinked.commits?[Xxe(e)]:[]],u=e.events.map(Kxe),f=e.events.some(p=>p.linked==="only-session"),m=[...n?[{id:"filter",title:"Filtered",summary:lz(e),actions:[o]}]:[],{id:"summary",facts:s},...l.length?[{id:"agents",title:"By agent",facts:l}]:[],...Qxe(e,d,r),{id:"events",title:"Events",summary:e.matched>u.length?"the newest "+u.length+" of "+e.matched:Br(e.matched,"event")+" "+r,columns:[{key:"time",label:"TIME"},{key:"agent",label:"AGENT"},{key:"kind",label:"KIND"},{key:"what",label:"WHAT"}],items:u,notes:[c,...f?[{text:"? = the only session running in that project then (likely, not proven)",tone:"muted"}]:[],...e.matched>u.length?[{text:"More: sandbox audit --limit <n>, or narrow it down.",tone:"muted",only:"cli"}]:[]]}];return{title:"Activity",...e.enabled?{}:{notice:{text:"The audit log is off: nothing new is recorded.",tone:"warn"}},sections:m,actions:e.enabled?[]:[i],empty:{title:n?"Nothing matches":e.enabled?"Nothing recorded "+r:"The audit log is off",text:n?"No events "+r+" for "+lz(e)+".":e.enabled?"What your agents run, change and commit appears here while a sandbox runs.":"Turn it on to keep a record of what your agents run, change and commit (kept "+Br(e.keepDays,"day")+" on this PC).",action:n?o:e.enabled?void 0:i,cliText:e.enabled?"Nothing in the audit log "+r+(n?" for "+lz(e):"")+".":"The audit log is off. Turn it on in the menu (Settings > Security & privacy > Audit log) or with: sandbox config set audit.enabled true"}}}var BQ=lt({id:"audit",title:"Activity",summary:"What your agents ran, changed and committed, from the audit log on this PC.",queries:{audit:fz},operations:[Qn],filters:[{param:"kind",label:"Kind",choices:[{value:"all",label:"Everything"},{value:"proc",label:"Commands"},{value:"file",label:"Files"},{value:"commit",label:"Commits"},{value:"session",label:"Sessions"},{value:"guard",label:"Repo guard"}]},{param:"days",label:"Period",choices:NQ.map(e=>({value:String(e),label:e===1?"24 hours":e+" days"}))}],params:["session","agent","project","grep"],inputs:e=>({audit:{days:NQ.find(t=>String(t)===e.days)??1,kind:uz.find(t=>t===e.kind)??"all",...e.session?{session:e.session}:{},...e.agent?{agent:e.agent}:{},...e.project?{project:e.project}:{},...e.grep?{grep:e.grep}:{}}}),build:({audit:e})=>Yxe(e)});var Jxe=h.object({viewers:h.number(),remote:h.number()}),ebe=h.object({id:h.string().describe("The session"),launchId:h.string(),harness:h.string().describe("The agent, or the shell (pwsh, powershell, cmd)"),kind:h.enum(["agent","shell"]).optional(),cwd:h.string().describe("Its folder in the sandbox"),project:h.string().optional(),phase:h.enum(["starting","running","exited","failed"]).describe("What it is doing"),message:h.string(),updatedAt:h.string(),startedAt:h.string().describe("When it started"),conversation:h.string().optional(),exitCode:h.number().optional(),projectName:h.string().optional().describe("The project it runs in"),here:h.boolean().optional().describe("In the project of the current folder"),viewers:Jxe.nullable().optional(),canOpen:h.boolean()}),tbe=h.object({sandboxRunning:h.boolean(),defaultAgent:h.string(),wide:h.boolean(),owner:h.string().optional(),sessions:h.array(ebe)});function jQ(e){return e===void 0?"-":e===null?"unknown (older session)":e.remote+" here, "+(e.viewers-e.remote)+" in sandbox"}function rbe(e){let t=(r,n)=>r.startedAt<n.startedAt?1:-1;return[...e.filter(r=>r.here).sort(t),...e.filter(r=>!r.here).sort(t)]}var pz=Ge({id:"sessions.list",title:"Sessions",summary:"list sessions (agents and shells) and who is attached",input:h.object({wide:h.boolean().default(!1).describe("also show each session's folder")}),output:tbe,live:{everyMs:2500},cli:{name:"sessions",group:"Sessions",json:!0,flags:{wide:{flag:"--wide",noMenu:!0}},shapeJson:e=>e.sessions.map(({canOpen:t,...r})=>r)}}),Ik=_e({id:"sessions.restart",access:"control",title:"Restart agents",summary:"restart this project's running agents in place; they resume their conversation",input:h.object({harness:h.string().optional().describe("only this agent"),all:h.boolean().default(!1).describe("every project's sessions, not only this folder's")}),output:h.object({message:h.string().describe("The sandbox's answer")}),text:e=>e.message,cli:{name:"restart",group:"Agents",flags:{harness:{flag:"--harness",shownAs:"--agent",value:"name",choices:"harnesses"},all:{flag:"--all"}}}}),obe=h.string().regex(/^[A-Za-z0-9_.-]{1,64}$/),nbe=h.string().regex(/^[A-Za-z0-9_-]{1,64}$/),ibe=["auto","pwsh","powershell","cmd"];function abe(e){return{kind:"terminal",session:e.session}}var wk=_e({id:"sessions.shell",title:"New shell",summary:"open PowerShell or cmd in a project of the running sandbox, as a session you can attach to",input:h.object({project:obe.optional().describe("The project of the running sandbox (default: this folder's, else asked)"),shell:h.enum(ibe).default("auto").describe("The shell: pwsh, powershell or cmd (default: pwsh if present)")}),output:h.object({session:h.string().describe("The new session"),shell:h.string().describe("The shell it runs"),message:h.string().describe("What happened")}),access:"owner",text:e=>e.message,opens:abe,cli:{name:"shell",group:"Sessions",positional:["project"],flags:{shell:{flag:"--shell",value:"name",choices:["pwsh","powershell","cmd"]}},json:!0,examples:["sandbox shell PowerShell in this folder's project, in this terminal (Ctrl+] detaches)","sandbox shell api --shell cmd cmd in the project api"]}}),Sk=_e({id:"sessions.close",title:"Close",summary:"end a running session (an agent or a shell) and every program it started",input:h.object({session:nbe.describe("The session to close")}),output:h.object({message:h.string().describe("The sandbox's answer")}),access:"control",danger:!0,text:e=>e.message,cli:{name:"close",group:"Sessions",positional:["session"],examples:["sandbox close 4f2c9a"]}});function sbe(e,t){let r=e.phase+(e.exitCode!==void 0?" ("+e.exitCode+")":""),n=e.phase==="running";return{id:e.id,label:(e.kind==="shell"?e.harness+" (shell)":e.harness)+" "+(e.projectName??"-"),hint:r+" "+_o(e.startedAt),badges:[{text:e.phase,tone:n?"ok":e.phase==="failed"?"danger":"muted"}],group:e.here?"This folder's project":"Other sessions",marked:e.here,icon:e.harness,description:n?"Opens this session's terminal (in a terminal, Ctrl+] detaches; the session keeps running). x closes it.":void 0,details:["Session "+e.id,"Folder "+e.cwd,"Attached "+jQ(e.viewers)],cells:{here:e.here?"*":"",id:e.id,agent:e.harness,project:e.projectName??"-",state:r,attached:jQ(e.viewers),...t?{folder:e.cwd}:{},started:_o(e.startedAt)},...n&&e.canOpen?{primary:An({kind:"terminal",session:e.id},"Open",{verb:"attach"})}:{},...n?{actions:[le(Sk,{session:e.id},{key:"x",verb:"close",importance:1})]}:{},...n?{}:{disabled:"This session has ended."},...n&&!e.canOpen?{disabled:"Not reachable from this PC."}:{}}}function lbe(e){let t=rbe(e.sessions),r=e.defaultAgent,n=An({kind:"start-agent",agent:r},"Start "+r,{verb:"start"}),o=t.length&&!t.some(i=>i.phase==="running"||i.phase==="starting")?[{id:"start",actions:[{...n,description:"Starts "+r+" in this folder."}]}]:[];return{title:"Sessions",...e.owner?{notice:{text:e.owner,tone:"accent"}}:{},sections:[{id:"sessions",cards:!0,columns:[{key:"here",label:""},{key:"id",label:"ID"},{key:"agent",label:"AGENT"},{key:"project",label:"PROJECT"},{key:"state",label:"STATE"},{key:"attached",label:"ATTACHED"},...e.wide?[{key:"folder",label:"FOLDER"}]:[],{key:"started",label:"STARTED"}],items:t.map(i=>sbe(i,e.wide)),notes:[...t.some(i=>i.here)?[{text:"* = the project of this folder",tone:"muted"}]:[],...e.wide?[]:[{text:"Folders: sandbox sessions --wide",tone:"muted",only:"cli"}]]},...o],actions:[...e.sandboxRunning?[{...n,label:"New session",key:"n",verb:"new session",importance:1}]:[],...e.sandboxRunning?[le(wk,{shell:"auto"},{key:"s",verb:"new shell",importance:1,description:"Opens PowerShell in a project of the sandbox, as a session like the agents."})]:[],...t.length?[le(Ik,{all:!1},{key:"r",verb:"restart agents",importance:1})]:[],An({kind:"command",argv:["resume"]},"Reopen last sessions",{key:"o",verb:"reopen last sessions",importance:2})],empty:{title:e.sandboxRunning?"No sessions":"No sandbox is running",text:e.sandboxRunning?"No agent is running. Start "+r+" in this folder.":"Starting "+r+" starts the sandbox too; its session is listed here.",action:n,cliText:"No sessions. Start one with: sandbox claude"}}}var UQ=lt({id:"sessions",title:"Sessions",summary:"The sessions of the running sandbox: open one, restart the agents, open a shell, close one.",queries:{sessions:pz},operations:[Ik,wk,Sk],build:({sessions:e})=>lbe(e)});var cbe=h.enum(["nordvpn","openvpn-file","wireguard-file"]).describe("Which VPN (setting vpn.provider)"),dbe=h.enum(["none","saved","unreadable"]).describe("Whether a login is saved and can be opened by you"),ube=["The VPN is an alpha: a tunnel carrying traffic is not confirmed yet (docs/vpn.md lists what still needs checking).","The agent in the sandbox can read the VPN login (a service login you can revoke) and can turn the tunnel off, because it is the administrator there.","Free VPNs see all your traffic: use one you trust."];var fbe=h.object({enabled:h.boolean().describe("The VPN is on (setting vpn.enabled)"),provider:cbe,protocol:h.enum(["udp","tcp"]).describe("udp or tcp (setting vpn.protocol)"),country:h.string().describe("The NordVPN country; empty = the best server anywhere"),killSwitch:h.boolean().describe("No internet when the tunnel fails (setting vpn.killSwitch)"),login:dbe,loginSavedAt:h.string().nullable().describe("When the login was saved (the date and time, never the login)"),running:h.object({level:h.enum(["ok","warn","bad"]).describe("How the tunnel is doing"),text:h.string().describe("What the sandbox reported")}).nullable().describe("The running sandbox's tunnel, when one runs with the VPN on")}),hz=Ge({id:"vpn.status",title:"VPN",summary:"the VPN settings, whether a login is saved, and the running tunnel",input:h.object({tunnel:h.boolean().default(!0).describe("also ask the running sandbox how its tunnel is doing (one request to api.ipify.org)")}),output:fbe,cli:{name:"vpn",action:"status",json:!0}}),kk=_e({id:"vpn.login",title:"Save the VPN login\u2026",summary:"save the VPN login (typed hidden, kept encrypted, never printed)",input:h.object({}).strict(),output:h.object({message:h.string().describe("What happened")}),text:e=>e.message,cli:{name:"vpn",action:"login"}}),Ck=_e({id:"vpn.logout",title:"Delete the VPN login",summary:"delete the saved VPN login",input:h.object({}).strict(),output:h.object({deleted:h.boolean().describe("A login was saved and is gone"),message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,cli:{name:"vpn",action:"logout"}}),mbe={nordvpn:"NordVPN","wireguard-file":"your own WireGuard .conf","openvpn-file":"your own .ovpn file"},pbe={none:"not saved",saved:"saved (encrypted)",unreadable:"cannot be read"},hbe={none:"warn",saved:"ok",unreadable:"danger"},gbe={ok:"ok",warn:"warn",bad:"danger"};function vbe(e){let t=e.provider==="wireguard-file",r=e.loginSavedAt?" "+e.loginSavedAt.slice(0,10):"",n=[e.enabled?{id:"vpn",label:"VPN",value:"on",tone:"ok"}:{id:"vpn",label:"VPN",value:"off (applies from the next start)",tone:"muted"},{id:"provider",label:"Provider",value:mbe[e.provider]},{id:"protocol",label:"Protocol",value:e.protocol},{id:"country",label:"Country",value:e.country||"best available"},e.killSwitch?{id:"killSwitch",label:"Kill switch",value:"on (no internet if the tunnel fails)"}:{id:"killSwitch",label:"Kill switch",value:"off",tone:"warn"},t?{id:"login",label:"Login",value:"not needed (the keys are in your config)",tone:"muted"}:{id:"login",label:"Login",value:pbe[e.login]+r,tone:hbe[e.login]},...e.running?[{id:"running",label:"Running now",value:e.running.text,tone:gbe[e.running.level]}]:[]],o=[...!t&&e.login==="none"?[{text:"Next: sandbox vpn login",tone:"muted",only:"cli"}]:[],...e.login==="unreadable"?[{text:"Only the Windows user that saved it can read it. Save it again: sandbox vpn login",tone:"muted"}]:[],...ube.map(l=>({text:l,tone:"warn"}))],a=[le(Qn,{scope:"user",key:"vpn.enabled",value:!e.enabled},{label:e.enabled?"Turn the VPN off":"Turn the VPN on",verb:e.enabled?"turn off":"turn on",key:"o"}),...t?[]:[le(kk,{},{key:"v",verb:"save login"}),...e.login!=="none"?[le(Ck,{},{key:"x",verb:"delete login"})]:[]]];return{title:"VPN",sections:[{id:"vpn",facts:n,notes:o,actions:a}]}}var VQ=lt({id:"vpn",title:"VPN",summary:"The sandbox's VPN: whether it is on, the saved login, and the tunnel.",queries:{status:hz},operations:[kk,Ck,Qn],build:({status:e})=>vbe(e)});var xbe="https://github.com/settings/personal-access-tokens/new",Iht=["Open "+xbe+" (a fine-grained personal access token).",'Under "Repository access" choose "Only select repositories" and pick only the ones the agent should reach.',"Give only the permissions it needs, for example Contents (read and write), Pull requests (read and write) and Actions (read).","Set an expiry date, then generate the token and copy it."],bbe=["The agent in the sandbox can read the token and use it for everything it allows: limit it to some repositories and permissions.",'It is handed over only with github.shareToken on and git access "full". Revoke it on GitHub whenever you like.'],ybe=h.enum(["none","saved","unreadable"]).describe("Whether a token is saved and can be opened by you"),_be=h.object({shareToken:h.boolean().describe("Sandboxes get the token (setting github.shareToken)"),gitAccess:h.enum(["full","readonly","none"]).describe("Git access in your settings (provisioning.git.access)"),token:ybe,kind:h.enum(["fine-grained","classic"]).nullable().describe("What kind of token is saved (never the token)"),savedAt:h.string().nullable().describe("When the token was saved (the date and time, never the token)")}),gz=Ge({id:"github.status",title:"GitHub",summary:"whether sandboxes get your GitHub token, and whether one is saved (never the token)",input:h.object({}).strict(),output:_be,cli:{name:"github",action:"status",json:!0}}),Pk=_e({id:"github.login",title:"Save the GitHub token\u2026",summary:"save a GitHub token for sandboxes (typed hidden, kept encrypted, never printed)",input:h.object({}).strict(),output:h.object({message:h.string().describe("What happened")}),text:e=>e.message,cli:{name:"github",action:"login"}}),Dk=_e({id:"github.logout",title:"Delete the GitHub token",summary:"delete the saved GitHub token",input:h.object({}).strict(),output:h.object({deleted:h.boolean().describe("A token was saved and is gone"),message:h.string().describe("What happened")}),danger:!0,text:e=>e.message,cli:{name:"github",action:"logout"}}),Ibe={none:"not saved",saved:"saved (encrypted)",unreadable:"cannot be read"},wbe={none:"warn",saved:"ok",unreadable:"danger"},Sbe={"fine-grained":"fine-grained",classic:"classic (reaches every repository you can: a fine-grained token is safer)"};function kbe(e){let t=e.savedAt?" "+e.savedAt.slice(0,10):"",r=[e.shareToken?{id:"share",label:"Share with sandboxes",value:"on",tone:"ok"}:{id:"share",label:"Share with sandboxes",value:"off (turn on: sandbox config set github.shareToken true)"},e.gitAccess==="full"?{id:"gitAccess",label:"Git access",value:"full"}:{id:"gitAccess",label:"Git access",value:e.gitAccess+' (the token is only handed over with "full")',tone:"warn"},{id:"token",label:"Token",value:Ibe[e.token]+t,tone:wbe[e.token]},...e.kind?[{id:"kind",label:"Kind",value:Sbe[e.kind],...e.kind==="classic"?{tone:"warn"}:{}}]:[]],n=[...e.token==="none"?[{text:"Next: sandbox github login",tone:"muted",only:"cli"}]:[],...e.token==="unreadable"?[{text:"Only the Windows user that saved it can read it. Save it again: sandbox github login",tone:"muted"}]:[],...bbe.map(a=>({text:a,tone:"muted"}))],o=[le(Pk,{},{key:"g",verb:"save token"}),...e.token!=="none"?[le(Dk,{},{key:"x",verb:"delete token"})]:[]];return{title:"GitHub",sections:[{id:"github",facts:r,notes:n,actions:o}]}}var HQ=lt({id:"github",title:"GitHub",summary:"A GitHub token for sandboxes: whether they get it, and the saved token.",queries:{status:gz},operations:[Pk,Dk],build:({status:e})=>kbe(e)});var Cbe=h.object({version:h.string().describe("The version that failed"),reason:h.string().describe("Why it failed, in one sentence")}),Pbe=h.object({managed:h.boolean().describe("Installed by the installer, so it can update itself"),version:h.string().describe("The version installed"),scope:h.enum(["user","machine"]).nullable().describe("Installed for you, or for everyone on this PC"),autoUpdate:h.boolean().describe("New versions install by themselves"),autoOffText:h.string().nullable().describe("Why automatic updates were turned off, if they were"),previous:h.string().nullable().describe("The version an update replaced (roll back goes there)"),failed:Cbe.nullable().describe("The last update that failed"),npmCommand:h.string().describe("How an npm install is updated"),error:h.string().nullable().describe("Why the status could not be read"),settings:h.object({pending:h.array(h.string()).describe('Each change still to make, as "name: what it does"'),error:h.string().nullable().describe("Why your saved settings could not be read")}).describe("Changes still to make to your saved settings")}),vz=Ge({id:"updates.status",title:"Updates",summary:"which version is installed and what your saved settings still need",input:h.object({}),output:Pbe,surfaces:{except:{cli:"no command shows this page; sandbox update --check and --version cover the command line"}}}),WQ=h.object({line:h.string().describe("What happened, in one sentence")}),as=_e({id:"updates.update",title:"Update now",summary:"install the newest version, or check, go back, or switch automatic updates",input:h.object({check:h.boolean().default(!1).describe("only look whether a newer version exists"),rollback:h.boolean().default(!1).describe("go back to the version before the last update"),auto:h.enum(["on","off"]).optional().describe("install new versions by themselves (for everyone on this PC: needs an admin terminal)"),unattended:h.boolean().default(!1).describe("used by automatic updates: no questions, short output"),feed:h.string().optional().describe("take the release from this folder (a feed.json and the package) instead of GitHub")}),output:WQ.extend({latest:h.string().nullable().describe("The newer version a check found")}),danger:!0,text:e=>e.line,cli:{name:"update",group:"Health",flags:{check:{flag:"--check"},rollback:{flag:"--rollback"},auto:{flag:"--auto",value:"on|off"},unattended:{flag:"--unattended",noMenu:!0,advanced:!0},feed:{flag:"--feed",value:"folder",noMenu:!0,advanced:!0}},yes:"(--rollback) do not ask first"}}),rb=_e({id:"updates.migrate",title:"Update saved settings",summary:"bring your saved settings up to date with this version",input:h.object({dryRun:h.boolean().default(!1).describe("only list what would change"),restore:h.string().optional().describe("put back the files saved before an update (a folder under <storage>\\backups)")}),output:WQ,text:e=>e.line,cli:{name:"migrate",group:"Health",flags:{dryRun:{flag:"--dry-run"},restore:{flag:"--restore",value:"backup",advanced:!0}},yes:"(--restore) do not ask first"}}),Gc=(e,t,r={})=>({id:"updates:"+e,label:t,...r});function Dbe(e,t){let r=e.managed&&!e.error,n=e.scope==="machine",o=e.autoUpdate?"off":"on",i=le(as,{rollback:!0},{label:"Roll back",verb:"go back"}),a={id:"program",title:"This program",notes:[{text:"After an update this page still runs the version it started with; sandbox web open (or the next sandbox start) starts the new one.",tone:"muted",only:"web"}],items:e.error?[{id:"updates:error",label:e.error,tone:"danger"}]:e.managed?[Gc("version","Version",{hint:e.version,description:"Installed "+(n?"for everyone on this PC":"for you")+"."}),Gc("latest","Newest version",{hint:t??"not looked yet",tone:t?"warn":"muted",keys:t?"Enter installs it.":"Enter looks on GitHub for a newer version.",primary:t?le(as,{},{label:"Install "+t,verb:"install"}):le(as,{check:!0},{label:"Check now",verb:"look",danger:!1})}),Gc("auto","Automatic updates",{hint:e.autoUpdate?"on":"off",tone:e.autoUpdate?"ok":"muted",description:n?"For everyone: needs an admin terminal.":"A new version installs once a day, even while a sandbox runs (it keeps its version until it restarts).",keys:"Enter switches them.",primary:le(as,{auto:o},{label:"Automatic updates "+o,verb:"switch",danger:!1}),actions:[le(as,{auto:o},{key:"a",label:"Automatic updates "+o,verb:"automatic on/off",danger:!1})]}),...e.autoOffText?[Gc("autooff","Automatic updates turned off",{hint:"off",tone:"warn",description:e.autoOffText})]:[],...e.previous?[Gc("previous","Previous version",{hint:e.previous,keys:"Enter goes back to it.",primary:i,actions:[{...i,key:"r",verb:"roll back"}]})]:[],...e.failed?[Gc("failed","Last failed update",{hint:e.failed.version,tone:"danger",description:"It is not tried again until a newer version is released.",details:[e.failed.reason]})]:[]]:[Gc("version","Version",{hint:e.version,description:"Installed with npm, so npm updates it: "+e.npmCommand}),Gc("npm","Update",{hint:"with npm",tone:"muted",description:"Run "+e.npmCommand+" in a terminal."})]},s=e.settings.pending,c={id:"settings",title:"Saved settings",items:e.settings.error?[{id:"settings:error",label:e.settings.error,tone:"danger"}]:s.length?s.map((d,u)=>({id:"settings:"+u,label:d.split(":")[0],hint:"to update",tone:"warn",description:"A backup is kept first.",keys:"Enter updates your saved settings.",details:[d],primary:le(rb,{},{label:"Update saved settings",verb:"update"}),actions:[le(rb,{},{key:"s",label:"Update saved settings",verb:"update saved settings"})]})):[{id:"settings:none",label:"Up to date",hint:"OK",tone:"ok",description:"Nothing to update."}]};return{title:"Updates",sections:[a,c],actions:r?[le(as,{check:!0},{key:"c",label:"Check now",verb:"check now",danger:!1}),le(as,{},{key:"u",label:"Update now",verb:"update now"})]:[]}}var ZQ=lt({id:"updates",title:"Updates",summary:"Which version is installed, installing a newer one, and bringing your saved settings up to date.",queries:{status:vz},operations:[as,rb],build:({status:e})=>Dbe(e,null)});var Rk={except:{web:"the page is the web UI"}},Rbe=h.object({running:h.boolean().describe("The web UI server answers"),port:h.number().nullable().describe("Its port on 127.0.0.1, when it runs"),address:h.string().nullable().describe("Its address (without the login token), when it runs"),lanAddress:h.string().nullable().optional().describe("Its address on your network for paired devices (LAN mode), when it listens there"),lanFingerprint:h.string().nullable().optional().describe("The LAN certificate's SHA-256 fingerprint"),lanProblem:h.string().nullable().optional().describe("Why LAN mode is on but not listening")}),Tbe=h.object({message:h.string().describe("What happened")}),xz=Ge({id:"web.status",title:"Web UI",summary:"whether the web UI server runs, and its address",input:h.object({}),output:Rbe,surfaces:Rk,text:e=>e.running&&e.port?"The web UI is running at http://127.0.0.1:"+e.port+"/ (sandbox web open signs you in)."+(e.lanAddress?`
|
|
130
130
|
On your network: `+e.lanAddress+" (certificate "+e.lanFingerprint+")":"")+(e.lanProblem?`
|
|
@@ -4,13 +4,13 @@ using System.Reflection;
|
|
|
4
4
|
using System.Runtime.InteropServices;
|
|
5
5
|
|
|
6
6
|
[assembly: AssemblyTitle("Windows Development Sandbox HCS helper")]
|
|
7
|
-
[assembly: AssemblyDescription("Helper of windows-development-sandbox (open source, MIT), used only by the beta HCS engine: asks the Windows Host Compute Service to list, create, start and stop its sandbox virtual machine, gives that machine access to its own disk file
|
|
7
|
+
[assembly: AssemblyDescription("Helper of windows-development-sandbox (open source, MIT), used only by the beta HCS engine: asks the Windows Host Compute Service to list, create, start and stop its sandbox virtual machine, gives that machine access to its own disk file, creates a blank virtual disk file and, for the opt-in live folders alpha, adds or removes a folder share on the running Windows Sandbox after an administrator prompt. It never mounts a disk on this PC. Source: https://github.com/JoshDiDuca/windows-development-sandbox")]
|
|
8
8
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
9
9
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
10
10
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
11
|
-
[assembly: AssemblyVersion("1.
|
|
12
|
-
[assembly: AssemblyFileVersion("1.
|
|
13
|
-
[assembly: AssemblyInformationalVersion("1.
|
|
11
|
+
[assembly: AssemblyVersion("1.15.0.0")]
|
|
12
|
+
[assembly: AssemblyFileVersion("1.15.0.0")]
|
|
13
|
+
[assembly: AssemblyInformationalVersion("1.15.0")]
|
|
14
14
|
[assembly: ComVisible(false)]
|
|
15
15
|
// computecore.dll and computestorage.dll are not KnownDLLs: load them from System32 only, never from the exe's folder.
|
|
16
16
|
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|