windows-development-sandbox 1.18.3 → 1.20.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/README.md +1 -1
- package/config.example.json +9 -0
- package/dist/app/features/accounts/accounts.def.d.ts +4 -0
- package/dist/app/features/accounts/accounts.run.d.ts +1 -0
- package/dist/app/features/accounts/services.def.d.ts +3 -0
- package/dist/app/features/accounts/services.def.js +4 -2
- package/dist/app/features/accounts/services.run.d.ts +1 -0
- package/dist/app/features/accounts/services.run.js +3 -1
- package/dist/app/features/agent-commands/agent-commands.def.d.ts +37 -0
- package/dist/app/features/agent-commands/agent-commands.def.js +91 -0
- package/dist/app/features/agent-commands/agent-commands.run.d.ts +28 -0
- package/dist/app/features/agent-commands/agent-commands.run.js +35 -0
- package/dist/app/features/agent-commands/index.d.ts +2 -0
- package/dist/app/features/agent-commands/index.js +3 -0
- package/dist/app/features/agents/agents.def.d.ts +14 -1
- package/dist/app/features/agents/agents.def.js +61 -6
- package/dist/app/features/agents/agents.run.d.ts +1 -0
- package/dist/app/features/agents/agents.run.js +8 -1
- package/dist/app/features/agents/claude-env.def.d.ts +36 -0
- package/dist/app/features/agents/claude-env.def.js +305 -0
- package/dist/app/features/agents/env.def.d.ts +163 -0
- package/dist/app/features/agents/env.def.js +184 -0
- package/dist/app/features/agents/env.run.d.ts +43 -0
- package/dist/app/features/agents/env.run.js +86 -0
- package/dist/app/features/agents/index.d.ts +2 -0
- package/dist/app/features/agents/index.js +2 -0
- package/dist/app/features/defs.d.ts +150 -1
- package/dist/app/features/defs.js +11 -1
- package/dist/app/features/sandbox/sandbox.def.d.ts +22 -0
- package/dist/app/features/sandbox/sandbox.def.js +41 -14
- package/dist/app/features/sandbox/sandbox.run.d.ts +20 -0
- package/dist/app/features/sandbox/sandbox.run.js +41 -1
- package/dist/app/features/settings/categories.def.js +5 -2
- package/dist/app/features/settings/settings-rows.js +5 -1
- package/dist/app/features/settings/settings.run.d.ts +8 -0
- package/dist/app/features/settings/settings.run.js +9 -0
- package/dist/app/features/updates/updates.run.js +12 -2
- package/dist/app/features/vpn/vpn.def.d.ts +33 -0
- package/dist/app/features/vpn/vpn.def.js +30 -6
- package/dist/app/features/vpn/vpn.run.d.ts +11 -0
- package/dist/app/features/vpn/vpn.run.js +4 -1
- package/dist/app/kernel/rpc.d.ts +1 -1
- package/dist/app/registry.js +9 -2
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-M6XUQK53.js → chunk-2IMT7ZCT.js} +1 -1
- package/dist/bin/{chunk-3G53NNZP.js → chunk-DK4NTBUF.js} +69 -26
- package/dist/bin/{chunk-FQWYCF6L.js → chunk-Z2P5OGKL.js} +6427 -5259
- 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/agent-commands.d.ts +0 -1
- package/dist/cli/commands/agent-commands.js +2 -32
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/launch.js +6 -3
- package/dist/cli/commands/launch/leftover-offer.d.ts +3 -0
- package/dist/cli/commands/launch/leftover-offer.js +26 -0
- package/dist/cli/commands/registry.js +3 -2
- package/dist/cli/commands/repair/checks/sandbox.js +29 -2
- package/dist/cli/manifest.d.ts +1 -1
- package/dist/cli/manifest.js +1 -1
- package/dist/cli/menu/menu.d.ts +1 -1
- package/dist/cli/menu/menu.js +3 -3
- package/dist/cli/menu/pages/agents-page.d.ts +7 -2
- package/dist/cli/menu/pages/agents-page.js +67 -11
- package/dist/cli/menu/pages/maintenance-page.js +1 -2
- package/dist/cli/menu/pages/settings-page.js +1 -0
- package/dist/cli/menu/views.js +2 -1
- package/dist/cli/services/agent-commands-service.d.ts +2 -0
- package/dist/cli/services/agent-commands-service.js +13 -7
- package/dist/cli/services/vpn-service.d.ts +5 -1
- package/dist/cli/services/vpn-service.js +6 -1
- package/dist/cli/tui/dialogs/text-screen.js +2 -1
- package/dist/cli/tui/terminal.js +3 -1
- package/dist/core/config/defaults.js +9 -0
- package/dist/core/detect/toolchains.js +9 -0
- package/dist/core/disk.d.ts +1 -5
- package/dist/core/disk.js +1 -16
- package/dist/core/schema/codex.d.ts +29 -0
- package/dist/core/schema/codex.js +24 -0
- package/dist/core/schema/config.d.ts +46 -14
- package/dist/core/schema/config.js +2 -0
- package/dist/core/schema/index.d.ts +1 -0
- package/dist/core/schema/index.js +1 -0
- package/dist/core/schema/toolchains.d.ts +4 -0
- package/dist/core/schema/toolchains.js +3 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/guest/accounts/apply.d.ts +6 -6
- package/dist/guest/agents/agent-files.d.ts +26 -6
- package/dist/guest/agents/agent-files.js +84 -14
- package/dist/guest/agents/local-state.d.ts +5 -2
- package/dist/guest/agents/local-state.js +24 -10
- package/dist/guest/boot/boot.js +10 -5
- package/dist/guest/daemon/heartbeat.d.ts +7 -2
- package/dist/guest/daemon/heartbeat.js +34 -15
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/daemon/sessions.js +2 -1
- package/dist/guest/entries/daemon.js +1 -1
- package/dist/guest/toolchains/installers.d.ts +6 -10
- package/dist/guest/toolchains/installers.js +4 -12
- package/dist/guest/toolchains/native/autosdk.d.ts +3 -0
- package/dist/guest/toolchains/native/autosdk.js +50 -0
- package/dist/guest/toolchains/native/unreal.js +3 -0
- package/dist/guest/toolchains/native/vcruntime.d.ts +0 -3
- package/dist/guest/toolchains/native/vcruntime.js +2 -5
- package/dist/guest/toolchains/native/visual-studio.d.ts +2 -2
- package/dist/guest/toolchains/native/visual-studio.js +100 -16
- package/dist/guest/toolchains/native/vs-request.d.ts +21 -0
- package/dist/guest/toolchains/native/vs-request.js +60 -1
- package/dist/guest/toolchains/not-yet.d.ts +1 -1
- package/dist/guest/toolchains/not-yet.js +3 -3
- package/dist/guest/toolchains/persisted.js +2 -7
- package/dist/guest/toolchains/plan.js +9 -4
- package/dist/guest/toolchains/signature.d.ts +5 -0
- package/dist/guest/toolchains/signature.js +22 -0
- package/dist/guest/vpn/tunnel.d.ts +3 -0
- package/dist/guest/vpn/tunnel.js +10 -12
- package/dist/guest/vpn/vpn.js +6 -1
- package/dist/host/accounts/leases.d.ts +3 -3
- package/dist/host/accounts/source.js +1 -1
- package/dist/host/agent-commands/commands.js +1 -1
- package/dist/host/agent-commands/forwarders.d.ts +14 -2
- package/dist/host/agent-commands/forwarders.js +31 -13
- package/dist/host/agent-commands/reconcile.d.ts +2 -1
- package/dist/host/agent-commands/reconcile.js +7 -8
- package/dist/host/agent-commands/user-path.d.ts +5 -0
- package/dist/host/agent-commands/user-path.js +13 -0
- package/dist/host/health/index.d.ts +1 -0
- package/dist/host/health/index.js +1 -0
- package/dist/host/health/leftovers.d.ts +3 -0
- package/dist/host/health/leftovers.js +40 -0
- package/dist/host/health/stale.d.ts +48 -0
- package/dist/host/health/stale.js +40 -0
- package/dist/host/launch/session-file.js +1 -0
- package/dist/host/life/crash-report.d.ts +1 -1
- package/dist/host/life/crash-report.js +5 -3
- package/dist/host/life/last-end.d.ts +7 -0
- package/dist/host/life/last-end.js +21 -0
- package/dist/host/life/life-record.d.ts +3 -0
- package/dist/host/life/life-record.js +2 -2
- package/dist/host/life/stop-events.d.ts +3 -1
- package/dist/host/life/stop-events.js +59 -0
- package/dist/host/life/stop-warning.js +3 -0
- package/dist/host/profile/accounts.js +2 -4
- package/dist/host/profile/claude-login.d.ts +3 -2
- package/dist/host/profile/claude-login.js +3 -13
- package/dist/host/sandbox/cleanup.d.ts +37 -0
- package/dist/host/sandbox/cleanup.js +82 -0
- package/dist/host/sandbox/index.d.ts +1 -0
- package/dist/host/sandbox/index.js +1 -0
- package/dist/host/sandbox/platform.js +1 -1
- package/dist/host/vpn/index.d.ts +2 -1
- package/dist/host/vpn/index.js +2 -1
- package/dist/host/vpn/last.d.ts +28 -0
- package/dist/host/vpn/last.js +43 -0
- package/dist/host/vpn/login.d.ts +3 -1
- package/dist/host/vpn/login.js +17 -3
- package/dist/runtime/agent.js +31 -1
- package/dist/runtime/daemon.js +1419 -1197
- package/dist/runtime/db.js +33 -1
- package/dist/runtime/main.js +1311 -1037
- package/dist/runtime/netproxy.js +25 -1
- package/dist/runtime/tool.js +241 -209
- package/dist/runtime/view.js +25 -1
- package/dist/selftest/agent-commands.test.js +45 -7
- package/dist/selftest/agent-paths.test.js +1 -12
- package/dist/selftest/agent-settings.test.d.ts +2 -0
- package/dist/selftest/agent-settings.test.js +94 -0
- package/dist/selftest/app.test.js +2 -1
- package/dist/selftest/cli.test.js +4 -0
- package/dist/selftest/heavy-load.test.js +119 -2
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/menu.test.js +5 -3
- package/dist/selftest/pc-installs.test.js +5 -0
- package/dist/selftest/persisted-installs.test.js +69 -0
- package/dist/selftest/service-accounts.test.js +1 -1
- package/dist/selftest/support/engine-golden.js +1 -1
- package/dist/selftest/support/fixtures.d.ts +9 -0
- package/dist/selftest/vpn.test.js +51 -3
- package/dist/shared/accounts/anthropic.d.ts +5 -0
- package/dist/shared/accounts/anthropic.js +15 -0
- package/dist/shared/accounts/index.d.ts +1 -0
- package/dist/shared/accounts/index.js +1 -0
- package/dist/shared/channel/schema.d.ts +20 -0
- package/dist/shared/channel/schema.js +4 -1
- package/dist/shared/io/disk.d.ts +9 -0
- package/dist/shared/io/disk.js +19 -0
- package/dist/shared/io/index.d.ts +1 -0
- package/dist/shared/io/index.js +1 -0
- package/dist/shared/readiness.d.ts +9 -0
- package/dist/shared/readiness.js +11 -0
- package/dist/shared/signer.d.ts +24 -0
- package/dist/shared/signer.js +15 -0
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/vpn/failure.d.ts +10 -0
- package/dist/shared/vpn/failure.js +28 -0
- package/dist/sync/watcher.js +11 -4
- package/dist/web/index.html +1 -1
- package/dist/web/{main-6XYO5FZC.js → main-OUUQYNK4.js} +75 -74
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/Program.cs +19 -2
- package/native/csharp/HostTools/UserPath.cs +17 -0
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/native/scripts/edit-user-path.ps1 +6 -2
- package/native/scripts/stop-events.ps1 +7 -3
- package/package.json +1 -1
- package/sandbox/scripts/get-signature.ps1 +13 -0
- package/schemas/config.schema.json +64 -0
- package/schemas/sandbox-config.schema.json +8 -0
- package/sandbox/scripts/get-signer.ps1 +0 -8
package/README.md
CHANGED
|
@@ -65,6 +65,7 @@ The first start downloads what the project needs (a few minutes, once). Later st
|
|
|
65
65
|
| **Several projects** | `sandbox claude` from another project joins the running sandbox, with that project's own folder, tools, versions, databases and environment. Start several agents at once (`--session claude@A --session codex@B`, or the menu) and attach to any of them from any terminal. |
|
|
66
66
|
| **Pick up again** | After a crash or restart, `sandbox resume` reopens the last sessions. `sandbox restart` restarts the agents in place, and they continue their conversations. |
|
|
67
67
|
| **Leaves nothing behind** | When an agent's session ends, everything it started ends too, background servers included. Nothing of this tool keeps running on your PC once the sandbox is closed. |
|
|
68
|
+
| **Agent commands** | Turn them on (menu: Agents, or `sandbox agent-commands on`) and typing `claude`, `codex` ... in any folder starts that agent in a hidden sandbox and attaches your terminal. |
|
|
68
69
|
| **GitHub, safely** | Give sandboxes a fine-grained GitHub token made just for them (`sandbox github login`, `github.shareToken`). `gh` and `git push` then work inside, and the token is never written to the sandbox's files. |
|
|
69
70
|
| **Feels like home** | Your desktop look, Claude settings, MCP servers and conversation history come along, and history syncs back. Saved logins (`sandbox account`) are encrypted for your Windows user. |
|
|
70
71
|
|
|
@@ -122,7 +123,6 @@ and keeps all its features.
|
|
|
122
123
|
| Feature | Status | What it does |
|
|
123
124
|
| ------------------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
124
125
|
| **Web UI** (`sandbox web`, `web.enabled`) | Beta | Agents, live terminals, status, apps, accounts and settings in your browser, with search (Ctrl+K). This PC only, signed in with a token; devices on your network if you allow them. [web-ui.md](docs/web-ui.md) |
|
|
125
|
-
| **Agent commands** (`sandbox agent-commands on`) | Beta | Typing `claude`, `codex` ... in any folder starts that agent in a hidden sandbox and attaches your terminal. |
|
|
126
126
|
| **Contained storage** (`sandbox storage contained on`) | Beta | Tools, logins and logs in one disk image, mounted only while a sandbox runs. One admin prompt per launch. [Details](docs/configuration.md#contained-storage-beta) |
|
|
127
127
|
| **VPN** (`sandbox vpn`, `vpn.enabled`) | Alpha | The sandbox's traffic through NordVPN, your own OpenVPN profile or a WireGuard config, with a kill switch. A tunnel carrying traffic is not confirmed yet: read [vpn.md](docs/vpn.md) first. |
|
|
128
128
|
| **HCS engine** (`sandbox.engine: hcs`) | Alpha | Headless agents in a Hyper-V isolated Server Core container. `sandbox engine check hcs` shows what your PC lacks. Starting it is not enabled yet. |
|
package/config.example.json
CHANGED
|
@@ -68,6 +68,14 @@
|
|
|
68
68
|
"github": {
|
|
69
69
|
"shareToken": false
|
|
70
70
|
},
|
|
71
|
+
"codex": {
|
|
72
|
+
"sandboxMode": "danger-full-access",
|
|
73
|
+
"approvalPolicy": "never",
|
|
74
|
+
"model": "",
|
|
75
|
+
"reasoningEffort": "default",
|
|
76
|
+
"windowsSandbox": "off",
|
|
77
|
+
"mcpLoginsInFile": true
|
|
78
|
+
},
|
|
71
79
|
"accounts": {
|
|
72
80
|
"epic": {
|
|
73
81
|
"share": false
|
|
@@ -155,6 +163,7 @@
|
|
|
155
163
|
"acceptLicense": false,
|
|
156
164
|
"components": [],
|
|
157
165
|
"keepInstallFiles": true,
|
|
166
|
+
"visualStudio": "full",
|
|
158
167
|
"persistEngines": true,
|
|
159
168
|
"derivedDataCache": "persisted"
|
|
160
169
|
},
|
|
@@ -74,6 +74,7 @@ export declare const AccountsListSchema: z.ZodObject<{
|
|
|
74
74
|
canImport: z.ZodBoolean;
|
|
75
75
|
canLogin: z.ZodBoolean;
|
|
76
76
|
needsFile: z.ZodBoolean;
|
|
77
|
+
ready: z.ZodBoolean;
|
|
77
78
|
}, z.core.$strip>>;
|
|
78
79
|
}, z.core.$strip>;
|
|
79
80
|
export type AccountsList = z.output<typeof AccountsListSchema>;
|
|
@@ -121,6 +122,7 @@ export declare const listAccounts: import("../../kernel/define.js").QueryDef<z.Z
|
|
|
121
122
|
canImport: z.ZodBoolean;
|
|
122
123
|
canLogin: z.ZodBoolean;
|
|
123
124
|
needsFile: z.ZodBoolean;
|
|
125
|
+
ready: z.ZodBoolean;
|
|
124
126
|
}, z.core.$strip>>;
|
|
125
127
|
}, z.core.$strip>, "accounts.list">;
|
|
126
128
|
export declare const saveAccount: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
@@ -209,6 +211,7 @@ export declare const accountsView: import("../../kernel/define.js").ViewDef<{
|
|
|
209
211
|
canImport: z.ZodBoolean;
|
|
210
212
|
canLogin: z.ZodBoolean;
|
|
211
213
|
needsFile: z.ZodBoolean;
|
|
214
|
+
ready: z.ZodBoolean;
|
|
212
215
|
}, z.core.$strip>>;
|
|
213
216
|
}, z.core.$strip>, "accounts.list">;
|
|
214
217
|
services: import("../../kernel/define.js").QueryDef<z.ZodObject<{
|
|
@@ -232,6 +235,7 @@ export declare const accountsView: import("../../kernel/define.js").ViewDef<{
|
|
|
232
235
|
canImport: z.ZodBoolean;
|
|
233
236
|
canLogin: z.ZodBoolean;
|
|
234
237
|
needsFile: z.ZodBoolean;
|
|
238
|
+
ready: z.ZodBoolean;
|
|
235
239
|
}, z.core.$strip>>;
|
|
236
240
|
}, z.core.$strip>, "accounts.services">;
|
|
237
241
|
}, Record<string, never>, "accounts">;
|
|
@@ -39,6 +39,7 @@ export declare const listAccountsRun: import("../../kernel/define.js").Implement
|
|
|
39
39
|
canImport: import("zod").ZodBoolean;
|
|
40
40
|
canLogin: import("zod").ZodBoolean;
|
|
41
41
|
needsFile: import("zod").ZodBoolean;
|
|
42
|
+
ready: import("zod").ZodBoolean;
|
|
42
43
|
}, import("zod/v4/core").$strip>>;
|
|
43
44
|
}, import("zod/v4/core").$strip>, "accounts.list">, import("../../../cli/commands/context.js").Context>;
|
|
44
45
|
/** Asks for an API key (one hidden question). The validator answers with fixed texts only, never the key. */
|
|
@@ -20,6 +20,7 @@ export declare const ServiceRowSchema: z.ZodObject<{
|
|
|
20
20
|
canImport: z.ZodBoolean;
|
|
21
21
|
canLogin: z.ZodBoolean;
|
|
22
22
|
needsFile: z.ZodBoolean;
|
|
23
|
+
ready: z.ZodBoolean;
|
|
23
24
|
}, z.core.$strip>;
|
|
24
25
|
export type ServiceRow = z.output<typeof ServiceRowSchema>;
|
|
25
26
|
export declare const ServicesListSchema: z.ZodObject<{
|
|
@@ -41,6 +42,7 @@ export declare const ServicesListSchema: z.ZodObject<{
|
|
|
41
42
|
canImport: z.ZodBoolean;
|
|
42
43
|
canLogin: z.ZodBoolean;
|
|
43
44
|
needsFile: z.ZodBoolean;
|
|
45
|
+
ready: z.ZodBoolean;
|
|
44
46
|
}, z.core.$strip>>;
|
|
45
47
|
}, z.core.$strip>;
|
|
46
48
|
export type ServicesList = z.output<typeof ServicesListSchema>;
|
|
@@ -67,6 +69,7 @@ export declare const listServices: import("../../kernel/define.js").QueryDef<z.Z
|
|
|
67
69
|
canImport: z.ZodBoolean;
|
|
68
70
|
canLogin: z.ZodBoolean;
|
|
69
71
|
needsFile: z.ZodBoolean;
|
|
72
|
+
ready: z.ZodBoolean;
|
|
70
73
|
}, z.core.$strip>>;
|
|
71
74
|
}, z.core.$strip>, "accounts.services">;
|
|
72
75
|
export declare const serviceImport: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
@@ -27,6 +27,7 @@ export const ServiceRowSchema = z.object({
|
|
|
27
27
|
canImport: z.boolean().describe('It can be taken from this PC or a file (sandbox account import)'),
|
|
28
28
|
canLogin: z.boolean().describe('It can be typed (sandbox account login)'),
|
|
29
29
|
needsFile: z.boolean().describe('Importing it needs --from <file>'),
|
|
30
|
+
ready: z.boolean().describe('Its sign-in is written; false: the menu and the web leave it out (the CLI says coming)'),
|
|
30
31
|
});
|
|
31
32
|
export const ServicesListSchema = z.object({ services: z.array(ServiceRowSchema) });
|
|
32
33
|
const STATE_TEXT = {
|
|
@@ -55,7 +56,8 @@ export function servicesText(o) {
|
|
|
55
56
|
s.share ? 'on' : 'off',
|
|
56
57
|
STATE_TEXT[s.state],
|
|
57
58
|
day(s.savedAt) || '-',
|
|
58
|
-
[s.summary, s.heldBy ? 'in use by sandbox ' + s.heldBy : null].filter(Boolean).join(', ') ||
|
|
59
|
+
[s.ready ? s.summary : 'coming', s.heldBy ? 'in use by sandbox ' + s.heldBy : null].filter(Boolean).join(', ') ||
|
|
60
|
+
'-',
|
|
59
61
|
]),
|
|
60
62
|
];
|
|
61
63
|
const widths = table[0].map((_, i) => Math.max(...table.map((r) => r[i].length)));
|
|
@@ -179,7 +181,7 @@ export function serviceSection(s) {
|
|
|
179
181
|
}
|
|
180
182
|
/** The sections of every service (appended to the accounts page on the web). */
|
|
181
183
|
export function serviceSections(o) {
|
|
182
|
-
return o.services.map(serviceSection);
|
|
184
|
+
return o.services.filter((s) => s.ready).map(serviceSection);
|
|
183
185
|
}
|
|
184
186
|
/** One service's page for the menu: its section, and its actions as keys. */
|
|
185
187
|
export function servicePage(s) {
|
|
@@ -44,6 +44,7 @@ export declare const listServicesRun: import("../../kernel/define.js").Implement
|
|
|
44
44
|
canImport: import("zod").ZodBoolean;
|
|
45
45
|
canLogin: import("zod").ZodBoolean;
|
|
46
46
|
needsFile: import("zod").ZodBoolean;
|
|
47
|
+
ready: import("zod").ZodBoolean;
|
|
47
48
|
}, import("zod/v4/core").$strip>>;
|
|
48
49
|
}, import("zod/v4/core").$strip>, "accounts.services">, import("../../../cli/commands/context.js").Context>;
|
|
49
50
|
export declare const serviceImportRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
@@ -10,6 +10,7 @@ import { isServiceKind, SERVICE_KINDS, SERVICE_SPECS, } from '../../../shared/ac
|
|
|
10
10
|
import { readBoundedFile } from '../../../shared/io/index.js';
|
|
11
11
|
import { implement } from '../../context.js';
|
|
12
12
|
import { cancelled } from '../../kernel/index.js';
|
|
13
|
+
import { isKindReady } from '../../../shared/readiness.js';
|
|
13
14
|
import { listServices, serviceImport, serviceLogin, serviceLogout } from './services.def.js';
|
|
14
15
|
/** One service's row: never the sign-in, and the store's summary through safeText. */
|
|
15
16
|
export function serviceRow(kind, config, store, leases) {
|
|
@@ -32,6 +33,7 @@ export function serviceRow(kind, config, store, leases) {
|
|
|
32
33
|
canImport: Boolean(source.fromPc || source.fromFile),
|
|
33
34
|
canLogin: Boolean(source.fromAnswers),
|
|
34
35
|
needsFile: Boolean(source.fromFile && !source.fromPc),
|
|
36
|
+
ready: isKindReady(kind),
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
/** The kind an operation is about: the name given (checked), else asked. */
|
|
@@ -42,7 +44,7 @@ async function kindOf(io, given, verb, offered = () => true) {
|
|
|
42
44
|
fail('There is no service called "' + safeText(given) + '".', 'Use one of: ' + SERVICE_KINDS.join(', '));
|
|
43
45
|
return name;
|
|
44
46
|
}
|
|
45
|
-
const choices = SERVICE_KINDS.filter((k) => offered(SERVICE_SPECS[k])).map((k) => ({
|
|
47
|
+
const choices = SERVICE_KINDS.filter((k) => isKindReady(k) && offered(SERVICE_SPECS[k])).map((k) => ({
|
|
46
48
|
value: k,
|
|
47
49
|
label: SERVICE_SPECS[k].label,
|
|
48
50
|
}));
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type Section } from '../../kernel/index.js';
|
|
3
|
+
export declare const AgentCommandsStatusSchema: z.ZodObject<{
|
|
4
|
+
enabled: z.ZodBoolean;
|
|
5
|
+
dir: z.ZodString;
|
|
6
|
+
found: z.ZodArray<z.ZodObject<{
|
|
7
|
+
command: z.ZodString;
|
|
8
|
+
harness: z.ZodString;
|
|
9
|
+
real: z.ZodString;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export type AgentCommandsStatus = z.output<typeof AgentCommandsStatusSchema>;
|
|
13
|
+
export declare const agentCommandsStatus: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
14
|
+
enabled: z.ZodBoolean;
|
|
15
|
+
dir: z.ZodString;
|
|
16
|
+
found: z.ZodArray<z.ZodObject<{
|
|
17
|
+
command: z.ZodString;
|
|
18
|
+
harness: z.ZodString;
|
|
19
|
+
real: z.ZodString;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
}, z.core.$strip>, "agentCommands.status">;
|
|
22
|
+
export declare const agentCommandsOn: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strict>, z.ZodObject<{
|
|
23
|
+
on: z.ZodBoolean;
|
|
24
|
+
commands: z.ZodArray<z.ZodString>;
|
|
25
|
+
message: z.ZodString;
|
|
26
|
+
}, z.core.$strip>, "agentCommands.on">;
|
|
27
|
+
export declare const agentCommandsOff: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strict>, z.ZodObject<{
|
|
28
|
+
on: z.ZodBoolean;
|
|
29
|
+
commands: z.ZodArray<z.ZodString>;
|
|
30
|
+
message: z.ZodString;
|
|
31
|
+
}, z.core.$strip>, "agentCommands.off">;
|
|
32
|
+
/** The words printed by `sandbox agent-commands status`. Pure. */
|
|
33
|
+
export declare function agentCommandsText(s: AgentCommandsStatus): string;
|
|
34
|
+
/** What turning them on does, in words (also the message after it). */
|
|
35
|
+
export declare const AGENT_COMMANDS_EXPLAINED = "Typing claude, codex ... in a folder on this PC starts that agent in a hidden sandbox and attaches your terminal. Open a new terminal after turning it on or off. To run the real program once, set SANDBOX_AGENT_DIRECT=1.";
|
|
36
|
+
/** The "Agent commands" section of the agents page: the switch, then one row per agent found. Pure. */
|
|
37
|
+
export declare function agentCommandsSection(s: AgentCommandsStatus): Section;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Agent commands: typing claude, codex ... on this PC starts them in a hidden sandbox and attaches the terminal.
|
|
2
|
+
// Pure: schemas, labels and the page section; agent-commands.run.ts does the work (files and PATH on this PC).
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { action, defineOperation, defineQuery } from '../../kernel/index.js';
|
|
5
|
+
export const AgentCommandsStatusSchema = z.object({
|
|
6
|
+
enabled: z.boolean().describe('Typing claude, codex ... starts them in a sandbox (setting agentCommands.enabled)'),
|
|
7
|
+
dir: z.string().describe('The folder with the forwarding commands (first on your PATH while this is on)'),
|
|
8
|
+
found: z
|
|
9
|
+
.array(z.object({
|
|
10
|
+
command: z.string().describe('What you type (claude)'),
|
|
11
|
+
harness: z.string().describe('The agent it starts in the sandbox'),
|
|
12
|
+
real: z.string().describe('The real program on this PC'),
|
|
13
|
+
}))
|
|
14
|
+
.describe('The agents found on this PC'),
|
|
15
|
+
});
|
|
16
|
+
export const agentCommandsStatus = defineQuery({
|
|
17
|
+
id: 'agentCommands.status',
|
|
18
|
+
title: 'Agent commands',
|
|
19
|
+
summary: 'whether claude, codex ... on this PC start in a sandbox, and which agents were found',
|
|
20
|
+
input: z.object({}),
|
|
21
|
+
output: AgentCommandsStatusSchema,
|
|
22
|
+
text: (o) => agentCommandsText(o),
|
|
23
|
+
cli: { name: 'agent-commands', action: 'status', json: true },
|
|
24
|
+
});
|
|
25
|
+
const ChangedSchema = z.object({
|
|
26
|
+
on: z.boolean().describe('Agent commands are on now'),
|
|
27
|
+
commands: z.array(z.string()).describe('The commands that start an agent in a sandbox'),
|
|
28
|
+
message: z.string().describe('What happened'),
|
|
29
|
+
});
|
|
30
|
+
export const agentCommandsOn = defineOperation({
|
|
31
|
+
id: 'agentCommands.on',
|
|
32
|
+
title: 'Turn agent commands on',
|
|
33
|
+
summary: 'make claude, codex ... on this PC start in a hidden sandbox and attach',
|
|
34
|
+
input: z.object({}).strict(),
|
|
35
|
+
output: ChangedSchema,
|
|
36
|
+
text: (o) => o.message,
|
|
37
|
+
cli: { name: 'agent-commands', action: 'on' },
|
|
38
|
+
});
|
|
39
|
+
export const agentCommandsOff = defineOperation({
|
|
40
|
+
id: 'agentCommands.off',
|
|
41
|
+
title: 'Turn agent commands off',
|
|
42
|
+
summary: 'make claude, codex ... on this PC run on the PC again',
|
|
43
|
+
input: z.object({}).strict(),
|
|
44
|
+
output: ChangedSchema,
|
|
45
|
+
text: (o) => o.message,
|
|
46
|
+
cli: { name: 'agent-commands', action: 'off' },
|
|
47
|
+
});
|
|
48
|
+
/** The words printed by `sandbox agent-commands status`. Pure. */
|
|
49
|
+
export function agentCommandsText(s) {
|
|
50
|
+
const lines = ['Agent commands: ' + (s.enabled ? 'on' : 'off') + ' (' + s.dir + ')'];
|
|
51
|
+
if (s.found.length)
|
|
52
|
+
for (const a of s.found)
|
|
53
|
+
lines.push(' ' + a.command + ' sandboxed ' + a.harness + (s.enabled ? '' : ' when on') + ' real: ' + a.real);
|
|
54
|
+
else
|
|
55
|
+
lines.push('No agents found on this PC (claude, codex, gemini ... on your PATH).');
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|
|
58
|
+
/** What turning them on does, in words (also the message after it). */
|
|
59
|
+
export const AGENT_COMMANDS_EXPLAINED = 'Typing claude, codex ... in a folder on this PC starts that agent in a hidden sandbox and attaches your terminal. Open a new terminal after turning it on or off. To run the real program once, set SANDBOX_AGENT_DIRECT=1.';
|
|
60
|
+
/** The "Agent commands" section of the agents page: the switch, then one row per agent found. Pure. */
|
|
61
|
+
export function agentCommandsSection(s) {
|
|
62
|
+
const toggle = s.enabled
|
|
63
|
+
? action(agentCommandsOff, {}, { label: 'Turn off', verb: 'turn off', key: 'o' })
|
|
64
|
+
: action(agentCommandsOn, {}, { label: 'Turn on', verb: 'turn on', key: 'o' });
|
|
65
|
+
const rows = [
|
|
66
|
+
{
|
|
67
|
+
id: 'agentCommands',
|
|
68
|
+
label: 'Agent commands',
|
|
69
|
+
hint: s.enabled ? 'on' : 'off',
|
|
70
|
+
tone: s.enabled ? 'ok' : 'muted',
|
|
71
|
+
description: AGENT_COMMANDS_EXPLAINED,
|
|
72
|
+
primary: toggle,
|
|
73
|
+
keys: 'o turns it ' + (s.enabled ? 'off' : 'on') + '.',
|
|
74
|
+
actions: [toggle],
|
|
75
|
+
},
|
|
76
|
+
...s.found.map((a) => ({
|
|
77
|
+
id: 'agentCommand:' + a.command,
|
|
78
|
+
label: a.command,
|
|
79
|
+
hint: s.enabled ? 'starts in a sandbox' : 'runs on this PC',
|
|
80
|
+
tone: s.enabled ? 'ok' : 'muted',
|
|
81
|
+
description: s.enabled
|
|
82
|
+
? 'Typing ' + a.command + ' starts ' + a.harness + ' in a sandbox. The real program: ' + a.real
|
|
83
|
+
: 'Typing ' +
|
|
84
|
+
a.command +
|
|
85
|
+
' runs the real program (' +
|
|
86
|
+
a.real +
|
|
87
|
+
'). Turn agent commands on to use a sandbox instead.',
|
|
88
|
+
})),
|
|
89
|
+
];
|
|
90
|
+
return { id: 'agentCommands', title: 'Agent commands', items: rows };
|
|
91
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AgentCommandsService } from '../../../cli/services/agent-commands-service.js';
|
|
2
|
+
import { type AgentCommandsStatus } from './agent-commands.def.js';
|
|
3
|
+
export declare function readAgentCommands(service: AgentCommandsService): Promise<AgentCommandsStatus>;
|
|
4
|
+
export declare const agentCommandsStatusRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
5
|
+
enabled: import("zod").ZodBoolean;
|
|
6
|
+
dir: import("zod").ZodString;
|
|
7
|
+
found: import("zod").ZodArray<import("zod").ZodObject<{
|
|
8
|
+
command: import("zod").ZodString;
|
|
9
|
+
harness: import("zod").ZodString;
|
|
10
|
+
real: import("zod").ZodString;
|
|
11
|
+
}, import("zod/v4/core").$strip>>;
|
|
12
|
+
}, import("zod/v4/core").$strip>, "agentCommands.status">, import("../../../cli/commands/context.js").Context>;
|
|
13
|
+
/** Switches agent commands, with the words that say what changed. */
|
|
14
|
+
export declare function switchAgentCommands(service: AgentCommandsService, on: boolean): {
|
|
15
|
+
on: boolean;
|
|
16
|
+
commands: string[];
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const agentCommandsOnRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
20
|
+
on: import("zod").ZodBoolean;
|
|
21
|
+
commands: import("zod").ZodArray<import("zod").ZodString>;
|
|
22
|
+
message: import("zod").ZodString;
|
|
23
|
+
}, import("zod/v4/core").$strip>, "agentCommands.on">, import("../../../cli/commands/context.js").Context>;
|
|
24
|
+
export declare const agentCommandsOffRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
25
|
+
on: import("zod").ZodBoolean;
|
|
26
|
+
commands: import("zod").ZodArray<import("zod").ZodString>;
|
|
27
|
+
message: import("zod").ZodString;
|
|
28
|
+
}, import("zod/v4/core").$strip>, "agentCommands.off">, import("../../../cli/commands/context.js").Context>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Agent commands' work: the status, and turning them on or off (your settings file, then the files and PATH on this
|
|
2
|
+
// PC). The same function runs after a change of agentCommands.* in Settings (settings.run.ts), so every surface agrees.
|
|
3
|
+
import { requireOnPc } from '../../../cli/commands/context.js';
|
|
4
|
+
import { AgentCommandsService } from '../../../cli/services/agent-commands-service.js';
|
|
5
|
+
import { implement } from '../../context.js';
|
|
6
|
+
import { agentCommandsOff, agentCommandsOn, agentCommandsStatus, AGENT_COMMANDS_EXPLAINED, } from './agent-commands.def.js';
|
|
7
|
+
export async function readAgentCommands(service) {
|
|
8
|
+
const s = await service.statusAsync();
|
|
9
|
+
return {
|
|
10
|
+
enabled: s.enabled,
|
|
11
|
+
dir: s.dir,
|
|
12
|
+
found: s.found.map((a) => ({ command: a.command, harness: a.harness, real: a.real })),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export const agentCommandsStatusRun = implement(agentCommandsStatus, (ctx) => readAgentCommands(new AgentCommandsService(ctx)));
|
|
16
|
+
/** Switches agent commands, with the words that say what changed. */
|
|
17
|
+
export function switchAgentCommands(service, on) {
|
|
18
|
+
const result = service.setEnabled(on);
|
|
19
|
+
const commands = result?.on ? result.commands.map((a) => a.command) : [];
|
|
20
|
+
const message = on
|
|
21
|
+
? 'Agent commands are on for: ' +
|
|
22
|
+
(commands.join(', ') || 'no installed agents found yet') +
|
|
23
|
+
'. ' +
|
|
24
|
+
AGENT_COMMANDS_EXPLAINED
|
|
25
|
+
: 'Agent commands are off: claude, codex ... run on this PC again. Open a new terminal.';
|
|
26
|
+
return { on, commands, message };
|
|
27
|
+
}
|
|
28
|
+
export const agentCommandsOnRun = implement(agentCommandsOn, (ctx) => {
|
|
29
|
+
requireOnPc('agent-commands on');
|
|
30
|
+
return switchAgentCommands(new AgentCommandsService(ctx), true);
|
|
31
|
+
});
|
|
32
|
+
export const agentCommandsOffRun = implement(agentCommandsOff, (ctx) => {
|
|
33
|
+
requireOnPc('agent-commands off');
|
|
34
|
+
return switchAgentCommands(new AgentCommandsService(ctx), false);
|
|
35
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type AgentCommandsStatus } from '../agent-commands/agent-commands.def.js';
|
|
2
3
|
import { type Page } from '../../kernel/index.js';
|
|
3
4
|
export declare const AgentRowSchema: z.ZodObject<{
|
|
4
5
|
name: z.ZodString;
|
|
@@ -16,6 +17,7 @@ export declare const AgentsListSchema: z.ZodObject<{
|
|
|
16
17
|
isDefault: z.ZodBoolean;
|
|
17
18
|
removable: z.ZodBoolean;
|
|
18
19
|
}, z.core.$strip>>;
|
|
20
|
+
subagents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
19
21
|
}, z.core.$strip>;
|
|
20
22
|
export type AgentsList = z.output<typeof AgentsListSchema>;
|
|
21
23
|
export declare const listAgents: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
@@ -27,6 +29,7 @@ export declare const listAgents: import("../../kernel/define.js").QueryDef<z.Zod
|
|
|
27
29
|
isDefault: z.ZodBoolean;
|
|
28
30
|
removable: z.ZodBoolean;
|
|
29
31
|
}, z.core.$strip>>;
|
|
32
|
+
subagents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
30
33
|
}, z.core.$strip>, "agents.list">;
|
|
31
34
|
export declare const startAgent: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
32
35
|
agent: z.ZodString;
|
|
@@ -50,7 +53,7 @@ export declare const removeAgent: import("../../kernel/define.js").OperationDef<
|
|
|
50
53
|
message: z.ZodString;
|
|
51
54
|
}, z.core.$strip>, "agents.remove">;
|
|
52
55
|
/** The agents page: the default agent first, then the others, then "Add an agent…" (ids `agent:<name>` and `add`). */
|
|
53
|
-
export declare function agentsPage(o: AgentsList): Page;
|
|
56
|
+
export declare function agentsPage(o: AgentsList, commands: AgentCommandsStatus): Page;
|
|
54
57
|
export declare const agentsView: import("../../kernel/define.js").ViewDef<{
|
|
55
58
|
agents: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
56
59
|
folder: z.ZodString;
|
|
@@ -61,5 +64,15 @@ export declare const agentsView: import("../../kernel/define.js").ViewDef<{
|
|
|
61
64
|
isDefault: z.ZodBoolean;
|
|
62
65
|
removable: z.ZodBoolean;
|
|
63
66
|
}, z.core.$strip>>;
|
|
67
|
+
subagents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
64
68
|
}, z.core.$strip>, "agents.list">;
|
|
69
|
+
agentCommands: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
enabled: z.ZodBoolean;
|
|
71
|
+
dir: z.ZodString;
|
|
72
|
+
found: z.ZodArray<z.ZodObject<{
|
|
73
|
+
command: z.ZodString;
|
|
74
|
+
harness: z.ZodString;
|
|
75
|
+
real: z.ZodString;
|
|
76
|
+
}, z.core.$strip>>;
|
|
77
|
+
}, z.core.$strip>, "agentCommands.status">;
|
|
65
78
|
}, Record<string, never>, "agents">;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// The agents you can start: the list, starting one in a project of the running sandbox, adding one, making one the
|
|
2
2
|
// default and removing one you added. Pure: schemas, labels and the view; agents.run.ts does the work.
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import {
|
|
4
|
+
import { agentsEnvSet, subagentsText, SUBAGENTS_VAR } from './env.def.js';
|
|
5
|
+
import { agentCommandsOff, agentCommandsOn, agentCommandsSection, agentCommandsStatus, } from '../agent-commands/agent-commands.def.js';
|
|
6
|
+
import { action, defineOperation, defineQuery, defineView, link, } from '../../kernel/index.js';
|
|
5
7
|
/** Agent and project names as the web UI has always accepted them. */
|
|
6
8
|
const NameText = z.string().regex(/^[A-Za-z0-9_.-]{1,64}$/);
|
|
7
9
|
export const AgentRowSchema = z.object({
|
|
@@ -14,6 +16,12 @@ export const AgentsListSchema = z.object({
|
|
|
14
16
|
folder: z.string().describe('The folder a start works on (the current folder)'),
|
|
15
17
|
defaultAgent: z.string().describe('The default agent'),
|
|
16
18
|
agents: z.array(AgentRowSchema).describe('Every agent in your settings, built in or added'),
|
|
19
|
+
subagents: z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.nullable()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Claude: how many subagents run at once (null = its default); missing when Claude is not an agent here'),
|
|
17
25
|
});
|
|
18
26
|
export const listAgents = defineQuery({
|
|
19
27
|
id: 'agents.list',
|
|
@@ -86,7 +94,11 @@ function agentDescription(a, where) {
|
|
|
86
94
|
}
|
|
87
95
|
/** The menu's words for the remove key, on an agent you added that is not the default. */
|
|
88
96
|
function agentKeys(a) {
|
|
89
|
-
|
|
97
|
+
const keys = [
|
|
98
|
+
...(a.name === 'claude' ? ['e opens its environment.'] : []),
|
|
99
|
+
...(a.removable && !a.isDefault ? ['x removes it.'] : []),
|
|
100
|
+
];
|
|
101
|
+
return keys.length ? keys.join(' ') : undefined;
|
|
90
102
|
}
|
|
91
103
|
function agentItem(a, where) {
|
|
92
104
|
return {
|
|
@@ -103,19 +115,61 @@ function agentItem(a, where) {
|
|
|
103
115
|
...(a.isDefault
|
|
104
116
|
? []
|
|
105
117
|
: [action(makeDefaultAgent, { name: a.name }, { key: 'd', verb: 'make default', importance: 1 })]),
|
|
118
|
+
...(a.name === 'claude'
|
|
119
|
+
? [
|
|
120
|
+
link({ kind: 'view', view: 'agentEnv', params: { agent: 'claude' } }, 'Environment…', {
|
|
121
|
+
key: 'e',
|
|
122
|
+
verb: 'environment',
|
|
123
|
+
importance: 1,
|
|
124
|
+
description: 'Models, limits, how many subagents run at once, and other variables of Claude.',
|
|
125
|
+
}),
|
|
126
|
+
]
|
|
127
|
+
: []),
|
|
106
128
|
...(a.removable && !a.isDefault
|
|
107
129
|
? [action(removeAgent, { name: a.name }, { key: 'x', verb: 'remove', importance: 1 })]
|
|
108
130
|
: []),
|
|
109
131
|
],
|
|
110
132
|
};
|
|
111
133
|
}
|
|
134
|
+
/** Claude's "Subagents at once": its value, changed in place (the rest of its variables: Environment…). */
|
|
135
|
+
function subagentsSection(n) {
|
|
136
|
+
return {
|
|
137
|
+
id: 'claude',
|
|
138
|
+
title: 'Claude',
|
|
139
|
+
items: [
|
|
140
|
+
{
|
|
141
|
+
id: 'subagents',
|
|
142
|
+
label: 'Subagents at once',
|
|
143
|
+
hint: subagentsText(n),
|
|
144
|
+
description: 'How many subagents Claude may run at the same time. Empty goes back to its default.',
|
|
145
|
+
primary: action(agentsEnvSet, { agent: 'claude', name: SUBAGENTS_VAR }, {
|
|
146
|
+
label: 'Change',
|
|
147
|
+
verb: 'edit',
|
|
148
|
+
inline: true,
|
|
149
|
+
fields: [
|
|
150
|
+
{
|
|
151
|
+
name: 'value',
|
|
152
|
+
key: ['value'],
|
|
153
|
+
kind: 'text',
|
|
154
|
+
label: 'Subagents at once',
|
|
155
|
+
help: 'A whole number from 1 to 1000. Empty goes back to the default.',
|
|
156
|
+
optional: true,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
initial: { value: n === null ? '' : String(n) },
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
112
165
|
/** The agents page: the default agent first, then the others, then "Add an agent…" (ids `agent:<name>` and `add`). */
|
|
113
|
-
export function agentsPage(o) {
|
|
166
|
+
export function agentsPage(o, commands) {
|
|
114
167
|
const where = folderName(o.folder);
|
|
115
168
|
const sorted = [...o.agents].sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
116
169
|
return {
|
|
117
170
|
title: 'Agents',
|
|
118
171
|
sections: [
|
|
172
|
+
...(o.subagents !== undefined ? [subagentsSection(o.subagents)] : []),
|
|
119
173
|
{
|
|
120
174
|
id: 'start',
|
|
121
175
|
title: 'Start in ' + where,
|
|
@@ -130,6 +184,7 @@ export function agentsPage(o) {
|
|
|
130
184
|
},
|
|
131
185
|
],
|
|
132
186
|
},
|
|
187
|
+
agentCommandsSection(commands),
|
|
133
188
|
],
|
|
134
189
|
};
|
|
135
190
|
}
|
|
@@ -137,7 +192,7 @@ export const agentsView = defineView({
|
|
|
137
192
|
id: 'agents',
|
|
138
193
|
title: 'Agents',
|
|
139
194
|
summary: 'The agents you can start: start one, add one, choose the default.',
|
|
140
|
-
queries: { agents: listAgents },
|
|
141
|
-
operations: [startAgent, addAgent, makeDefaultAgent, removeAgent],
|
|
142
|
-
build: ({ agents }) => agentsPage(agents),
|
|
195
|
+
queries: { agents: listAgents, agentCommands: agentCommandsStatus },
|
|
196
|
+
operations: [startAgent, addAgent, makeDefaultAgent, removeAgent, agentsEnvSet, agentCommandsOn, agentCommandsOff],
|
|
197
|
+
build: ({ agents, agentCommands }) => agentsPage(agents, agentCommands),
|
|
143
198
|
});
|
|
@@ -7,6 +7,7 @@ export declare const listAgentsRun: import("../../kernel/define.js").Implementat
|
|
|
7
7
|
isDefault: import("zod").ZodBoolean;
|
|
8
8
|
removable: import("zod").ZodBoolean;
|
|
9
9
|
}, import("zod/v4/core").$strip>>;
|
|
10
|
+
subagents: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodNumber>>;
|
|
10
11
|
}, import("zod/v4/core").$strip>, "agents.list">, import("../../../cli/commands/context.js").Context>;
|
|
11
12
|
export declare const startAgentRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
12
13
|
agent: import("zod").ZodString;
|
|
@@ -14,6 +14,7 @@ import { implement } from '../../context.js';
|
|
|
14
14
|
import { cancelled } from '../../kernel/index.js';
|
|
15
15
|
import { ConfigFile } from '../settings/settings-file.js';
|
|
16
16
|
import { addAgent, listAgents, makeDefaultAgent, removeAgent, startAgent, } from './agents.def.js';
|
|
17
|
+
import { SUBAGENTS_VAR } from './env.def.js';
|
|
17
18
|
import { addedAgents, agentNameProblem, checkedAgent, commandFromPackage, newAgent, withAgent, withoutAgent, } from './agent-entry.js';
|
|
18
19
|
/** The longest a start waits for the agent to run (the first start installs it). */
|
|
19
20
|
const SESSION_START_MS = 15 * 60 * 1000;
|
|
@@ -42,7 +43,13 @@ export const listAgentsRun = implement(listAgents, async (ctx) => {
|
|
|
42
43
|
isDefault: name === config.defaultHarness,
|
|
43
44
|
removable: removable.includes(name),
|
|
44
45
|
}));
|
|
45
|
-
|
|
46
|
+
const limit = Number(config.harnesses.claude?.environment?.[SUBAGENTS_VAR]);
|
|
47
|
+
return {
|
|
48
|
+
folder: hereDir(ctx),
|
|
49
|
+
defaultAgent: config.defaultHarness,
|
|
50
|
+
agents,
|
|
51
|
+
...(config.harnesses.claude ? { subagents: Number.isInteger(limit) && limit > 0 ? limit : null } : {}),
|
|
52
|
+
};
|
|
46
53
|
});
|
|
47
54
|
export const startAgentRun = implement(startAgent, async (ctx, input, io) => {
|
|
48
55
|
if (insideSandbox() || !isSandboxRunning())
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const ENV_GROUPS: readonly ["Subagents", "Models", "Limits", "Behaviour", "Privacy", "Network", "Providers"];
|
|
2
|
+
export type EnvGroup = (typeof ENV_GROUPS)[number];
|
|
3
|
+
export interface EnvVarSpec {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly group: EnvGroup;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly kind: 'flag' | 'number' | 'text' | 'enum';
|
|
8
|
+
readonly choices?: readonly string[];
|
|
9
|
+
readonly min?: number;
|
|
10
|
+
readonly max?: number;
|
|
11
|
+
/** Its value is a login or a token: never shown, never sent to a screen. */
|
|
12
|
+
readonly secret?: boolean;
|
|
13
|
+
readonly description: string;
|
|
14
|
+
/** What Claude does when it is not set (shown beside the value). */
|
|
15
|
+
readonly defaultText?: string;
|
|
16
|
+
}
|
|
17
|
+
/** The variable that sets how many subagents run at once (Claude's code default is 20). */
|
|
18
|
+
export declare const MAX_SUBAGENTS_VAR = "CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS";
|
|
19
|
+
export declare const MAX_SUBAGENTS_DEFAULT = 20;
|
|
20
|
+
export declare const CLAUDE_ENV: readonly EnvVarSpec[];
|
|
21
|
+
/** The catalogue entry of a variable name. */
|
|
22
|
+
export declare function envSpec(name: string): EnvVarSpec | undefined;
|
|
23
|
+
/** A variable name anyone may set (the same shape the settings accept). */
|
|
24
|
+
export declare const ENV_NAME: RegExp;
|
|
25
|
+
/**
|
|
26
|
+
* What a typed value becomes for this variable: the text to save, null when it removes the variable, or a problem the
|
|
27
|
+
* person can act on. A flag is "1" or removed; a number is whole and in range; ANTHROPIC_API_KEY must pass the key
|
|
28
|
+
* check it is given. Pure.
|
|
29
|
+
*/
|
|
30
|
+
export declare function envValue(spec: EnvVarSpec | undefined, raw: string | null,
|
|
31
|
+
/** What is wrong with an Anthropic API key (the host passes anthropicKeyProblem), or null. */
|
|
32
|
+
keyProblem?: (key: string) => string | null): {
|
|
33
|
+
readonly save: string | null;
|
|
34
|
+
} | {
|
|
35
|
+
readonly problem: string;
|
|
36
|
+
};
|