windows-development-sandbox 1.11.6 → 1.12.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.
Files changed (131) hide show
  1. package/README.md +12 -6
  2. package/config.example.json +4 -3
  3. package/dist/app/features/apps/apps-rows.d.ts +4 -1
  4. package/dist/app/features/apps/apps-rows.js +7 -2
  5. package/dist/app/features/apps/apps.def.d.ts +19 -0
  6. package/dist/app/features/apps/apps.def.js +49 -12
  7. package/dist/app/features/apps/apps.run.d.ts +2 -0
  8. package/dist/app/features/apps/apps.run.js +1 -1
  9. package/dist/app/features/audit/audit.def.d.ts +341 -0
  10. package/dist/app/features/audit/audit.def.js +454 -0
  11. package/dist/app/features/audit/audit.run.d.ts +107 -0
  12. package/dist/app/features/audit/audit.run.js +133 -0
  13. package/dist/app/features/audit/index.d.ts +2 -0
  14. package/dist/app/features/audit/index.js +3 -0
  15. package/dist/app/features/defs.d.ts +194 -1
  16. package/dist/app/features/defs.js +4 -0
  17. package/dist/app/features/projects/projects.def.js +1 -1
  18. package/dist/app/features/settings/settings.run.d.ts +3 -0
  19. package/dist/app/features/settings/settings.run.js +16 -2
  20. package/dist/app/features/updates/update-lines.d.ts +1 -1
  21. package/dist/app/features/updates/update-lines.js +3 -7
  22. package/dist/app/features/updates/updates.def.js +1 -1
  23. package/dist/app/kernel/define.d.ts +12 -1
  24. package/dist/app/registry.js +2 -0
  25. package/dist/cli/args.d.ts +0 -3
  26. package/dist/cli/args.js +3 -4
  27. package/dist/cli/commands/index.d.ts +1 -1
  28. package/dist/cli/commands/index.js +1 -1
  29. package/dist/cli/commands/launch/prepare.js +1 -1
  30. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  31. package/dist/cli/commands/maintenance/index.js +0 -1
  32. package/dist/cli/commands/registry.js +1 -2
  33. package/dist/cli/manifest.d.ts +0 -41
  34. package/dist/cli/manifest.js +0 -14
  35. package/dist/cli/menu/pages/apps-page.js +2 -15
  36. package/dist/cli/menu/pages/maintenance-page.d.ts +4 -0
  37. package/dist/cli/menu/pages/maintenance-page.js +51 -8
  38. package/dist/cli/menu/views.js +2 -0
  39. package/dist/core/config/defaults.js +1 -1
  40. package/dist/core/schema/apps.d.ts +9 -0
  41. package/dist/core/schema/apps.js +9 -0
  42. package/dist/core/schema/config.d.ts +1 -0
  43. package/dist/core/schema/config.js +3 -3
  44. package/dist/core/schema/sandbox.d.ts +1 -0
  45. package/dist/core/schema/sandbox.js +11 -3
  46. package/dist/guest/apps/app-installer.js +50 -4
  47. package/dist/guest/apps/index.d.ts +1 -1
  48. package/dist/guest/apps/index.js +1 -1
  49. package/dist/guest/apps/sources.js +1 -1
  50. package/dist/guest/audit/parse.d.ts +32 -2
  51. package/dist/guest/audit/parse.js +43 -5
  52. package/dist/guest/audit/process-audit.d.ts +3 -1
  53. package/dist/guest/audit/process-audit.js +9 -6
  54. package/dist/guest/boot/boot.js +12 -3
  55. package/dist/guest/boot/guide.d.ts +1 -1
  56. package/dist/guest/boot/guide.js +27 -3
  57. package/dist/guest/daemon/sessions.d.ts +7 -0
  58. package/dist/guest/daemon/sessions.js +27 -2
  59. package/dist/guest/entries/daemon.js +2 -1
  60. package/dist/guest/setup/addon-mcp.d.ts +2 -0
  61. package/dist/guest/setup/addon-mcp.js +49 -0
  62. package/dist/guest/setup/agent-addons.d.ts +9 -0
  63. package/dist/guest/setup/agent-addons.js +22 -0
  64. package/dist/guest/setup/headroom.d.ts +7 -0
  65. package/dist/guest/setup/headroom.js +60 -0
  66. package/dist/guest/setup/managed-policy.d.ts +2 -1
  67. package/dist/guest/setup/managed-policy.js +15 -6
  68. package/dist/guest/toolchains/plan.js +8 -3
  69. package/dist/host/audit/attribute.d.ts +46 -0
  70. package/dist/host/audit/attribute.js +76 -0
  71. package/dist/host/audit/collect.d.ts +29 -3
  72. package/dist/host/audit/collect.js +256 -61
  73. package/dist/host/audit/git-commits.d.ts +29 -0
  74. package/dist/host/audit/git-commits.js +157 -0
  75. package/dist/host/audit/index.d.ts +5 -0
  76. package/dist/host/audit/index.js +6 -0
  77. package/dist/host/audit/log.d.ts +44 -7
  78. package/dist/host/audit/log.js +148 -45
  79. package/dist/host/audit/redact.d.ts +2 -0
  80. package/dist/host/audit/redact.js +67 -0
  81. package/dist/host/update/decision.d.ts +3 -2
  82. package/dist/host/update/decision.js +2 -3
  83. package/dist/host/update/updater.d.ts +4 -1
  84. package/dist/host/update/updater.js +11 -6
  85. package/dist/runtime/agent.js +110 -15
  86. package/dist/runtime/daemon.js +569 -316
  87. package/dist/runtime/db.js +110 -15
  88. package/dist/runtime/main.js +1011 -672
  89. package/dist/runtime/netproxy.js +110 -15
  90. package/dist/runtime/view.js +110 -15
  91. package/dist/selftest/app.test.js +25 -1
  92. package/dist/selftest/audit.test.js +354 -47
  93. package/dist/selftest/hcs.test.js +35 -0
  94. package/dist/selftest/menu-screens.js +1 -1
  95. package/dist/selftest/menu.test.js +3 -3
  96. package/dist/selftest/support/engine-golden.js +9 -0
  97. package/dist/selftest/support/fixtures.d.ts +1 -0
  98. package/dist/selftest/support/web-preview.js +94 -0
  99. package/dist/selftest/toolchains.test.js +147 -2
  100. package/dist/selftest/update-service.test.js +0 -7
  101. package/dist/selftest/update.test.js +4 -4
  102. package/dist/shared/apps/agent-addons.d.ts +64 -0
  103. package/dist/shared/apps/agent-addons.js +95 -0
  104. package/dist/shared/apps/catalogue.d.ts +33 -2
  105. package/dist/shared/apps/catalogue.js +102 -11
  106. package/dist/shared/apps/index.d.ts +3 -2
  107. package/dist/shared/apps/index.js +3 -2
  108. package/dist/shared/apps/selection.d.ts +2 -0
  109. package/dist/shared/apps/selection.js +7 -0
  110. package/dist/sync/watcher.js +9 -1
  111. package/dist/web/index.html +2 -2
  112. package/dist/web/{main-RQFN4WBY.css → main-UAQPI5XD.css} +1 -1
  113. package/dist/web/{main-QL7KHCEE.js → main-UD4QCXZR.js} +66 -66
  114. package/native/csharp/HcsHost/AssemblyInfo.cs +5 -3
  115. package/native/csharp/HcsHost/Hcs.cs +9 -0
  116. package/native/csharp/HcsHost/Program.cs +26 -1
  117. package/native/csharp/HcsHost/Share.cs +173 -0
  118. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  119. package/package.json +1 -1
  120. package/sandbox/addons/ccusage/package-lock.json +111 -0
  121. package/sandbox/addons/ccusage/package.json +7 -0
  122. package/sandbox/addons/context7/package-lock.json +1313 -0
  123. package/sandbox/addons/context7/package.json +7 -0
  124. package/sandbox/addons/headroom/requirements.in +1 -0
  125. package/sandbox/addons/headroom/requirements.txt +2922 -0
  126. package/sandbox/addons/playwright-mcp/package-lock.json +56 -0
  127. package/sandbox/addons/playwright-mcp/package.json +7 -0
  128. package/schemas/config.schema.json +13 -4
  129. package/schemas/sandbox-config.schema.json +2 -2
  130. package/dist/cli/commands/maintenance/audit.d.ts +0 -3
  131. package/dist/cli/commands/maintenance/audit.js +0 -58
package/README.md CHANGED
@@ -24,8 +24,9 @@ irm https://github.com/JoshDiDuca/windows-development-sandbox/releases/latest/do
24
24
 
25
25
  It checks your PC, offers to turn on Windows Sandbox, and asks **1) Just me** or **2) Everyone on this PC** (needs
26
26
  admin). It brings its own private copy of Node.js; nothing else is installed system-wide, and no Start menu shortcut
27
- unless you ask for one. `sandbox update` installs newer versions (and can do it by itself); a version that fails to
28
- start is rolled back automatically, and `sandbox update --rollback` goes back one by hand.
27
+ unless you ask for one. `sandbox update` installs newer versions (and can do it by itself), even while a sandbox runs:
28
+ the sandbox keeps its version until it restarts. A version that fails to start is rolled back automatically, and
29
+ `sandbox update --rollback` goes back one by hand.
29
30
 
30
31
  Needs Windows 10/11 **Pro, Enterprise or Education**. Have Node.js 20+? `npm install -g windows-development-sandbox`
31
32
  works too. [Scopes, options (`-Version`, `-StartMenuShortcut` ...), upgrading, uninstall](docs/install.md)
@@ -54,12 +55,14 @@ The first start downloads what the project needs (a few minutes, once). After th
54
55
  |---|---|
55
56
  | **Safe by default** | The agent sees only your project folder. Credentials are stripped before anything is copied in, your LAN is blocked, and nothing the sandbox writes can run on your PC. |
56
57
  | **Languages** | Node, Python, Rust, C/C++ (GCC or MSVC), .NET (incl. .NET Framework targeting), Go, Java, Ruby, PHP, Deno, Bun, PowerShell 7, with pnpm, yarn, Volta, uv, pyenv, Maven, Gradle, Composer, gh ... |
57
- | **Apps and tools** | VS Code (set up for your languages, with their extensions) and Windows Terminal, plus 60 optional apps and tools by category: DBeaver, pgAdmin, Bruno, Godot, Blender, kubectl, jq, ripgrep ... and programs of your own |
58
+ | **Apps and tools** | VS Code (set up for your languages, with their extensions) and Windows Terminal, plus 60 optional apps and tools by category: DBeaver, pgAdmin, Bruno, Godot, Blender, kubectl, jq, ripgrep ... and programs of your own. Agent add-ons too: rtk and Headroom (fewer tokens), ccusage, Playwright and Context7 MCP servers, claude-mem, REA. Playwright works out of the box with Edge |
58
59
  | **Databases** | PostgreSQL, MySQL, MongoDB, Redis and DynamoDB Local with a web UI, started when the project uses them, or any time with `--database` / `sandbox db` |
59
60
  | **Agents** | Claude Code, Codex, Gemini, opencode, Qwen, Crush, Copilot, Kilo, Amp, Cline, Continue, Kimi, Aider, DeepSeek agents |
60
61
  | **Smart** | Detects what the project needs from its files, respects version files, installs in parallel and reuses everything |
61
62
  | **Several projects** | `sandbox claude` from another project joins the running sandbox: its own folder, tools, versions, databases and environment, set up on demand. Start several agents at once (`--session claude@A --session codex@B`, or the menu) and attach to any of them from any terminal |
62
63
  | **Picks up where you left off** | After a crash or a restart, `sandbox resume` reopens the last sessions; `sandbox restart` restarts the agents in place and they continue their conversation |
64
+ | **Leaves nothing behind** | When an agent's session ends, everything it started ends with it, background servers included. The web UI's server stops when no browser uses it, and nothing of this tool keeps running on your PC once the sandbox is closed |
65
+ | **GitHub, safely** | Give sandboxes a fine-grained GitHub token you made for them (`sandbox github login`, `github.shareToken`): `gh` and `git push` work inside, and the token never lands in the sandbox's files |
63
66
  | **Feels like home** | Your desktop look, Claude settings, MCP servers and conversation history come along; history syncs back. Logins you save (`sandbox account`) are kept encrypted for your Windows user |
64
67
 
65
68
  ## Built for heavy workloads
@@ -98,10 +101,12 @@ Details and settings: [troubleshooting](docs/troubleshooting.md#the-sandbox-clos
98
101
  | `sandbox exec -- <cmd>` | run a command inside |
99
102
  | `sandbox config get\|set\|reset\|list` | read and change any setting from the command line (`export` / `import` to share them) |
100
103
  | `sandbox account` | save, switch and rename agent logins |
104
+ | `sandbox github` / `vpn` | the GitHub token for sandboxes; the VPN login and status |
101
105
  | `sandbox web` | (Beta) the web UI: start, stop, status, open |
102
106
  | `sandbox stop` / `hide` / `show` | shut down, hide or show the window |
103
107
  | `sandbox data` / `storage` | what's stored and how big, freeing space, moving the data folder |
104
108
  | `sandbox setup` / `doctor` / `repair` | check this PC, see what will be installed, fix common problems |
109
+ | `sandbox engine` | the engines and what each can do on this PC; `engine clean` stops HCS systems left running |
105
110
  | `sandbox logs [-f] [--crash]` | the sandbox log, or the report of the last crash |
106
111
  | `sandbox update [--rollback]` / `--version` | update (or go back one version); the installed version |
107
112
 
@@ -117,14 +122,15 @@ keeps every feature it has.
117
122
  | **Web UI** (`sandbox web`, `web.enabled`) | Beta | Agents, sessions with live terminals, the sandbox's status, apps, accounts and every setting in your browser, with search (Ctrl+K) and a folder picker; on this PC only (loopback, signed in with a token). `web.openOnLaunch` opens it with every sandbox. [web-ui.md](docs/web-ui.md) |
118
123
  | **Agent commands** (`sandbox agent-commands on`) | Beta | Typing `claude`, `codex` ... in any folder starts it in a hidden sandbox and attaches your terminal |
119
124
  | **Contained storage** (`sandbox storage contained on`) | Beta | Tools, logins and logs in one disk image per data set, mounted only while a sandbox runs. One admin prompt per launch. [engines](docs/design/engines.md) |
120
- | **VPN** (`sandbox vpn`, `vpn.enabled`) | Alpha | The sandbox's traffic through NordVPN, your own OpenVPN profile or a WireGuard config, with a kill switch. Not yet tried on a real PC: read [vpn.md](docs/vpn.md) first |
121
- | **HCS engine** (`sandbox.engine: hcs`, `sandbox engine`) | 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 |
125
+ | **VPN** (`sandbox vpn`, `vpn.enabled`) | Alpha | The sandbox's traffic through NordVPN, your own OpenVPN profile or a WireGuard config, with a kill switch that is checked with a real connection. The first real try fixed the install and the kill switch; a tunnel carrying traffic is not confirmed yet: read [vpn.md](docs/vpn.md) first |
126
+ | **HCS engine** (`sandbox.engine: hcs`, `sandbox engine`) | 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. Its create, start and stop steps pass on GitHub's Windows Server 2022 and 2025 runners |
122
127
 
123
128
  ## Known gaps
124
129
 
125
130
  - Adding a folder to a RUNNING sandbox needs Windows 11 24H2+ with the updated Windows Sandbox (`wsb share`,
126
131
  untested). On older Windows, folders inside a project root open at once and anything else offers a restart.
127
- [Details, and how to get `wsb`](docs/projects.md#adding-folders-to-a-running-sandbox-wsb-share).
132
+ [Details, and how to get `wsb`](docs/projects.md#adding-folders-to-a-running-sandbox-wsb-share). A way for older
133
+ Windows through HCS is designed and waiting for a test on a real PC ([design](docs/design/hcs-live-folders.md)).
128
134
  - Windows Sandbox runs one sandbox at a time per PC; every project and agent shares it.
129
135
  - What is planned next: [roadmap](docs/roadmap.md).
130
136
 
@@ -9,11 +9,12 @@
9
9
  "include": []
10
10
  },
11
11
  "audit": {
12
- "enabled": false,
13
- "days": 14,
12
+ "enabled": true,
13
+ "days": 7,
14
14
  "maxMb": 100,
15
15
  "processes": true,
16
- "files": true
16
+ "files": true,
17
+ "commits": true
17
18
  },
18
19
  "mappings": [],
19
20
  "sandbox": {
@@ -21,7 +21,10 @@ export interface AppsSource {
21
21
  }
22
22
  /** The files as they are on disk. */
23
23
  export declare const SAVED: AppsSource;
24
- /** The catalogue entries a file can change (a project cannot change an app that has a setting of its own). */
24
+ /**
25
+ * The catalogue entries a file can change (a project cannot change an app that has a setting of its own, nor an agent
26
+ * add-on that is yours only).
27
+ */
25
28
  export declare function entriesOf(file: ConfigFile): AppEntry[];
26
29
  /** Is the entry on in this source? */
27
30
  export declare function appIsOn(entry: AppEntry, file: ConfigFile, source: AppsSource): boolean;
@@ -17,9 +17,12 @@ export const SAVED = {
17
17
  setting: (file, key) => _.get(file.userConfig(), key),
18
18
  custom: (file) => (file.isProject ? {} : file.userConfig().apps.custom),
19
19
  };
20
- /** The catalogue entries a file can change (a project cannot change an app that has a setting of its own). */
20
+ /**
21
+ * The catalogue entries a file can change (a project cannot change an app that has a setting of its own, nor an agent
22
+ * add-on that is yours only).
23
+ */
21
24
  export function entriesOf(file) {
22
- return APPS.filter((a) => !(file.isProject && a.setting));
25
+ return APPS.filter((a) => !(file.isProject && (a.setting || a.userOnly)));
23
26
  }
24
27
  /** Downloaded already (into this data folder), so the next sandbox starts it without a download. */
25
28
  function installed(entry, dataPath) {
@@ -57,6 +60,8 @@ export function appRows(file, dataPath, source = SAVED) {
57
60
  cli: Boolean(entry.cli),
58
61
  mesa: entry.needs?.includes('mesa') ?? false,
59
62
  fullGitOnly: Boolean(entry.fullGitOnly),
63
+ ...(entry.plugsInto ? { plugsInto: entry.plugsInto } : {}),
64
+ ...(entry.service ? { service: true } : {}),
60
65
  ...settingParts(entry, file, source),
61
66
  installed: installed(entry, dataPath),
62
67
  on: appIsOn(entry, file, source),
@@ -32,6 +32,8 @@ export declare const AppRowSchema: z.ZodObject<{
32
32
  cli: z.ZodBoolean;
33
33
  mesa: z.ZodBoolean;
34
34
  fullGitOnly: z.ZodBoolean;
35
+ plugsInto: z.ZodOptional<z.ZodString>;
36
+ service: z.ZodOptional<z.ZodBoolean>;
35
37
  setting: z.ZodOptional<z.ZodString>;
36
38
  settingField: z.ZodOptional<z.ZodType<Field, unknown, z.core.$ZodTypeInternals<Field, unknown>>>;
37
39
  settingValue: z.ZodOptional<z.ZodUnknown>;
@@ -63,6 +65,8 @@ export declare const AppsListSchema: z.ZodObject<{
63
65
  cli: z.ZodBoolean;
64
66
  mesa: z.ZodBoolean;
65
67
  fullGitOnly: z.ZodBoolean;
68
+ plugsInto: z.ZodOptional<z.ZodString>;
69
+ service: z.ZodOptional<z.ZodBoolean>;
66
70
  setting: z.ZodOptional<z.ZodString>;
67
71
  settingField: z.ZodOptional<z.ZodType<Field, unknown, z.core.$ZodTypeInternals<Field, unknown>>>;
68
72
  settingValue: z.ZodOptional<z.ZodUnknown>;
@@ -100,6 +104,8 @@ export declare const listApps: import("../../kernel/define.js").QueryDef<z.ZodOb
100
104
  cli: z.ZodBoolean;
101
105
  mesa: z.ZodBoolean;
102
106
  fullGitOnly: z.ZodBoolean;
107
+ plugsInto: z.ZodOptional<z.ZodString>;
108
+ service: z.ZodOptional<z.ZodBoolean>;
103
109
  setting: z.ZodOptional<z.ZodString>;
104
110
  settingField: z.ZodOptional<z.ZodType<Field, unknown, z.core.$ZodTypeInternals<Field, unknown>>>;
105
111
  settingValue: z.ZodOptional<z.ZodUnknown>;
@@ -137,6 +143,17 @@ export declare const setCustomApps: import("../../kernel/define.js").OperationDe
137
143
  export declare const requestApp: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
138
144
  url: z.ZodString;
139
145
  }, z.core.$strip>, "apps.request">;
146
+ /** One line under an app: a short label ('' for a warning on its own) and its text. */
147
+ export interface AppDetail {
148
+ readonly label: string;
149
+ readonly text: string;
150
+ readonly warn?: boolean;
151
+ }
152
+ /**
153
+ * The lines under an app: its download, how it starts, what it plugs into, what it needs. A setting-backed entry with
154
+ * nothing to download (claude-mem) has no size, so no download lines. The menu draws the same lines with colours.
155
+ */
156
+ export declare function appDetails(row: AppRow): AppDetail[];
140
157
  /** The apps page of one scope: a category per group (with a switch per app), your own programs and their actions. */
141
158
  export declare function appsPage(o: AppsList): Page;
142
159
  export declare const appsView: import("../../kernel/define.js").ViewDef<{
@@ -161,6 +178,8 @@ export declare const appsView: import("../../kernel/define.js").ViewDef<{
161
178
  cli: z.ZodBoolean;
162
179
  mesa: z.ZodBoolean;
163
180
  fullGitOnly: z.ZodBoolean;
181
+ plugsInto: z.ZodOptional<z.ZodString>;
182
+ service: z.ZodOptional<z.ZodBoolean>;
164
183
  setting: z.ZodOptional<z.ZodString>;
165
184
  settingField: z.ZodOptional<z.ZodType<Field, unknown, z.core.$ZodTypeInternals<Field, unknown>>>;
166
185
  settingValue: z.ZodOptional<z.ZodUnknown>;
@@ -10,6 +10,12 @@ export const AppsScopeSchema = z
10
10
  .describe("Your own settings (all projects) or this folder's .sandbox-config.json (this project)");
11
11
  /** The groups the page shows; the menu and the web list the apps by these, so the navigation stays short. */
12
12
  export const APP_GROUPS = [
13
+ {
14
+ id: 'agents',
15
+ label: 'Agent add-ons',
16
+ 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).',
17
+ members: ['agents'],
18
+ },
13
19
  {
14
20
  id: 'editors',
15
21
  label: 'Editors & docs',
@@ -79,6 +85,8 @@ export const AppRowSchema = z.object({
79
85
  cli: z.boolean().describe('A command-line tool (on PATH), not a desktop app'),
80
86
  mesa: z.boolean().describe('Needs OpenGL on the CPU (Mesa)'),
81
87
  fullGitOnly: z.boolean().describe('Only with full git access'),
88
+ plugsInto: z.string().optional().describe('Which agents an add-on plugs into, and how'),
89
+ service: z.boolean().optional().describe('Started by the sandbox or the agent (a proxy, an MCP server)'),
82
90
  setting: z.string().optional().describe('The setting it stands for (VS Code, Windows Terminal)'),
83
91
  /** That setting's own Field and value (on, off or auto), so it is changed with its own control. */
84
92
  settingField: FieldSchema.optional(),
@@ -144,23 +152,52 @@ export const requestApp = defineOperation({
144
152
  text: (o) => 'Opened the request form in your browser: ' + o.url,
145
153
  surfaces: { except: { cli: 'a request is filed on GitHub; the address is in docs' } },
146
154
  });
147
- /** The lines under an app: its download, how it starts, what it needs. Plain text, like the CLI's. */
148
- function details(row) {
155
+ /**
156
+ * The lines under an app: its download, how it starts, what it plugs into, what it needs. A setting-backed entry with
157
+ * nothing to download (claude-mem) has no size, so no download lines. The menu draws the same lines with colours.
158
+ */
159
+ export function appDetails(row) {
160
+ const downloads = row.size !== '';
149
161
  return [
150
- 'Download ~' +
151
- row.size +
152
- ' once, kept in C:\\AgentData\\tools\\' +
153
- (row.setting ? '' : 'apps\\') +
154
- row.id +
155
- (row.installed ? ' (downloaded already)' : ''),
156
- 'Starts ' + (row.cli ? 'from a terminal (on PATH)' : 'from the desktop or Start > Sandbox apps'),
157
- ...(row.mesa ? ['Graphics OpenGL on the CPU (Mesa) is added for it'] : []),
162
+ ...(downloads
163
+ ? [
164
+ {
165
+ label: 'Download',
166
+ text: '~' +
167
+ row.size +
168
+ ' once, kept in C:\\AgentData\\tools\\' +
169
+ (row.setting ? '' : 'apps\\') +
170
+ row.id +
171
+ (row.installed ? ' (downloaded already)' : ''),
172
+ },
173
+ {
174
+ label: 'Starts',
175
+ text: row.service
176
+ ? 'by the sandbox or the agent (no shortcut, not on PATH)'
177
+ : row.cli
178
+ ? 'from a terminal (on PATH)'
179
+ : 'from the desktop or Start > Sandbox apps',
180
+ },
181
+ ]
182
+ : []),
183
+ ...(row.plugsInto ? [{ label: 'Plugs in', text: row.plugsInto }] : []),
184
+ ...(row.mesa ? [{ label: 'Graphics', text: 'OpenGL on the CPU (Mesa) is added for it' }] : []),
158
185
  ...(row.fullGitOnly
159
- ? ['Needs full git access (Settings > Projects & setup > Git): it pushes with its own git.']
186
+ ? [
187
+ {
188
+ label: '',
189
+ text: 'Needs full git access (Settings > Projects & setup > Git): it pushes with its own git.',
190
+ warn: true,
191
+ },
192
+ ]
160
193
  : []),
161
- ...(row.setting ? ['Setting ' + row.setting] : []),
194
+ ...(row.setting ? [{ label: 'Setting', text: row.setting }] : []),
162
195
  ];
163
196
  }
197
+ /** The lines as plain text, like the CLI's. */
198
+ function details(row) {
199
+ return appDetails(row).map((d) => (d.label ? d.label.padEnd(10) : '') + d.text);
200
+ }
164
201
  /** The switch that turns an app on or off: one boolean field, changed in place. */
165
202
  function switchField(row) {
166
203
  return { name: 'on', key: ['apps', 'install'], kind: 'boolean', label: row.name, optional: false };
@@ -19,6 +19,8 @@ export declare const listAppsRun: import("../../kernel/define.js").Implementatio
19
19
  cli: import("zod").ZodBoolean;
20
20
  mesa: import("zod").ZodBoolean;
21
21
  fullGitOnly: import("zod").ZodBoolean;
22
+ plugsInto: import("zod").ZodOptional<import("zod").ZodString>;
23
+ service: import("zod").ZodOptional<import("zod").ZodBoolean>;
22
24
  setting: import("zod").ZodOptional<import("zod").ZodString>;
23
25
  settingField: import("zod").ZodOptional<import("zod").ZodType<import("../../kernel/fields.js").Field, unknown, import("zod/v4/core").$ZodTypeInternals<import("../../kernel/fields.js").Field, unknown>>>;
24
26
  settingValue: import("zod").ZodOptional<import("zod").ZodUnknown>;
@@ -26,7 +26,7 @@ export const listAppsRun = implement(listApps, (ctx, input) => {
26
26
  export const toggleAppRun = implement(toggleApp, (ctx, input) => {
27
27
  const file = settingsFiles(ctx)[input.scope];
28
28
  const entry = APPS.find((a) => a.id === input.id);
29
- if (!entry || (file.isProject && entry.setting))
29
+ if (!entry || (file.isProject && (entry.setting || entry.userOnly)))
30
30
  fail('"' + input.id + '" is not an app this scope can change.', 'Pick one of the apps the Apps page lists.');
31
31
  const name = entry.name;
32
32
  // A setting-backed app (VS Code, Windows Terminal) is its setting; a catalogue app is one id in apps.install.
@@ -0,0 +1,341 @@
1
+ import { z } from 'zod';
2
+ import { type Page } from '../../kernel/index.js';
3
+ export declare const AUDIT_EVENT_KINDS: readonly ["proc", "file", "commit", "session", "guard", "note"];
4
+ export declare const AUDIT_KIND_FILTERS: readonly ["all", "proc", "file", "commit", "session", "guard"];
5
+ /** The session filter that means "not linked to any session". */
6
+ export declare const NO_SESSION = "none";
7
+ export declare const AuditRowSchema: z.ZodObject<{
8
+ time: z.ZodString;
9
+ kind: z.ZodEnum<{
10
+ file: "file";
11
+ session: "session";
12
+ note: "note";
13
+ commit: "commit";
14
+ proc: "proc";
15
+ guard: "guard";
16
+ }>;
17
+ what: z.ZodString;
18
+ command: z.ZodOptional<z.ZodString>;
19
+ parent: z.ZodOptional<z.ZodString>;
20
+ action: z.ZodOptional<z.ZodString>;
21
+ folder: z.ZodOptional<z.ZodString>;
22
+ project: z.ZodOptional<z.ZodString>;
23
+ session: z.ZodOptional<z.ZodString>;
24
+ agent: z.ZodOptional<z.ZodString>;
25
+ linked: z.ZodOptional<z.ZodEnum<{
26
+ process: "process";
27
+ "only-session": "only-session";
28
+ }>>;
29
+ count: z.ZodNumber;
30
+ sha: z.ZodOptional<z.ZodString>;
31
+ author: z.ZodOptional<z.ZodString>;
32
+ }, z.core.$strip>;
33
+ export type AuditRow = z.output<typeof AuditRowSchema>;
34
+ export declare const AuditSessionSchema: z.ZodObject<{
35
+ commands: z.ZodNumber;
36
+ files: z.ZodNumber;
37
+ commits: z.ZodNumber;
38
+ id: z.ZodString;
39
+ agent: z.ZodString;
40
+ project: z.ZodString;
41
+ started: z.ZodString;
42
+ ended: z.ZodOptional<z.ZodString>;
43
+ last: z.ZodOptional<z.ZodString>;
44
+ }, z.core.$strip>;
45
+ export type AuditSession = z.output<typeof AuditSessionSchema>;
46
+ export declare const AuditAgentSchema: z.ZodObject<{
47
+ commands: z.ZodNumber;
48
+ files: z.ZodNumber;
49
+ commits: z.ZodNumber;
50
+ agent: z.ZodString;
51
+ sessions: z.ZodNumber;
52
+ }, z.core.$strip>;
53
+ export declare const AuditListSchema: z.ZodObject<{
54
+ enabled: z.ZodBoolean;
55
+ keepDays: z.ZodNumber;
56
+ maxMb: z.ZodNumber;
57
+ bytes: z.ZodNumber;
58
+ folder: z.ZodString;
59
+ filter: z.ZodObject<{
60
+ days: z.ZodNumber;
61
+ kind: z.ZodEnum<{
62
+ file: "file";
63
+ all: "all";
64
+ session: "session";
65
+ commit: "commit";
66
+ proc: "proc";
67
+ guard: "guard";
68
+ }>;
69
+ session: z.ZodOptional<z.ZodString>;
70
+ agent: z.ZodOptional<z.ZodString>;
71
+ project: z.ZodOptional<z.ZodString>;
72
+ grep: z.ZodOptional<z.ZodString>;
73
+ }, z.core.$strip>;
74
+ matched: z.ZodNumber;
75
+ events: z.ZodArray<z.ZodObject<{
76
+ time: z.ZodString;
77
+ kind: z.ZodEnum<{
78
+ file: "file";
79
+ session: "session";
80
+ note: "note";
81
+ commit: "commit";
82
+ proc: "proc";
83
+ guard: "guard";
84
+ }>;
85
+ what: z.ZodString;
86
+ command: z.ZodOptional<z.ZodString>;
87
+ parent: z.ZodOptional<z.ZodString>;
88
+ action: z.ZodOptional<z.ZodString>;
89
+ folder: z.ZodOptional<z.ZodString>;
90
+ project: z.ZodOptional<z.ZodString>;
91
+ session: z.ZodOptional<z.ZodString>;
92
+ agent: z.ZodOptional<z.ZodString>;
93
+ linked: z.ZodOptional<z.ZodEnum<{
94
+ process: "process";
95
+ "only-session": "only-session";
96
+ }>>;
97
+ count: z.ZodNumber;
98
+ sha: z.ZodOptional<z.ZodString>;
99
+ author: z.ZodOptional<z.ZodString>;
100
+ }, z.core.$strip>>;
101
+ totals: z.ZodObject<{
102
+ commands: z.ZodNumber;
103
+ files: z.ZodNumber;
104
+ commits: z.ZodNumber;
105
+ events: z.ZodNumber;
106
+ sessions: z.ZodNumber;
107
+ }, z.core.$strip>;
108
+ agents: z.ZodArray<z.ZodObject<{
109
+ commands: z.ZodNumber;
110
+ files: z.ZodNumber;
111
+ commits: z.ZodNumber;
112
+ agent: z.ZodString;
113
+ sessions: z.ZodNumber;
114
+ }, z.core.$strip>>;
115
+ sessions: z.ZodArray<z.ZodObject<{
116
+ commands: z.ZodNumber;
117
+ files: z.ZodNumber;
118
+ commits: z.ZodNumber;
119
+ id: z.ZodString;
120
+ agent: z.ZodString;
121
+ project: z.ZodString;
122
+ started: z.ZodString;
123
+ ended: z.ZodOptional<z.ZodString>;
124
+ last: z.ZodOptional<z.ZodString>;
125
+ }, z.core.$strip>>;
126
+ unlinked: z.ZodObject<{
127
+ commands: z.ZodNumber;
128
+ files: z.ZodNumber;
129
+ commits: z.ZodNumber;
130
+ }, z.core.$strip>;
131
+ }, z.core.$strip>;
132
+ export type AuditList = z.output<typeof AuditListSchema>;
133
+ export declare const listAudit: import("../../kernel/define.js").QueryDef<z.ZodObject<{
134
+ days: z.ZodDefault<z.ZodNumber>;
135
+ kind: z.ZodDefault<z.ZodEnum<{
136
+ file: "file";
137
+ all: "all";
138
+ session: "session";
139
+ commit: "commit";
140
+ proc: "proc";
141
+ guard: "guard";
142
+ }>>;
143
+ session: z.ZodOptional<z.ZodString>;
144
+ agent: z.ZodOptional<z.ZodString>;
145
+ project: z.ZodOptional<z.ZodString>;
146
+ grep: z.ZodOptional<z.ZodString>;
147
+ limit: z.ZodDefault<z.ZodNumber>;
148
+ }, z.core.$strip>, z.ZodObject<{
149
+ enabled: z.ZodBoolean;
150
+ keepDays: z.ZodNumber;
151
+ maxMb: z.ZodNumber;
152
+ bytes: z.ZodNumber;
153
+ folder: z.ZodString;
154
+ filter: z.ZodObject<{
155
+ days: z.ZodNumber;
156
+ kind: z.ZodEnum<{
157
+ file: "file";
158
+ all: "all";
159
+ session: "session";
160
+ commit: "commit";
161
+ proc: "proc";
162
+ guard: "guard";
163
+ }>;
164
+ session: z.ZodOptional<z.ZodString>;
165
+ agent: z.ZodOptional<z.ZodString>;
166
+ project: z.ZodOptional<z.ZodString>;
167
+ grep: z.ZodOptional<z.ZodString>;
168
+ }, z.core.$strip>;
169
+ matched: z.ZodNumber;
170
+ events: z.ZodArray<z.ZodObject<{
171
+ time: z.ZodString;
172
+ kind: z.ZodEnum<{
173
+ file: "file";
174
+ session: "session";
175
+ note: "note";
176
+ commit: "commit";
177
+ proc: "proc";
178
+ guard: "guard";
179
+ }>;
180
+ what: z.ZodString;
181
+ command: z.ZodOptional<z.ZodString>;
182
+ parent: z.ZodOptional<z.ZodString>;
183
+ action: z.ZodOptional<z.ZodString>;
184
+ folder: z.ZodOptional<z.ZodString>;
185
+ project: z.ZodOptional<z.ZodString>;
186
+ session: z.ZodOptional<z.ZodString>;
187
+ agent: z.ZodOptional<z.ZodString>;
188
+ linked: z.ZodOptional<z.ZodEnum<{
189
+ process: "process";
190
+ "only-session": "only-session";
191
+ }>>;
192
+ count: z.ZodNumber;
193
+ sha: z.ZodOptional<z.ZodString>;
194
+ author: z.ZodOptional<z.ZodString>;
195
+ }, z.core.$strip>>;
196
+ totals: z.ZodObject<{
197
+ commands: z.ZodNumber;
198
+ files: z.ZodNumber;
199
+ commits: z.ZodNumber;
200
+ events: z.ZodNumber;
201
+ sessions: z.ZodNumber;
202
+ }, z.core.$strip>;
203
+ agents: z.ZodArray<z.ZodObject<{
204
+ commands: z.ZodNumber;
205
+ files: z.ZodNumber;
206
+ commits: z.ZodNumber;
207
+ agent: z.ZodString;
208
+ sessions: z.ZodNumber;
209
+ }, z.core.$strip>>;
210
+ sessions: z.ZodArray<z.ZodObject<{
211
+ commands: z.ZodNumber;
212
+ files: z.ZodNumber;
213
+ commits: z.ZodNumber;
214
+ id: z.ZodString;
215
+ agent: z.ZodString;
216
+ project: z.ZodString;
217
+ started: z.ZodString;
218
+ ended: z.ZodOptional<z.ZodString>;
219
+ last: z.ZodOptional<z.ZodString>;
220
+ }, z.core.$strip>>;
221
+ unlinked: z.ZodObject<{
222
+ commands: z.ZodNumber;
223
+ files: z.ZodNumber;
224
+ commits: z.ZodNumber;
225
+ }, z.core.$strip>;
226
+ }, z.core.$strip>, "audit.list">;
227
+ /** "14:03:22" today, "Oct 18 14:03" before (local time). */
228
+ export declare function eventTime(iso: string, now?: number): string;
229
+ /** The first few characters of a session id (enough to tell sessions apart, and to filter by). */
230
+ export declare function shortId(id: string): string;
231
+ /** What an event says, in one line. */
232
+ export declare function eventWhat(e: AuditRow): string;
233
+ /** The page: the period's totals, per agent, the sessions (each opens its own events), and the events. Pure. */
234
+ export declare function auditPage(o: AuditList): Page;
235
+ /** The command line that shows what a view address of this page shows (the menu runs it on the normal screen). */
236
+ export declare function auditArgv(params?: Readonly<Record<string, string>>): string[];
237
+ /** What the view's address can set. */
238
+ export interface AuditParams {
239
+ readonly days?: string;
240
+ readonly kind?: string;
241
+ readonly session?: string;
242
+ readonly agent?: string;
243
+ readonly project?: string;
244
+ readonly grep?: string;
245
+ }
246
+ export declare const auditView: import("../../kernel/define.js").ViewDef<{
247
+ audit: import("../../kernel/define.js").QueryDef<z.ZodObject<{
248
+ days: z.ZodDefault<z.ZodNumber>;
249
+ kind: z.ZodDefault<z.ZodEnum<{
250
+ file: "file";
251
+ all: "all";
252
+ session: "session";
253
+ commit: "commit";
254
+ proc: "proc";
255
+ guard: "guard";
256
+ }>>;
257
+ session: z.ZodOptional<z.ZodString>;
258
+ agent: z.ZodOptional<z.ZodString>;
259
+ project: z.ZodOptional<z.ZodString>;
260
+ grep: z.ZodOptional<z.ZodString>;
261
+ limit: z.ZodDefault<z.ZodNumber>;
262
+ }, z.core.$strip>, z.ZodObject<{
263
+ enabled: z.ZodBoolean;
264
+ keepDays: z.ZodNumber;
265
+ maxMb: z.ZodNumber;
266
+ bytes: z.ZodNumber;
267
+ folder: z.ZodString;
268
+ filter: z.ZodObject<{
269
+ days: z.ZodNumber;
270
+ kind: z.ZodEnum<{
271
+ file: "file";
272
+ all: "all";
273
+ session: "session";
274
+ commit: "commit";
275
+ proc: "proc";
276
+ guard: "guard";
277
+ }>;
278
+ session: z.ZodOptional<z.ZodString>;
279
+ agent: z.ZodOptional<z.ZodString>;
280
+ project: z.ZodOptional<z.ZodString>;
281
+ grep: z.ZodOptional<z.ZodString>;
282
+ }, z.core.$strip>;
283
+ matched: z.ZodNumber;
284
+ events: z.ZodArray<z.ZodObject<{
285
+ time: z.ZodString;
286
+ kind: z.ZodEnum<{
287
+ file: "file";
288
+ session: "session";
289
+ note: "note";
290
+ commit: "commit";
291
+ proc: "proc";
292
+ guard: "guard";
293
+ }>;
294
+ what: z.ZodString;
295
+ command: z.ZodOptional<z.ZodString>;
296
+ parent: z.ZodOptional<z.ZodString>;
297
+ action: z.ZodOptional<z.ZodString>;
298
+ folder: z.ZodOptional<z.ZodString>;
299
+ project: z.ZodOptional<z.ZodString>;
300
+ session: z.ZodOptional<z.ZodString>;
301
+ agent: z.ZodOptional<z.ZodString>;
302
+ linked: z.ZodOptional<z.ZodEnum<{
303
+ process: "process";
304
+ "only-session": "only-session";
305
+ }>>;
306
+ count: z.ZodNumber;
307
+ sha: z.ZodOptional<z.ZodString>;
308
+ author: z.ZodOptional<z.ZodString>;
309
+ }, z.core.$strip>>;
310
+ totals: z.ZodObject<{
311
+ commands: z.ZodNumber;
312
+ files: z.ZodNumber;
313
+ commits: z.ZodNumber;
314
+ events: z.ZodNumber;
315
+ sessions: z.ZodNumber;
316
+ }, z.core.$strip>;
317
+ agents: z.ZodArray<z.ZodObject<{
318
+ commands: z.ZodNumber;
319
+ files: z.ZodNumber;
320
+ commits: z.ZodNumber;
321
+ agent: z.ZodString;
322
+ sessions: z.ZodNumber;
323
+ }, z.core.$strip>>;
324
+ sessions: z.ZodArray<z.ZodObject<{
325
+ commands: z.ZodNumber;
326
+ files: z.ZodNumber;
327
+ commits: z.ZodNumber;
328
+ id: z.ZodString;
329
+ agent: z.ZodString;
330
+ project: z.ZodString;
331
+ started: z.ZodString;
332
+ ended: z.ZodOptional<z.ZodString>;
333
+ last: z.ZodOptional<z.ZodString>;
334
+ }, z.core.$strip>>;
335
+ unlinked: z.ZodObject<{
336
+ commands: z.ZodNumber;
337
+ files: z.ZodNumber;
338
+ commits: z.ZodNumber;
339
+ }, z.core.$strip>;
340
+ }, z.core.$strip>, "audit.list">;
341
+ }, AuditParams, "audit">;