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
@@ -25570,14 +25570,19 @@ var NetworkSchema = external_exports.strictObject({
25570
25570
  });
25571
25571
  var AuditSchema = external_exports.strictObject({
25572
25572
  enabled: external_exports.boolean().describe(
25573
- "Keep an audit log on this PC of what happened in your sandboxes: programs started (with their command lines), files changed in the project, sessions, and what the repo guard caught. The sandbox cannot change it. Read it with sandbox audit."
25573
+ "Keep an audit log on this PC of what your agents did: programs started (with their command lines, secrets hidden), files changed in the projects, git commits, sessions, and what the repo guard caught, each linked to the agent session that did it where that can be known. The sandbox cannot change it. Read it with sandbox audit or on the Activity page."
25574
+ ),
25575
+ days: external_exports.number().int().min(1).max(365).describe(
25576
+ "Days the audit log is kept (1 to 30; a larger number keeps 30); older days are deleted when a sandbox starts and once a day."
25574
25577
  ),
25575
- days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
25576
25578
  maxMb: external_exports.number().int().min(5).max(5e3).describe("Most space the audit log may take, in MB (older days go first). Days before today are compressed."),
25577
25579
  processes: external_exports.boolean().describe(
25578
25580
  "Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."
25579
25581
  ),
25580
- files: external_exports.boolean().describe("Record the files changed in the project while the sandbox runs.")
25582
+ files: external_exports.boolean().describe("Record the files changed in the projects while the sandbox runs."),
25583
+ commits: external_exports.boolean().describe(
25584
+ "Record the git commits made in the projects while the sandbox runs (read from each project's .git folder on this PC)."
25585
+ )
25581
25586
  });
25582
25587
  var WorkspaceFilterSchema = external_exports.strictObject({
25583
25588
  enabled: external_exports.boolean().describe(
@@ -25780,7 +25785,100 @@ var ToolchainsSchema = external_exports.strictObject({
25780
25785
 
25781
25786
  // src/shared/apps/catalogue.ts
25782
25787
  var gh = (github, asset) => ({ github, asset });
25788
+ var RTK_VERSION = "1.0.1";
25789
+ var RTK_URL = "https://github.com/rtk-ai/rtk/releases/download/v" + RTK_VERSION + "/rtk-oss-x86_64-pc-windows-msvc.zip";
25790
+ var RTK_SHA256 = "0e53e2eca471e15fbd3636e64e6bc0b182cbc278ed0339c80450a2dd03f4cd6b";
25791
+ var HEADROOM_VERSION = "0.41.0";
25792
+ var CCUSAGE_VERSION = "20.0.36";
25793
+ var PLAYWRIGHT_MCP_VERSION = "0.0.83";
25794
+ var CONTEXT7_MCP_VERSION = "4.4.2";
25783
25795
  var APPS = [
25796
+ // ---- agent add-ons
25797
+ {
25798
+ id: "rtk",
25799
+ name: "rtk (Rust Token Killer)",
25800
+ category: "agents",
25801
+ about: "Compacts the output of shell commands (git, tests, builds, ls ...) before the agent reads it, so it uses fewer tokens. Claude Code's Bash commands go through it on their own.",
25802
+ size: "6 MB",
25803
+ source: { url: RTK_URL, sha256: RTK_SHA256 },
25804
+ exe: "rtk.exe",
25805
+ cli: true,
25806
+ plugsInto: "Claude Code through a hook in the sandbox's managed settings; other agents are told to use it",
25807
+ userOnly: true
25808
+ },
25809
+ {
25810
+ id: "headroom",
25811
+ name: "Headroom",
25812
+ category: "agents",
25813
+ about: "Compresses what Claude Code sends to the model (tool output, logs, files) so it uses fewer tokens: a local proxy on 127.0.0.1:8787 that sits in Claude Code's API path, offline apart from forwarding to api.anthropic.com.",
25814
+ size: "150 MB",
25815
+ source: { locked: "uv", package: "headroom-ai", version: HEADROOM_VERSION },
25816
+ exe: "headroom.exe",
25817
+ service: true,
25818
+ plugsInto: "Claude Code: the sandbox starts the proxy and points Claude Code at it (managed settings)",
25819
+ userOnly: true
25820
+ },
25821
+ {
25822
+ id: "ccusage",
25823
+ name: "ccusage",
25824
+ category: "agents",
25825
+ about: "Reports the agents' token use and cost by day, month or session from their logs in the sandbox (`ccusage daily`; add --offline to skip fetching prices).",
25826
+ size: "5 MB",
25827
+ source: { locked: "npm", package: "ccusage", version: CCUSAGE_VERSION },
25828
+ exe: "ccusage.cmd",
25829
+ cli: true,
25830
+ plugsInto: "Reads Claude Code's session logs in the sandbox; changes nothing",
25831
+ userOnly: true
25832
+ },
25833
+ {
25834
+ id: "playwright-mcp",
25835
+ name: "Playwright MCP",
25836
+ category: "agents",
25837
+ about: "Lets Claude Code drive a browser (Microsoft Edge, already in the sandbox) to open pages, click, fill forms and take screenshots: the MCP server of microsoft/playwright-mcp.",
25838
+ size: "20 MB",
25839
+ source: { locked: "npm", package: "@playwright/mcp", version: PLAYWRIGHT_MCP_VERSION },
25840
+ exe: "playwright-mcp.cmd",
25841
+ service: true,
25842
+ mcp: { name: "sbx-playwright", script: "node_modules/@playwright/mcp/cli.js", args: ["--browser", "msedge"] },
25843
+ plugsInto: "Claude Code as the MCP server sbx-playwright (the sandbox's Claude settings)",
25844
+ userOnly: true
25845
+ },
25846
+ {
25847
+ id: "context7",
25848
+ name: "Context7 MCP",
25849
+ category: "agents",
25850
+ about: "Up-to-date documentation and code examples for libraries, looked up by Claude Code while it works (upstash/context7). The library names and questions go to Upstash's context7.com.",
25851
+ size: "55 MB",
25852
+ source: { locked: "npm", package: "@upstash/context7-mcp", version: CONTEXT7_MCP_VERSION },
25853
+ exe: "context7-mcp.cmd",
25854
+ service: true,
25855
+ mcp: { name: "sbx-context7", script: "node_modules/@upstash/context7-mcp/dist/index.js" },
25856
+ plugsInto: "Claude Code as the MCP server sbx-context7 (the sandbox's Claude settings)",
25857
+ userOnly: true
25858
+ },
25859
+ {
25860
+ id: "claude-mem",
25861
+ name: "claude-mem",
25862
+ category: "agents",
25863
+ about: "Persistent memory for Claude Code (a plugin you install on this PC): its database is brought into the sandbox.",
25864
+ size: "",
25865
+ source: { resolve: "setting" },
25866
+ exe: "",
25867
+ setting: "claudeProfile.syncClaudeMem",
25868
+ plugsInto: "Claude Code, with your Claude settings copied from this PC",
25869
+ userOnly: true
25870
+ },
25871
+ {
25872
+ id: "rea",
25873
+ name: "REA (Reverse Engineer Anything)",
25874
+ category: "agents",
25875
+ about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
25876
+ size: "8 MB",
25877
+ source: { npm: "rea-agents" },
25878
+ exe: "rea.cmd",
25879
+ cli: true,
25880
+ plugsInto: "Claude Code and Codex as an MCP server, after `rea setup`"
25881
+ },
25784
25882
  // ---- editors
25785
25883
  {
25786
25884
  id: "vscode",
@@ -26242,16 +26340,6 @@ var APPS = [
26242
26340
  cli: true
26243
26341
  },
26244
26342
  // ---- reverse engineering
26245
- {
26246
- id: "rea",
26247
- name: "REA (Reverse Engineer Anything)",
26248
- category: "reversing",
26249
- about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
26250
- size: "8 MB",
26251
- source: { npm: "rea-agents" },
26252
- exe: "rea.cmd",
26253
- cli: true
26254
- },
26255
26343
  {
26256
26344
  id: "ghidra",
26257
26345
  name: "Ghidra",
@@ -26531,6 +26619,8 @@ var APPS = [
26531
26619
  // src/core/schema/apps.ts
26532
26620
  var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
26533
26621
  var AppIdSchema = external_exports.enum(CATALOGUE_IDS);
26622
+ var PROJECT_IDS = APPS.filter((a) => !a.setting && !a.userOnly).map((a) => a.id);
26623
+ var ProjectAppIdSchema = external_exports.enum(PROJECT_IDS);
26534
26624
  var CustomAppIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
26535
26625
  var compiles = (pattern) => {
26536
26626
  try {
@@ -26554,6 +26644,11 @@ var CustomAppSchema = external_exports.strictObject({
26554
26644
  }).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, {
26555
26645
  message: "give github + asset, or url (not both)"
26556
26646
  });
26647
+ var ProjectAppsSchema = external_exports.strictObject({
26648
+ install: external_exports.array(ProjectAppIdSchema).describe(
26649
+ "Apps from the catalogue this project adds to yours (agent add-ons such as rtk, Headroom and the MCP servers are set in your own settings only)."
26650
+ )
26651
+ });
26557
26652
  var AppsSchema = external_exports.strictObject({
26558
26653
  install: external_exports.array(AppIdSchema).describe(
26559
26654
  "Apps from the catalogue to install in every sandbox (the Apps screen in the menu lists them by category). Each is downloaded once and kept."
@@ -26718,8 +26813,8 @@ var LocalOverridesSchema = external_exports.strictObject({
26718
26813
  attach: AttachSchema.partial(),
26719
26814
  personalization: toggle("Copy your desktop look into the sandbox.").partial(),
26720
26815
  // Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
26721
- // them.
26722
- apps: AppsSchema.pick({ install: true }).partial(),
26816
+ // them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
26817
+ apps: ProjectAppsSchema.partial(),
26723
26818
  claudeProfile: ClaudeProfileSchema.pick({
26724
26819
  enabled: true,
26725
26820
  overwrite: true,
@@ -25969,14 +25969,19 @@ var NetworkSchema = external_exports.strictObject({
25969
25969
  });
25970
25970
  var AuditSchema = external_exports.strictObject({
25971
25971
  enabled: external_exports.boolean().describe(
25972
- "Keep an audit log on this PC of what happened in your sandboxes: programs started (with their command lines), files changed in the project, sessions, and what the repo guard caught. The sandbox cannot change it. Read it with sandbox audit."
25972
+ "Keep an audit log on this PC of what your agents did: programs started (with their command lines, secrets hidden), files changed in the projects, git commits, sessions, and what the repo guard caught, each linked to the agent session that did it where that can be known. The sandbox cannot change it. Read it with sandbox audit or on the Activity page."
25973
+ ),
25974
+ days: external_exports.number().int().min(1).max(365).describe(
25975
+ "Days the audit log is kept (1 to 30; a larger number keeps 30); older days are deleted when a sandbox starts and once a day."
25973
25976
  ),
25974
- days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
25975
25977
  maxMb: external_exports.number().int().min(5).max(5e3).describe("Most space the audit log may take, in MB (older days go first). Days before today are compressed."),
25976
25978
  processes: external_exports.boolean().describe(
25977
25979
  "Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."
25978
25980
  ),
25979
- files: external_exports.boolean().describe("Record the files changed in the project while the sandbox runs.")
25981
+ files: external_exports.boolean().describe("Record the files changed in the projects while the sandbox runs."),
25982
+ commits: external_exports.boolean().describe(
25983
+ "Record the git commits made in the projects while the sandbox runs (read from each project's .git folder on this PC)."
25984
+ )
25980
25985
  });
25981
25986
  var WorkspaceFilterSchema = external_exports.strictObject({
25982
25987
  enabled: external_exports.boolean().describe(
@@ -26179,7 +26184,100 @@ var ToolchainsSchema = external_exports.strictObject({
26179
26184
 
26180
26185
  // src/shared/apps/catalogue.ts
26181
26186
  var gh = (github, asset) => ({ github, asset });
26187
+ var RTK_VERSION = "1.0.1";
26188
+ var RTK_URL = "https://github.com/rtk-ai/rtk/releases/download/v" + RTK_VERSION + "/rtk-oss-x86_64-pc-windows-msvc.zip";
26189
+ var RTK_SHA256 = "0e53e2eca471e15fbd3636e64e6bc0b182cbc278ed0339c80450a2dd03f4cd6b";
26190
+ var HEADROOM_VERSION = "0.41.0";
26191
+ var CCUSAGE_VERSION = "20.0.36";
26192
+ var PLAYWRIGHT_MCP_VERSION = "0.0.83";
26193
+ var CONTEXT7_MCP_VERSION = "4.4.2";
26182
26194
  var APPS = [
26195
+ // ---- agent add-ons
26196
+ {
26197
+ id: "rtk",
26198
+ name: "rtk (Rust Token Killer)",
26199
+ category: "agents",
26200
+ about: "Compacts the output of shell commands (git, tests, builds, ls ...) before the agent reads it, so it uses fewer tokens. Claude Code's Bash commands go through it on their own.",
26201
+ size: "6 MB",
26202
+ source: { url: RTK_URL, sha256: RTK_SHA256 },
26203
+ exe: "rtk.exe",
26204
+ cli: true,
26205
+ plugsInto: "Claude Code through a hook in the sandbox's managed settings; other agents are told to use it",
26206
+ userOnly: true
26207
+ },
26208
+ {
26209
+ id: "headroom",
26210
+ name: "Headroom",
26211
+ category: "agents",
26212
+ about: "Compresses what Claude Code sends to the model (tool output, logs, files) so it uses fewer tokens: a local proxy on 127.0.0.1:8787 that sits in Claude Code's API path, offline apart from forwarding to api.anthropic.com.",
26213
+ size: "150 MB",
26214
+ source: { locked: "uv", package: "headroom-ai", version: HEADROOM_VERSION },
26215
+ exe: "headroom.exe",
26216
+ service: true,
26217
+ plugsInto: "Claude Code: the sandbox starts the proxy and points Claude Code at it (managed settings)",
26218
+ userOnly: true
26219
+ },
26220
+ {
26221
+ id: "ccusage",
26222
+ name: "ccusage",
26223
+ category: "agents",
26224
+ about: "Reports the agents' token use and cost by day, month or session from their logs in the sandbox (`ccusage daily`; add --offline to skip fetching prices).",
26225
+ size: "5 MB",
26226
+ source: { locked: "npm", package: "ccusage", version: CCUSAGE_VERSION },
26227
+ exe: "ccusage.cmd",
26228
+ cli: true,
26229
+ plugsInto: "Reads Claude Code's session logs in the sandbox; changes nothing",
26230
+ userOnly: true
26231
+ },
26232
+ {
26233
+ id: "playwright-mcp",
26234
+ name: "Playwright MCP",
26235
+ category: "agents",
26236
+ about: "Lets Claude Code drive a browser (Microsoft Edge, already in the sandbox) to open pages, click, fill forms and take screenshots: the MCP server of microsoft/playwright-mcp.",
26237
+ size: "20 MB",
26238
+ source: { locked: "npm", package: "@playwright/mcp", version: PLAYWRIGHT_MCP_VERSION },
26239
+ exe: "playwright-mcp.cmd",
26240
+ service: true,
26241
+ mcp: { name: "sbx-playwright", script: "node_modules/@playwright/mcp/cli.js", args: ["--browser", "msedge"] },
26242
+ plugsInto: "Claude Code as the MCP server sbx-playwright (the sandbox's Claude settings)",
26243
+ userOnly: true
26244
+ },
26245
+ {
26246
+ id: "context7",
26247
+ name: "Context7 MCP",
26248
+ category: "agents",
26249
+ about: "Up-to-date documentation and code examples for libraries, looked up by Claude Code while it works (upstash/context7). The library names and questions go to Upstash's context7.com.",
26250
+ size: "55 MB",
26251
+ source: { locked: "npm", package: "@upstash/context7-mcp", version: CONTEXT7_MCP_VERSION },
26252
+ exe: "context7-mcp.cmd",
26253
+ service: true,
26254
+ mcp: { name: "sbx-context7", script: "node_modules/@upstash/context7-mcp/dist/index.js" },
26255
+ plugsInto: "Claude Code as the MCP server sbx-context7 (the sandbox's Claude settings)",
26256
+ userOnly: true
26257
+ },
26258
+ {
26259
+ id: "claude-mem",
26260
+ name: "claude-mem",
26261
+ category: "agents",
26262
+ about: "Persistent memory for Claude Code (a plugin you install on this PC): its database is brought into the sandbox.",
26263
+ size: "",
26264
+ source: { resolve: "setting" },
26265
+ exe: "",
26266
+ setting: "claudeProfile.syncClaudeMem",
26267
+ plugsInto: "Claude Code, with your Claude settings copied from this PC",
26268
+ userOnly: true
26269
+ },
26270
+ {
26271
+ id: "rea",
26272
+ name: "REA (Reverse Engineer Anything)",
26273
+ category: "agents",
26274
+ about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
26275
+ size: "8 MB",
26276
+ source: { npm: "rea-agents" },
26277
+ exe: "rea.cmd",
26278
+ cli: true,
26279
+ plugsInto: "Claude Code and Codex as an MCP server, after `rea setup`"
26280
+ },
26183
26281
  // ---- editors
26184
26282
  {
26185
26283
  id: "vscode",
@@ -26641,16 +26739,6 @@ var APPS = [
26641
26739
  cli: true
26642
26740
  },
26643
26741
  // ---- reverse engineering
26644
- {
26645
- id: "rea",
26646
- name: "REA (Reverse Engineer Anything)",
26647
- category: "reversing",
26648
- about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
26649
- size: "8 MB",
26650
- source: { npm: "rea-agents" },
26651
- exe: "rea.cmd",
26652
- cli: true
26653
- },
26654
26742
  {
26655
26743
  id: "ghidra",
26656
26744
  name: "Ghidra",
@@ -26930,6 +27018,8 @@ var APPS = [
26930
27018
  // src/core/schema/apps.ts
26931
27019
  var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
26932
27020
  var AppIdSchema = external_exports.enum(CATALOGUE_IDS);
27021
+ var PROJECT_IDS = APPS.filter((a) => !a.setting && !a.userOnly).map((a) => a.id);
27022
+ var ProjectAppIdSchema = external_exports.enum(PROJECT_IDS);
26933
27023
  var CustomAppIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
26934
27024
  var compiles = (pattern) => {
26935
27025
  try {
@@ -26953,6 +27043,11 @@ var CustomAppSchema = external_exports.strictObject({
26953
27043
  }).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, {
26954
27044
  message: "give github + asset, or url (not both)"
26955
27045
  });
27046
+ var ProjectAppsSchema = external_exports.strictObject({
27047
+ install: external_exports.array(ProjectAppIdSchema).describe(
27048
+ "Apps from the catalogue this project adds to yours (agent add-ons such as rtk, Headroom and the MCP servers are set in your own settings only)."
27049
+ )
27050
+ });
26956
27051
  var AppsSchema = external_exports.strictObject({
26957
27052
  install: external_exports.array(AppIdSchema).describe(
26958
27053
  "Apps from the catalogue to install in every sandbox (the Apps screen in the menu lists them by category). Each is downloaded once and kept."
@@ -27117,8 +27212,8 @@ var LocalOverridesSchema = external_exports.strictObject({
27117
27212
  attach: AttachSchema.partial(),
27118
27213
  personalization: toggle("Copy your desktop look into the sandbox.").partial(),
27119
27214
  // Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
27120
- // them.
27121
- apps: AppsSchema.pick({ install: true }).partial(),
27215
+ // them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
27216
+ apps: ProjectAppsSchema.partial(),
27122
27217
  claudeProfile: ClaudeProfileSchema.pick({
27123
27218
  enabled: true,
27124
27219
  overwrite: true,
@@ -17,7 +17,7 @@ import { DEFAULTS } from '../core/config/index.js';
17
17
  import { sandboxPage } from '../app/features/sandbox/index.js';
18
18
  import { sessionsPage } from '../app/features/sessions/index.js';
19
19
  import { APP_GROUPS, appsPage, listApps } from '../app/features/apps/index.js';
20
- import { settingsPage } from '../app/features/settings/index.js';
20
+ import { keepShownSecrets, settingsPage } from '../app/features/settings/index.js';
21
21
  import { checkEngine, checkText, enginePage } from '../app/features/engine/index.js';
22
22
  import { runUpdate, updatesPage } from '../app/features/updates/index.js';
23
23
  import { MenuOperations } from '../cli/menu/io-menu.js';
@@ -384,6 +384,8 @@ export const appSuite = {
384
384
  edit.op === 'settings.set' &&
385
385
  edit.fields?.[0]?.name === 'value' &&
386
386
  page.sections.some((s) => s.items?.some((i) => i.id === '@data-folder')), 'the settings page: a section per category, each setting edited through its Field');
387
+ t.section('a secret shown as *** is never saved as ***');
388
+ t.equal(keepShownSecrets({ API_KEY: 'sk-real', LOG: 'debug' }, { API_KEY: '***', LOG: 'info', NEW_KEY: '***' }), { API_KEY: 'sk-real', LOG: 'info', NEW_KEY: '***' }, 'a map edited in the web keeps the saved secret where *** came back, and takes the rest as typed');
387
389
  t.section('settings export and import, run against a config file');
388
390
  const exportFile = t.at('app-settings', 'out.json');
389
391
  const exported = (await runDefinition('settings.export', ctx, { settingsFile: exportFile }, fakeIO().io));
@@ -428,6 +430,28 @@ export const appSuite = {
428
430
  const offText = fs.readFileSync(appsConfig, 'utf8');
429
431
  t.check(onText.includes('"lazygit"') && !offText.includes('"lazygit"'), 'apps: turning an app on writes apps.install, off removes it');
430
432
  await t.throws(() => runDefinition('apps.toggle', appsCtx, { scope: 'project', id: 'vscode', on: false }, quiet), 'is not an app this scope can change', 'apps: a project cannot change VS Code');
433
+ await t.throws(() => runDefinition('apps.toggle', appsCtx, { scope: 'project', id: 'rtk', on: true }, quiet), 'is not an app this scope can change', 'apps: a project cannot turn rtk on (it hooks every agent command)');
434
+ for (const id of ['headroom', 'ccusage', 'playwright-mcp', 'context7'])
435
+ await t.throws(() => runDefinition('apps.toggle', appsCtx, { scope: 'project', id, on: true }, quiet), 'is not an app this scope can change', 'apps: a project cannot turn ' + id + ' on (an agent add-on: your own settings only)');
436
+ const projectApps = (await readQuery(listApps, appsCtx, { scope: 'project' }));
437
+ const userApps = (await readQuery(listApps, appsCtx, { scope: 'user' }));
438
+ const mem = userApps.apps.find((a) => a.id === 'claude-mem');
439
+ const addons = appsPage(userApps).sections.find((s) => s.id === 'agents');
440
+ t.check(!projectApps.apps.some((a) => a.id === 'rtk' || a.id === 'claude-mem') &&
441
+ userApps.apps.find((a) => a.id === 'rtk')?.group === 'agents' &&
442
+ mem?.group === 'agents' &&
443
+ mem.setting === 'claudeProfile.syncClaudeMem' &&
444
+ mem.settingField?.kind === 'boolean' &&
445
+ mem.on === true &&
446
+ addons?.title === 'Agent add-ons' &&
447
+ (addons.items ?? []).some((i) => i.id === 'rtk') &&
448
+ (addons.items ?? []).some((i) => i.id === 'claude-mem' && !(i.details ?? []).some((d) => d.startsWith('Download'))), 'apps: an Agent add-ons section with rtk and claude-mem (its own setting, nothing to download); not in a project');
449
+ const headroomItem = (addons?.items ?? []).find((i) => i.id === 'headroom');
450
+ t.check(['headroom', 'ccusage', 'playwright-mcp', 'context7'].every((id) => (addons?.items ?? []).some((i) => i.id === id) &&
451
+ !projectApps.apps.some((a) => a.id === id) &&
452
+ userApps.apps.find((a) => a.id === id)?.on === false) &&
453
+ (headroomItem?.details ?? []).some((d) => d.includes('no shortcut, not on PATH')) &&
454
+ (headroomItem?.details ?? []).some((d) => d.startsWith('Plugs in')), 'apps: Headroom, ccusage, Playwright MCP and Context7 are agent add-ons, off by default, not in a project');
431
455
  const dataDir = t.dir('app-apps', 'data');
432
456
  fs.mkdirSync(path.join(dataDir, 'tools', 'apps', 'lazygit'), { recursive: true });
433
457
  fs.writeFileSync(path.join(dataDir, 'tools', 'apps', 'lazygit', '.agent-sandbox-app'), 'lazygit');