windows-development-sandbox 1.0.5 → 1.4.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/LICENSE +21 -0
- package/README.md +25 -8
- package/config.example.json +55 -5
- package/dist/api.js +2 -1
- package/dist/cli/args.d.ts +23 -0
- package/dist/cli/args.js +38 -4
- package/dist/cli/colors.d.ts +24 -0
- package/dist/cli/colors.js +42 -0
- package/dist/cli/commands/accounts.js +2 -2
- package/dist/cli/commands/agent-commands.d.ts +6 -0
- package/dist/cli/commands/agent-commands.js +61 -0
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +5 -1
- package/dist/cli/commands/data/clean.d.ts +15 -0
- package/dist/cli/commands/data/clean.js +106 -0
- package/dist/cli/commands/data/collect.d.ts +11 -0
- package/dist/cli/commands/data/collect.js +54 -0
- package/dist/cli/commands/data/index.d.ts +4 -0
- package/dist/cli/commands/data/index.js +45 -0
- package/dist/cli/commands/data/remove.d.ts +2 -0
- package/dist/cli/commands/data/remove.js +30 -0
- package/dist/cli/commands/index.d.ts +6 -4
- package/dist/cli/commands/index.js +6 -4
- package/dist/cli/commands/launch.d.ts +26 -2
- package/dist/cli/commands/launch.js +256 -42
- package/dist/cli/commands/maintenance.d.ts +2 -0
- package/dist/cli/commands/maintenance.js +67 -5
- package/dist/cli/commands/project.d.ts +29 -0
- package/dist/cli/commands/project.js +63 -0
- package/dist/cli/commands/projects.d.ts +14 -0
- package/dist/cli/commands/projects.js +146 -0
- package/dist/cli/commands/repair/checks.d.ts +2 -0
- package/dist/cli/commands/{repair.js → repair/checks.js} +19 -181
- package/dist/cli/commands/{repair.d.ts → repair/finders.d.ts} +0 -29
- package/dist/cli/commands/repair/finders.js +108 -0
- package/dist/cli/commands/repair/index.d.ts +12 -0
- package/dist/cli/commands/repair/index.js +61 -0
- package/dist/cli/commands/repair/types.d.ts +26 -0
- package/dist/cli/commands/repair/types.js +3 -0
- package/dist/cli/commands/restart.d.ts +6 -0
- package/dist/cli/commands/restart.js +85 -0
- package/dist/cli/commands/sessions.d.ts +2 -1
- package/dist/cli/commands/sessions.js +189 -45
- package/dist/cli/commands/setup/checks.d.ts +13 -0
- package/dist/cli/commands/setup/checks.js +71 -0
- package/dist/cli/commands/{setup.d.ts → setup/facts.d.ts} +1 -15
- package/dist/cli/commands/setup/facts.js +60 -0
- package/dist/cli/commands/setup/index.d.ts +2 -0
- package/dist/cli/commands/setup/index.js +43 -0
- package/dist/cli/commands/user-config.d.ts +8 -0
- package/dist/cli/commands/user-config.js +41 -0
- package/dist/cli/history.d.ts +11 -0
- package/dist/cli/history.js +21 -0
- package/dist/cli/index.d.ts +7 -1
- package/dist/cli/index.js +42 -15
- package/dist/cli/manifest.d.ts +8 -0
- package/dist/cli/manifest.js +40 -15
- package/dist/cli/menu/apps.d.ts +21 -0
- package/dist/cli/menu/apps.js +122 -0
- package/dist/cli/menu/command-form.d.ts +28 -0
- package/dist/cli/menu/command-form.js +219 -0
- package/dist/cli/menu/index.d.ts +26 -0
- package/dist/cli/menu/index.js +180 -0
- package/dist/cli/menu/settings/categories.d.ts +9 -0
- package/dist/cli/menu/settings/categories.js +28 -0
- package/dist/cli/menu/settings/config-file.d.ts +40 -0
- package/dist/cli/menu/settings/config-file.js +71 -0
- package/dist/cli/menu/settings/editors.d.ts +30 -0
- package/dist/cli/menu/settings/editors.js +305 -0
- package/dist/cli/menu/settings/index.d.ts +32 -0
- package/dist/cli/menu/settings/index.js +136 -0
- package/dist/cli/menu/settings/schema-node.d.ts +62 -0
- package/dist/cli/menu/settings/schema-node.js +104 -0
- package/dist/cli/menu/several.d.ts +20 -0
- package/dist/cli/menu/several.js +102 -0
- package/dist/cli/progress.d.ts +9 -0
- package/dist/cli/progress.js +49 -0
- package/dist/cli/tui/app.d.ts +39 -0
- package/dist/cli/tui/app.js +52 -0
- package/dist/cli/tui/dialogs.d.ts +57 -0
- package/dist/cli/tui/dialogs.js +162 -0
- package/dist/cli/tui/frame.d.ts +18 -0
- package/dist/cli/tui/frame.js +27 -0
- package/dist/cli/tui/index.d.ts +7 -0
- package/dist/cli/tui/index.js +8 -0
- package/dist/cli/tui/list-screen.d.ts +101 -0
- package/dist/cli/tui/list-screen.js +299 -0
- package/dist/cli/tui/terminal.d.ts +37 -0
- package/dist/cli/tui/terminal.js +89 -0
- package/dist/cli/tui/text.d.ts +20 -0
- package/dist/cli/tui/text.js +105 -0
- package/dist/cli/tui/theme.d.ts +45 -0
- package/dist/cli/tui/theme.js +30 -0
- package/dist/cli/validate.d.ts +17 -0
- package/dist/cli/validate.js +89 -0
- package/dist/core/config.js +12 -6
- package/dist/core/disk.d.ts +16 -0
- package/dist/core/disk.js +55 -0
- package/dist/core/local-config.d.ts +23 -0
- package/dist/core/local-config.js +79 -7
- package/dist/core/project-policy.d.ts +15 -0
- package/dist/core/project-policy.js +35 -0
- package/dist/core/prompt.d.ts +4 -0
- package/dist/core/prompt.js +15 -0
- package/dist/core/safe-paths.d.ts +4 -0
- package/dist/core/safe-paths.js +37 -0
- package/dist/core/schema/apps.d.ts +40 -0
- package/dist/core/schema/apps.js +27 -0
- package/dist/core/schema/common.d.ts +17 -0
- package/dist/core/schema/common.js +15 -0
- package/dist/core/schema/config.d.ts +659 -0
- package/dist/core/schema/config.js +75 -0
- package/dist/core/schema/databases.d.ts +33 -0
- package/dist/core/schema/databases.js +35 -0
- package/dist/core/schema/harness.d.ts +12 -0
- package/dist/core/schema/harness.js +17 -0
- package/dist/core/schema/json-schema.d.ts +5 -0
- package/dist/core/schema/json-schema.js +25 -0
- package/dist/core/schema/profile.d.ts +32 -0
- package/dist/core/schema/profile.js +31 -0
- package/dist/core/schema/projects.d.ts +9 -0
- package/dist/core/schema/projects.js +11 -0
- package/dist/core/schema/sandbox.d.ts +78 -0
- package/dist/core/schema/sandbox.js +64 -0
- package/dist/core/schema/toolchains.d.ts +96 -0
- package/dist/core/schema/toolchains.js +88 -0
- package/dist/core/schema.d.ts +6 -604
- package/dist/core/schema.js +8 -264
- package/dist/core/types.d.ts +35 -1
- package/dist/core/util.d.ts +9 -0
- package/dist/core/util.js +14 -3
- package/dist/core/workspace.d.ts +0 -5
- package/dist/core/workspace.js +33 -50
- package/dist/guest/apps/index.d.ts +10 -0
- package/dist/guest/apps/index.js +206 -0
- package/dist/guest/apps/resolvers.d.ts +8 -0
- package/dist/guest/apps/resolvers.js +90 -0
- package/dist/guest/audit-parse.d.ts +7 -0
- package/dist/guest/audit-parse.js +24 -0
- package/dist/guest/audit.d.ts +4 -0
- package/dist/guest/audit.js +47 -0
- package/dist/guest/boot-env.d.ts +4 -0
- package/dist/guest/boot-env.js +25 -0
- package/dist/guest/cmdline.d.ts +12 -0
- package/dist/guest/cmdline.js +23 -0
- package/dist/guest/daemon/exec.d.ts +5 -0
- package/dist/guest/daemon/exec.js +32 -0
- package/dist/guest/daemon/project.d.ts +14 -0
- package/dist/guest/daemon/project.js +132 -0
- package/dist/guest/daemon/relays.d.ts +1 -0
- package/dist/guest/daemon/relays.js +18 -0
- package/dist/guest/daemon/session.d.ts +13 -0
- package/dist/guest/daemon/session.js +139 -0
- package/dist/guest/daemon/shutdown.d.ts +1 -0
- package/dist/guest/daemon/shutdown.js +21 -0
- package/dist/guest/daemon/state.d.ts +17 -0
- package/dist/guest/daemon/state.js +31 -0
- package/dist/guest/daemon.js +12 -141
- package/dist/guest/db.js +18 -3
- package/dist/guest/env.d.ts +3 -0
- package/dist/guest/env.js +7 -3
- package/dist/guest/guide.d.ts +6 -2
- package/dist/guest/guide.js +5 -4
- package/dist/guest/helpers.d.ts +3 -0
- package/dist/guest/helpers.js +26 -0
- package/dist/guest/main.js +31 -8
- package/dist/guest/netproxy.d.ts +1 -0
- package/dist/guest/netproxy.js +100 -0
- package/dist/guest/ports.d.ts +6 -0
- package/dist/guest/ports.js +22 -0
- package/dist/guest/project-context.d.ts +7 -0
- package/dist/guest/project-context.js +10 -0
- package/dist/guest/project-env.d.ts +20 -0
- package/dist/guest/project-env.js +20 -0
- package/dist/guest/project-status.d.ts +5 -0
- package/dist/guest/project-status.js +17 -0
- package/dist/guest/ptyhost.d.ts +0 -18
- package/dist/guest/ptyhost.js +17 -65
- package/dist/guest/setup/agents.d.ts +5 -2
- package/dist/guest/setup/agents.js +22 -8
- package/dist/guest/setup/claude.d.ts +0 -4
- package/dist/guest/setup/claude.js +59 -5
- package/dist/guest/setup/environment.d.ts +13 -3
- package/dist/guest/setup/environment.js +14 -10
- package/dist/guest/setup/hooks.d.ts +9 -1
- package/dist/guest/setup/hooks.js +28 -14
- package/dist/guest/setup/network.d.ts +9 -0
- package/dist/guest/setup/network.js +97 -4
- package/dist/guest/setup/user.js +4 -0
- package/dist/guest/toolchains/catalogue.d.ts +4 -0
- package/dist/guest/toolchains/catalogue.js +2 -2
- package/dist/guest/toolchains/cli.js +25 -17
- package/dist/guest/toolchains/common.d.ts +18 -1
- package/dist/guest/toolchains/common.js +34 -11
- package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
- package/dist/guest/toolchains/databases/dynamodb.js +52 -0
- package/dist/guest/toolchains/{databases.d.ts → databases/index.d.ts} +2 -3
- package/dist/guest/toolchains/databases/index.js +62 -0
- package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
- package/dist/guest/toolchains/databases/mongodb.js +31 -0
- package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
- package/dist/guest/toolchains/databases/mysql.js +38 -0
- package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
- package/dist/guest/toolchains/databases/postgres.js +38 -0
- package/dist/guest/toolchains/databases/redis.d.ts +3 -0
- package/dist/guest/toolchains/databases/redis.js +16 -0
- package/dist/guest/toolchains/databases/server.d.ts +14 -0
- package/dist/guest/toolchains/databases/server.js +52 -0
- package/dist/guest/toolchains/git.js +25 -16
- package/dist/guest/toolchains/go.js +1 -1
- package/dist/guest/toolchains/index.d.ts +13 -9
- package/dist/guest/toolchains/index.js +40 -82
- package/dist/guest/toolchains/java.js +5 -5
- package/dist/guest/toolchains/leftovers.d.ts +2 -0
- package/dist/guest/toolchains/leftovers.js +26 -0
- package/dist/guest/toolchains/managers.js +12 -10
- package/dist/guest/toolchains/{binstall.js → native/binstall.js} +6 -9
- package/dist/guest/toolchains/native/cpp.d.ts +4 -0
- package/dist/guest/toolchains/native/cpp.js +38 -0
- package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
- package/dist/guest/toolchains/native/dotnet.js +103 -0
- package/dist/guest/toolchains/native/mesa.d.ts +7 -0
- package/dist/guest/toolchains/native/mesa.js +56 -0
- package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
- package/dist/guest/toolchains/native/msvc/environment.js +57 -0
- package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/index.js +48 -0
- package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/packages.js +156 -0
- package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
- package/dist/guest/toolchains/native/msvc/tree.js +21 -0
- package/dist/guest/toolchains/native/rust.d.ts +3 -0
- package/dist/guest/toolchains/native/rust.js +45 -0
- package/dist/guest/toolchains/node.js +26 -6
- package/dist/guest/toolchains/plan.d.ts +24 -0
- package/dist/guest/toolchains/plan.js +140 -0
- package/dist/guest/toolchains/pwsh.js +1 -1
- package/dist/guest/toolchains/python.js +43 -12
- package/dist/guest/toolchains/runtimes.d.ts +2 -0
- package/dist/guest/toolchains/runtimes.js +6 -8
- package/dist/guest/toolchains/scripting/php.d.ts +3 -0
- package/dist/guest/toolchains/scripting/php.js +71 -0
- package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
- package/dist/guest/toolchains/scripting/ruby.js +47 -0
- package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
- package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
- package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
- package/dist/guest/toolchains/vscode-profile.js +69 -0
- package/dist/guest/toolchains/vscode.d.ts +17 -0
- package/dist/guest/toolchains/vscode.js +87 -1
- package/dist/guest/view.js +21 -1
- package/dist/host/accounts.js +14 -5
- package/dist/host/agent-commands.d.ts +25 -0
- package/dist/host/agent-commands.js +145 -0
- package/dist/host/attach.d.ts +17 -0
- package/dist/host/attach.js +70 -0
- package/dist/host/audit/collect.d.ts +34 -0
- package/dist/host/audit/collect.js +126 -0
- package/dist/host/audit/log.d.ts +46 -0
- package/dist/host/audit/log.js +143 -0
- package/dist/host/channel.d.ts +23 -22
- package/dist/host/channel.js +66 -84
- package/dist/host/claude-profile.js +7 -3
- package/dist/host/cleanup.js +2 -11
- package/dist/host/database-plan.d.ts +12 -0
- package/dist/host/database-plan.js +52 -0
- package/dist/host/generate.d.ts +10 -12
- package/dist/host/generate.js +58 -135
- package/dist/host/join.d.ts +28 -0
- package/dist/host/join.js +76 -0
- package/dist/host/launch/mappings.d.ts +3 -0
- package/dist/host/launch/mappings.js +54 -0
- package/dist/host/launch/projects.d.ts +15 -0
- package/dist/host/launch/projects.js +56 -0
- package/dist/host/launch/stage.d.ts +11 -0
- package/dist/host/launch/stage.js +66 -0
- package/dist/host/launch/wsb.d.ts +10 -0
- package/dist/host/launch/wsb.js +34 -0
- package/dist/host/motw.d.ts +17 -0
- package/dist/host/motw.js +74 -0
- package/dist/host/pc-scan.d.ts +6 -0
- package/dist/host/pc-scan.js +37 -0
- package/dist/host/platform.d.ts +2 -0
- package/dist/host/platform.js +16 -1
- package/dist/host/port-forward.d.ts +8 -0
- package/dist/host/port-forward.js +37 -0
- package/dist/host/project-scan.d.ts +1 -17
- package/dist/host/project-scan.js +2 -86
- package/dist/host/projects.d.ts +100 -0
- package/dist/host/projects.js +147 -0
- package/dist/host/repo-guard.d.ts +25 -5
- package/dist/host/repo-guard.js +242 -23
- package/dist/host/stops.d.ts +67 -0
- package/dist/host/stops.js +126 -0
- package/dist/host/terminal.d.ts +8 -0
- package/dist/host/terminal.js +48 -1
- package/dist/host/test-guard.d.ts +6 -0
- package/dist/host/test-guard.js +15 -0
- package/dist/host/window.js +7 -3
- package/dist/host/workspace-view/index.d.ts +20 -0
- package/dist/host/workspace-view/index.js +53 -0
- package/dist/host/workspace-view/rules.d.ts +26 -0
- package/dist/host/workspace-view/rules.js +93 -0
- package/dist/host/workspace-view/view.d.ts +50 -0
- package/dist/host/workspace-view/view.js +281 -0
- package/dist/host/wsb.d.ts +37 -0
- package/dist/host/wsb.js +101 -0
- package/dist/runtime/daemon.js +11791 -2821
- package/dist/runtime/db.js +6585 -466
- package/dist/runtime/main.js +10238 -1724
- package/dist/runtime/netproxy.js +25936 -0
- package/dist/runtime/view.js +6183 -59
- package/dist/selftest/accounts.test.d.ts +2 -0
- package/dist/selftest/accounts.test.js +44 -0
- package/dist/selftest/agent-commands.test.d.ts +2 -0
- package/dist/selftest/agent-commands.test.js +47 -0
- package/dist/selftest/audit.test.d.ts +2 -0
- package/dist/selftest/audit.test.js +57 -0
- package/dist/selftest/channel.test.d.ts +2 -0
- package/dist/selftest/channel.test.js +44 -0
- package/dist/selftest/cli.test.d.ts +2 -2
- package/dist/selftest/cli.test.js +145 -27
- package/dist/selftest/cmdline.test.d.ts +2 -0
- package/dist/selftest/cmdline.test.js +45 -0
- package/dist/selftest/config.test.d.ts +2 -3
- package/dist/selftest/config.test.js +36 -72
- package/dist/selftest/data.test.d.ts +2 -2
- package/dist/selftest/data.test.js +77 -70
- package/dist/selftest/detect.test.d.ts +2 -2
- package/dist/selftest/detect.test.js +54 -38
- package/dist/selftest/fixtures.d.ts +89 -4
- package/dist/selftest/fixtures.js +43 -24
- package/dist/selftest/generate.test.d.ts +2 -0
- package/dist/selftest/generate.test.js +68 -0
- package/dist/selftest/git-access.test.d.ts +2 -0
- package/dist/selftest/git-access.test.js +26 -0
- package/dist/selftest/guest-boot.test.d.ts +2 -0
- package/dist/selftest/guest-boot.test.js +76 -0
- package/dist/selftest/harness.d.ts +44 -7
- package/dist/selftest/harness.js +62 -21
- package/dist/selftest/host-sim.test.d.ts +2 -0
- package/dist/selftest/host-sim.test.js +93 -0
- package/dist/selftest/hostile-input.test.d.ts +2 -0
- package/dist/selftest/hostile-input.test.js +54 -0
- package/dist/selftest/index.d.ts +8 -1
- package/dist/selftest/index.js +137 -35
- package/dist/selftest/links.test.d.ts +2 -0
- package/dist/selftest/links.test.js +50 -0
- package/dist/selftest/live-daemon.test.d.ts +2 -0
- package/dist/selftest/live-daemon.test.js +91 -0
- package/dist/selftest/live-git.test.d.ts +2 -0
- package/dist/selftest/live-git.test.js +60 -0
- package/dist/selftest/live-network.test.d.ts +2 -0
- package/dist/selftest/live-network.test.js +63 -0
- package/dist/selftest/live-projects.test.d.ts +2 -0
- package/dist/selftest/live-projects.test.js +127 -0
- package/dist/selftest/live.d.ts +65 -0
- package/dist/selftest/live.js +109 -0
- package/dist/selftest/local-config.test.d.ts +2 -0
- package/dist/selftest/local-config.test.js +120 -0
- package/dist/selftest/mirror.test.d.ts +2 -3
- package/dist/selftest/mirror.test.js +92 -65
- package/dist/selftest/network.test.d.ts +2 -0
- package/dist/selftest/network.test.js +40 -0
- package/dist/selftest/personalization.test.d.ts +2 -0
- package/dist/selftest/personalization.test.js +53 -0
- package/dist/selftest/projects.test.d.ts +2 -0
- package/dist/selftest/projects.test.js +254 -0
- package/dist/selftest/repair.test.d.ts +2 -0
- package/dist/selftest/repair.test.js +42 -0
- package/dist/selftest/repo-guard.test.d.ts +2 -0
- package/dist/selftest/repo-guard.test.js +121 -0
- package/dist/selftest/secrets.test.d.ts +2 -0
- package/dist/selftest/secrets.test.js +71 -0
- package/dist/selftest/setup.test.d.ts +2 -2
- package/dist/selftest/setup.test.js +45 -22
- package/dist/selftest/suite.d.ts +13 -0
- package/dist/selftest/suite.js +1 -0
- package/dist/selftest/sync.test.d.ts +2 -3
- package/dist/selftest/sync.test.js +130 -78
- package/dist/selftest/test-guard.test.d.ts +2 -0
- package/dist/selftest/test-guard.test.js +49 -0
- package/dist/selftest/toolchains.test.d.ts +2 -0
- package/dist/selftest/toolchains.test.js +133 -0
- package/dist/selftest/workspace-view.test.d.ts +2 -0
- package/dist/selftest/workspace-view.test.js +89 -0
- package/dist/selftest/workspace.test.d.ts +2 -0
- package/dist/selftest/workspace.test.js +53 -0
- package/dist/shared/apps.d.ts +49 -0
- package/dist/shared/apps.js +114 -0
- package/dist/shared/download.d.ts +3 -1
- package/dist/shared/download.js +19 -4
- package/dist/shared/netpolicy.d.ts +27 -0
- package/dist/shared/netpolicy.js +51 -0
- package/dist/shared/paths.d.ts +5 -0
- package/dist/shared/paths.js +6 -0
- package/dist/shared/projects.d.ts +53 -0
- package/dist/shared/projects.js +67 -0
- package/dist/shared/pty-client.d.ts +9 -4
- package/dist/shared/pty-client.js +139 -17
- package/dist/shared/rundir.d.ts +12 -1
- package/dist/shared/rundir.js +14 -4
- package/dist/shared/safe-remove.js +11 -0
- package/dist/shared/schema.d.ts +453 -0
- package/dist/shared/schema.js +43 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/test-guard.d.ts +4 -0
- package/dist/shared/test-guard.js +37 -0
- package/dist/sync/claude-mem.js +6 -3
- package/dist/sync/history.d.ts +29 -12
- package/dist/sync/history.js +72 -25
- package/dist/sync/watcher.d.ts +8 -0
- package/dist/sync/watcher.js +99 -8
- package/package.json +7 -6
- package/sandbox/bootstrap.ps1 +258 -258
- package/sandbox/cargoshim.cs +56 -0
- package/sandbox/cpucap.cs +33 -0
- package/sandbox/cpucap.ps1 +20 -0
- package/sandbox/logon.cmd +24 -16
- package/sandbox/memlog.ps1 +34 -0
- package/sandbox/openssl.cs +42 -0
- package/sandbox/pagefile.cs +31 -0
- package/sandbox/pagefile.ps1 +21 -0
- package/sandbox/ptyhost.cs +120 -11
- package/sandbox/trust.cmd +35 -35
- package/schemas/config.schema.json +403 -3
- package/schemas/sandbox-config.schema.json +143 -13
- package/dist/cli/commands/data.d.ts +0 -46
- package/dist/cli/commands/data.js +0 -249
- package/dist/cli/commands/setup.js +0 -152
- package/dist/cli/menu.d.ts +0 -22
- package/dist/cli/menu.js +0 -187
- package/dist/cli/settings.d.ts +0 -11
- package/dist/cli/settings.js +0 -156
- package/dist/guest/toolchains/databases.js +0 -226
- package/dist/guest/toolchains/msvc.d.ts +0 -10
- package/dist/guest/toolchains/msvc.js +0 -216
- package/dist/guest/toolchains/native.d.ts +0 -12
- package/dist/guest/toolchains/native.js +0 -220
- package/dist/guest/toolchains/scripting.d.ts +0 -10
- package/dist/guest/toolchains/scripting.js +0 -137
- package/dist/selftest/guest.test.d.ts +0 -3
- package/dist/selftest/guest.test.js +0 -61
- package/dist/selftest/helpers.test.d.ts +0 -2
- package/dist/selftest/helpers.test.js +0 -125
- package/dist/selftest/host.test.d.ts +0 -2
- package/dist/selftest/host.test.js +0 -71
- package/dist/selftest/live.test.d.ts +0 -7
- package/dist/selftest/live.test.js +0 -127
- package/dist/selftest/security.test.d.ts +0 -3
- package/dist/selftest/security.test.js +0 -143
- /package/dist/guest/toolchains/{binstall.d.ts → native/binstall.d.ts} +0 -0
package/dist/sync/history.d.ts
CHANGED
|
@@ -1,24 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { projectFolderName, translatePaths } from '../shared/paths.js';
|
|
2
3
|
export { projectFolderName, translatePaths };
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
declare const SyncStateSchema: z.ZodObject<{
|
|
5
|
+
hostClaudeDir: z.ZodString;
|
|
6
|
+
hostWorkspace: z.ZodString;
|
|
7
|
+
guestWorkspace: z.ZodString;
|
|
8
|
+
syncHistory: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
syncClaudeMem: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
syncClaudeMemBack: z.ZodOptional<z.ZodBoolean>;
|
|
11
|
+
historyScope: z.ZodOptional<z.ZodEnum<{
|
|
12
|
+
project: "project";
|
|
13
|
+
all: "all";
|
|
14
|
+
}>>;
|
|
15
|
+
memHostStamp: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
memGuestStamp: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
projects: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
18
|
+
hostWorkspace: z.ZodString;
|
|
19
|
+
guestWorkspace: z.ZodString;
|
|
20
|
+
}, z.core.$strip>>>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type SyncState = z.output<typeof SyncStateSchema>;
|
|
23
|
+
export interface WorkspacePair {
|
|
6
24
|
hostWorkspace: string;
|
|
7
25
|
guestWorkspace: string;
|
|
8
|
-
syncHistory?: boolean;
|
|
9
|
-
syncClaudeMem?: boolean;
|
|
10
|
-
/** Newest claude-mem database time on each side right after the last sync (detects edits on both sides). */
|
|
11
|
-
memHostStamp?: number;
|
|
12
|
-
memGuestStamp?: number;
|
|
13
26
|
}
|
|
14
|
-
|
|
27
|
+
/** extra: projects registered after boot (C:\Projects\<name> -> their real folder on this PC). */
|
|
28
|
+
export interface SyncPaths extends WorkspacePair {
|
|
15
29
|
hostClaudeDir: string;
|
|
16
30
|
guestClaudeDir: string;
|
|
17
|
-
|
|
18
|
-
guestWorkspace: string;
|
|
31
|
+
extra?: WorkspacePair[];
|
|
19
32
|
}
|
|
20
33
|
/** Brings this PC's history into the sandbox state (run before the sandbox starts). Returns files copied. */
|
|
21
|
-
export declare const syncHistoryIn: (p: SyncPaths
|
|
34
|
+
export declare const syncHistoryIn: (p: SyncPaths, options?: {
|
|
35
|
+
promptHistory?: boolean;
|
|
36
|
+
scope?: "project" | "all";
|
|
37
|
+
}) => number;
|
|
22
38
|
/** Copies new sandbox history back to this PC (safe while the sandbox runs: transcripts are append-only). */
|
|
23
39
|
export declare const syncHistoryOut: (p: SyncPaths) => number;
|
|
24
40
|
/**
|
|
@@ -26,5 +42,6 @@ export declare const syncHistoryOut: (p: SyncPaths) => number;
|
|
|
26
42
|
* never live in the data folder the sandbox can write (a forged copy could redirect writes anywhere on this PC).
|
|
27
43
|
*/
|
|
28
44
|
export declare const syncStatePath: (dataPath: string) => string;
|
|
45
|
+
/** A state file that is missing, oversized or not in this shape counts as no state (nothing syncs back until the next launch). */
|
|
29
46
|
export declare const readSyncState: (dataPath: string) => SyncState | null;
|
|
30
47
|
export declare const writeSyncState: (dataPath: string, state: SyncState) => void;
|
package/dist/sync/history.js
CHANGED
|
@@ -7,17 +7,33 @@
|
|
|
7
7
|
//
|
|
8
8
|
// Safety (the sandbox side is untrusted):
|
|
9
9
|
// - links are never followed or written through, on either side;
|
|
10
|
-
// - what comes BACK is limited to transcripts (.jsonl)
|
|
11
|
-
// size, and never Claude's memory folders.
|
|
10
|
+
// - what comes BACK is limited to the sandbox's own projects: their transcripts (.jsonl) and prompt-history lines,
|
|
11
|
+
// plus to-do lists (.json), each capped in size, and never Claude's memory folders. A sandbox cannot plant a
|
|
12
|
+
// conversation for another project on this PC (claude --resume there would load it);
|
|
13
|
+
// - what goes IN is, by default (historyScope "project"), only the sandbox's own projects: other projects'
|
|
14
|
+
// conversations, file backups and prompts are not the agent's business.
|
|
12
15
|
import fs from 'node:fs';
|
|
13
16
|
import path from 'node:path';
|
|
14
17
|
import _ from 'lodash';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { guestWorkspaceAliases, isSafeFileName, projectFolderName, translatePaths } from '../shared/paths.js';
|
|
20
|
+
import { readValid, writeJsonAtomic } from '../shared/rundir.js';
|
|
21
|
+
import { assertTestWritable } from '../host/test-guard.js';
|
|
22
|
+
import { dirExists, ensureDir, fileExists, isLink, removeLink } from '../core/util.js';
|
|
17
23
|
export { projectFolderName, translatePaths };
|
|
18
24
|
const SESSION_DIRS = ['todos', 'plans', 'file-history'];
|
|
19
25
|
const DATA_FILE = /\.(jsonl?|txt|md)$/i;
|
|
20
26
|
const MAX_FILE_BYTES = 100 * 1024 * 1024;
|
|
27
|
+
/** Host-only record of the last launch: which folders map to each other and what syncs (from the effective config). */
|
|
28
|
+
const AbsolutePath = z.string().max(1024).refine((p) => path.isAbsolute(p), 'must be an absolute path');
|
|
29
|
+
const SyncStateSchema = z.object({
|
|
30
|
+
hostClaudeDir: AbsolutePath, hostWorkspace: AbsolutePath, guestWorkspace: z.string().max(1024),
|
|
31
|
+
syncHistory: z.boolean().optional(), syncClaudeMem: z.boolean().optional(), syncClaudeMemBack: z.boolean().optional(), historyScope: z.enum(['project', 'all']).optional(),
|
|
32
|
+
/** Newest claude-mem database time on each side right after the last sync (detects edits on both sides). */
|
|
33
|
+
memHostStamp: z.number().optional(), memGuestStamp: z.number().optional(),
|
|
34
|
+
/** Projects registered while the sandbox ran (their history goes back to their own folders). */
|
|
35
|
+
projects: z.array(z.object({ hostWorkspace: AbsolutePath, guestWorkspace: z.string().max(1024) })).max(256).optional(),
|
|
36
|
+
});
|
|
21
37
|
const anyFile = () => true;
|
|
22
38
|
const transcript = (name) => name.endsWith('.jsonl');
|
|
23
39
|
const json = (name) => name.endsWith('.json');
|
|
@@ -43,6 +59,8 @@ const copyNewer = (from, to, options = {}) => {
|
|
|
43
59
|
return 0;
|
|
44
60
|
const accept = options.accept ?? anyFile;
|
|
45
61
|
return _.sumBy(fs.readdirSync(from, { withFileTypes: true }), (entry) => {
|
|
62
|
+
if (!isSafeFileName(entry.name))
|
|
63
|
+
return 0;
|
|
46
64
|
const source = path.join(from, entry.name);
|
|
47
65
|
const destination = path.join(to, entry.name);
|
|
48
66
|
if (entry.isDirectory())
|
|
@@ -69,26 +87,52 @@ const copyNewer = (from, to, options = {}) => {
|
|
|
69
87
|
});
|
|
70
88
|
};
|
|
71
89
|
const readLines = (file) => fileExists(file) && !isLink(file) && fs.statSync(file).size <= MAX_FILE_BYTES ? fs.readFileSync(file, 'utf8').split(/\r?\n/).filter((l) => l.trim() !== '') : [];
|
|
90
|
+
const isJsonObject = (line) => { try {
|
|
91
|
+
const v = JSON.parse(line);
|
|
92
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
} };
|
|
97
|
+
/** A prompt-history line whose project is one of `workspaces` (on this PC's side). */
|
|
98
|
+
const inProjects = (line, workspaces) => {
|
|
99
|
+
try {
|
|
100
|
+
const project = JSON.parse(line).project;
|
|
101
|
+
return typeof project === 'string' && workspaces.some((w) => path.resolve(w).toLowerCase() === path.resolve(project).toLowerCase());
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
72
107
|
const lineTime = (line) => { try {
|
|
73
108
|
return Number(JSON.parse(line).timestamp) || 0;
|
|
74
109
|
}
|
|
75
110
|
catch {
|
|
76
111
|
return 0;
|
|
77
112
|
} };
|
|
113
|
+
/** Every workspace pair of the sandbox: the launch folder's, then the projects registered later (most specific first). */
|
|
114
|
+
const pairsOf = (p) => _.sortBy([{ hostWorkspace: p.hostWorkspace, guestWorkspace: p.guestWorkspace }, ...(p.extra ?? [])], (x) => -x.hostWorkspace.length);
|
|
115
|
+
const translateAll = (text, pairs) => pairs.reduce((out, [from, to]) => translatePaths(out, from, to), text);
|
|
78
116
|
/** Brings this PC's history into the sandbox state (run before the sandbox starts). Returns files copied. */
|
|
79
|
-
export const syncHistoryIn = (p) => {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const
|
|
117
|
+
export const syncHistoryIn = (p, options = {}) => {
|
|
118
|
+
const all = options.scope === 'all';
|
|
119
|
+
assertTestWritable(p.guestClaudeDir);
|
|
120
|
+
const pairs = pairsOf(p);
|
|
121
|
+
const byHost = new Map(pairs.map((x) => [projectFolderName(x.hostWorkspace), projectFolderName(x.guestWorkspace)]));
|
|
122
|
+
const guestNames = new Set(pairs.map((x) => projectFolderName(x.guestWorkspace)));
|
|
123
|
+
const transform = (t) => translateAll(t, pairs.map((x) => [x.hostWorkspace, x.guestWorkspace]));
|
|
83
124
|
const hostProjects = path.join(p.hostClaudeDir, 'projects');
|
|
84
|
-
const names = dirExists(hostProjects) ? fs.readdirSync(hostProjects).filter((name) => name
|
|
85
|
-
const projects = _.sumBy(names, (name) => name
|
|
86
|
-
? copyNewer(path.join(hostProjects, name), path.join(p.guestClaudeDir, 'projects',
|
|
125
|
+
const names = dirExists(hostProjects) ? fs.readdirSync(hostProjects).filter((name) => isSafeFileName(name) && (all ? !guestNames.has(name) || byHost.has(name) : byHost.has(name))) : [];
|
|
126
|
+
const projects = _.sumBy(names, (name) => byHost.has(name)
|
|
127
|
+
? copyNewer(path.join(hostProjects, name), path.join(p.guestClaudeDir, 'projects', byHost.get(name)), { transform })
|
|
87
128
|
: copyNewer(path.join(hostProjects, name), path.join(p.guestClaudeDir, 'projects', name)));
|
|
88
|
-
|
|
129
|
+
// To-do lists, plans and file backups are kept by session, not by project: only with historyScope "all".
|
|
130
|
+
const sessions = all ? _.sumBy(SESSION_DIRS, (dir) => copyNewer(path.join(p.hostClaudeDir, dir), path.join(p.guestClaudeDir, dir))) : 0;
|
|
131
|
+
if (options.promptHistory === false)
|
|
132
|
+
return projects + sessions;
|
|
89
133
|
// Prompt history: rebuild the sandbox copy from this PC's file plus anything only the sandbox has.
|
|
90
134
|
const target = path.join(p.guestClaudeDir, 'history.jsonl');
|
|
91
|
-
const hostLines = readLines(path.join(p.hostClaudeDir, 'history.jsonl')).map(transform);
|
|
135
|
+
const hostLines = readLines(path.join(p.hostClaudeDir, 'history.jsonl')).filter((l) => all || inProjects(l, pairs.map((x) => x.hostWorkspace))).map(transform);
|
|
92
136
|
const known = new Set(hostLines);
|
|
93
137
|
const merged = _.sortBy([...hostLines, ...readLines(target).filter((l) => !known.has(l))], lineTime);
|
|
94
138
|
if (merged.length) {
|
|
@@ -99,21 +143,23 @@ export const syncHistoryIn = (p) => {
|
|
|
99
143
|
};
|
|
100
144
|
/** Copies new sandbox history back to this PC (safe while the sandbox runs: transcripts are append-only). */
|
|
101
145
|
export const syncHistoryOut = (p) => {
|
|
102
|
-
|
|
103
|
-
// A mirrored workspace on F: really lives at C:\Mirror\F\...; tools that resolve real paths record that one.
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const
|
|
146
|
+
assertTestWritable(p.hostClaudeDir);
|
|
147
|
+
// A mirrored workspace on F: really lives at C:\Mirror\F\...; tools that resolve real paths record that one. A
|
|
148
|
+
// project registered later is in the hub (C:\Projects\<name>) and goes back to its real folder on this PC.
|
|
149
|
+
const pairs = pairsOf(p).flatMap((x) => guestWorkspaceAliases(x.guestWorkspace).map((guest) => [guest, x.hostWorkspace]));
|
|
150
|
+
const byGuest = new Map(pairs.map(([guest, host]) => [projectFolderName(guest), projectFolderName(host)]));
|
|
151
|
+
const transform = (t) => translateAll(t, pairs);
|
|
107
152
|
const guestProjectsDir = path.join(p.guestClaudeDir, 'projects');
|
|
108
|
-
const names = dirExists(guestProjectsDir) && !isLink(guestProjectsDir) ? fs.readdirSync(guestProjectsDir) : [];
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
: copyNewer(path.join(guestProjectsDir, name), path.join(p.hostClaudeDir, 'projects', name), { accept: transcript, skipDirs: NO_MEMORY }));
|
|
153
|
+
const names = dirExists(guestProjectsDir) && !isLink(guestProjectsDir) ? fs.readdirSync(guestProjectsDir).filter(isSafeFileName) : [];
|
|
154
|
+
// Only this sandbox's projects: a transcript under any other folder name would be planted into that project on this PC.
|
|
155
|
+
const projects = _.sumBy(names.filter((name) => byGuest.has(name)), (name) => copyNewer(path.join(guestProjectsDir, name), path.join(p.hostClaudeDir, 'projects', byGuest.get(name)), { accept: transcript, skipDirs: NO_MEMORY, transform }));
|
|
112
156
|
// Only to-do lists come back besides transcripts; plans and file backups stay in the sandbox.
|
|
113
157
|
const sessions = copyNewer(path.join(p.guestClaudeDir, 'todos'), path.join(p.hostClaudeDir, 'todos'), { accept: json });
|
|
114
158
|
const hostFile = path.join(p.hostClaudeDir, 'history.jsonl');
|
|
115
159
|
const known = new Set(readLines(hostFile));
|
|
116
|
-
|
|
160
|
+
// Only prompt-history entries (one JSON object per line) of this sandbox's projects come back.
|
|
161
|
+
const hostWorkspaces = pairsOf(p).map((x) => x.hostWorkspace);
|
|
162
|
+
const missing = readLines(path.join(p.guestClaudeDir, 'history.jsonl')).filter(isJsonObject).map(transform).filter((l) => inProjects(l, hostWorkspaces) && !known.has(l));
|
|
117
163
|
if (missing.length) {
|
|
118
164
|
ensureDir(p.hostClaudeDir);
|
|
119
165
|
fs.appendFileSync(hostFile, missing.join('\n') + '\n', 'utf8');
|
|
@@ -125,5 +171,6 @@ export const syncHistoryOut = (p) => {
|
|
|
125
171
|
* never live in the data folder the sandbox can write (a forged copy could redirect writes anywhere on this PC).
|
|
126
172
|
*/
|
|
127
173
|
export const syncStatePath = (dataPath) => path.join(path.dirname(path.dirname(dataPath)), 'sync', path.basename(dataPath) + '.json');
|
|
128
|
-
|
|
129
|
-
export const
|
|
174
|
+
/** A state file that is missing, oversized or not in this shape counts as no state (nothing syncs back until the next launch). */
|
|
175
|
+
export const readSyncState = (dataPath) => readValid(SyncStateSchema, syncStatePath(dataPath));
|
|
176
|
+
export const writeSyncState = (dataPath, state) => writeJsonAtomic(syncStatePath(dataPath), state);
|
package/dist/sync/watcher.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { Config } from '../core/types.js';
|
|
2
2
|
import { type MemResult } from './claude-mem.js';
|
|
3
|
+
/**
|
|
4
|
+
* A project registered while the sandbox runs: its history comes in now (the sandbox's copy only gains files), and
|
|
5
|
+
* from now on syncs back to its own folder on this PC.
|
|
6
|
+
*/
|
|
7
|
+
export declare const syncProjectIn: (dataPath: string, project: {
|
|
8
|
+
hostWorkspace: string;
|
|
9
|
+
guestWorkspace: string;
|
|
10
|
+
}) => number;
|
|
3
11
|
export interface SyncSummary {
|
|
4
12
|
history: number;
|
|
5
13
|
claudeMem: MemResult | 'disabled';
|
package/dist/sync/watcher.js
CHANGED
|
@@ -3,10 +3,18 @@
|
|
|
3
3
|
// Its pid file and log live in host-only storage, never in the data folder the sandbox can write.
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
+
import { writeFileAtomic } from '../shared/rundir.js';
|
|
7
|
+
import { refuseInSelfTest } from '../host/test-guard.js';
|
|
6
8
|
import { assertNoLinks, errMsg, sleep } from '../core/util.js';
|
|
7
9
|
import { hostClaudeDir } from '../host/claude-profile.js';
|
|
8
10
|
import { checkRepo } from '../host/repo-guard.js';
|
|
9
11
|
import { isSandboxRunning } from '../host/platform.js';
|
|
12
|
+
import { readActiveViews, WorkspaceView } from '../host/workspace-view/index.js';
|
|
13
|
+
import { readForwards, sandboxAddress, startPortForwards } from '../host/port-forward.js';
|
|
14
|
+
import { AuditCollector, readAuditSettings } from '../host/audit/collect.js';
|
|
15
|
+
import { readMarkedProjects, saveDataSize, watchAndMark } from '../host/motw.js';
|
|
16
|
+
import { sizeOf } from '../core/disk.js';
|
|
17
|
+
import { beatLife, causeSince, endLife, keepAwake, readLife } from '../host/stops.js';
|
|
10
18
|
import { hostClaudeMemDir, syncClaudeMem } from './claude-mem.js';
|
|
11
19
|
import { readSyncState, syncHistoryIn, syncHistoryOut, writeSyncState } from './history.js';
|
|
12
20
|
const WATCH_INTERVAL_MS = 60 * 1000;
|
|
@@ -16,7 +24,21 @@ const guestMem = (dataPath) => path.join(dataPath, 'state', 'claude-mem');
|
|
|
16
24
|
/** Sync paths for the sandbox side, after checking nothing on the way there is a link planted by the sandbox. */
|
|
17
25
|
const toPaths = (state, dataPath) => {
|
|
18
26
|
assertNoLinks(dataPath, guestClaude(dataPath));
|
|
19
|
-
return { hostClaudeDir: state.hostClaudeDir, guestClaudeDir: guestClaude(dataPath), hostWorkspace: state.hostWorkspace, guestWorkspace: state.guestWorkspace };
|
|
27
|
+
return { hostClaudeDir: state.hostClaudeDir, guestClaudeDir: guestClaude(dataPath), hostWorkspace: state.hostWorkspace, guestWorkspace: state.guestWorkspace, extra: state.projects ?? [] };
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A project registered while the sandbox runs: its history comes in now (the sandbox's copy only gains files), and
|
|
31
|
+
* from now on syncs back to its own folder on this PC.
|
|
32
|
+
*/
|
|
33
|
+
export const syncProjectIn = (dataPath, project) => {
|
|
34
|
+
const state = readSyncState(dataPath);
|
|
35
|
+
if (!state)
|
|
36
|
+
return 0;
|
|
37
|
+
const projects = [...(state.projects ?? []).filter((p) => p.hostWorkspace.toLowerCase() !== project.hostWorkspace.toLowerCase()), project];
|
|
38
|
+
const next = { ...state, projects };
|
|
39
|
+
writeSyncState(dataPath, next);
|
|
40
|
+
// Prompt history is left alone: sessions are appending to the sandbox's copy right now.
|
|
41
|
+
return state.syncHistory ? syncHistoryIn(toPaths(next, dataPath), { promptHistory: false, scope: state.historyScope }) : 0;
|
|
20
42
|
};
|
|
21
43
|
const memSync = (dataPath, state, direction) => {
|
|
22
44
|
assertNoLinks(dataPath, guestMem(dataPath));
|
|
@@ -31,11 +53,11 @@ export const syncBeforeLaunch = (config, dataPath, hostWorkspace) => {
|
|
|
31
53
|
const previous = readSyncState(dataPath);
|
|
32
54
|
if (previous?.syncHistory)
|
|
33
55
|
syncHistoryOut(toPaths(previous, dataPath));
|
|
34
|
-
const state = { ...previous, hostClaudeDir: hostClaudeDir(profile), hostWorkspace, guestWorkspace: config.guestWorkspace, syncHistory: profile.syncHistory, syncClaudeMem: profile.syncClaudeMem };
|
|
56
|
+
const state = { ...previous, hostClaudeDir: hostClaudeDir(profile), hostWorkspace, guestWorkspace: config.guestWorkspace, syncHistory: profile.syncHistory, historyScope: profile.historyScope, syncClaudeMem: profile.syncClaudeMem, syncClaudeMemBack: profile.syncClaudeMemBack, projects: [] };
|
|
35
57
|
if (profile.syncHistory)
|
|
36
|
-
summary.history = syncHistoryIn(toPaths(state, dataPath));
|
|
58
|
+
summary.history = syncHistoryIn(toPaths(state, dataPath), { scope: profile.historyScope });
|
|
37
59
|
if (profile.syncClaudeMem) {
|
|
38
|
-
if (previous?.syncClaudeMem)
|
|
60
|
+
if (previous?.syncClaudeMem && previous.syncClaudeMemBack)
|
|
39
61
|
memSync(dataPath, state, 'out');
|
|
40
62
|
summary.claudeMem = memSync(dataPath, state, 'in');
|
|
41
63
|
}
|
|
@@ -50,7 +72,7 @@ export const syncBack = (dataPath, final) => {
|
|
|
50
72
|
return summary;
|
|
51
73
|
if (state.syncHistory)
|
|
52
74
|
summary.history = syncHistoryOut(toPaths(state, dataPath));
|
|
53
|
-
if (final && state.syncClaudeMem)
|
|
75
|
+
if (final && state.syncClaudeMem && state.syncClaudeMemBack)
|
|
54
76
|
summary.claudeMem = memSync(dataPath, state, 'out');
|
|
55
77
|
writeSyncState(dataPath, state);
|
|
56
78
|
return summary;
|
|
@@ -58,7 +80,9 @@ export const syncBack = (dataPath, final) => {
|
|
|
58
80
|
const hostRunDir = (dataPath) => path.join(storageOf(dataPath), 'run');
|
|
59
81
|
const watcherPidFile = (dataPath) => path.join(hostRunDir(dataPath), 'watcher-' + path.basename(dataPath) + '.pid');
|
|
60
82
|
const watcherLog = (dataPath) => path.join(storageOf(dataPath), 'logs', 'host-sync-' + path.basename(dataPath) + '.log');
|
|
61
|
-
|
|
83
|
+
// Signal 0 only asks whether the process exists. pid 0 would mean "my own process group", so it never counts.
|
|
84
|
+
const alive = (pid) => { if (!Number.isInteger(pid) || pid <= 0)
|
|
85
|
+
return false; try {
|
|
62
86
|
process.kill(pid, 0);
|
|
63
87
|
return true;
|
|
64
88
|
}
|
|
@@ -75,19 +99,22 @@ export const watcherRunning = (dataPath) => {
|
|
|
75
99
|
};
|
|
76
100
|
/** Body of the detached watcher process (`agent-sandbox _watch`). */
|
|
77
101
|
export const watch = async (dataPath) => {
|
|
102
|
+
refuseInSelfTest('start the background sync');
|
|
78
103
|
if (watcherRunning(dataPath))
|
|
79
104
|
return;
|
|
80
105
|
fs.mkdirSync(hostRunDir(dataPath), { recursive: true });
|
|
81
106
|
fs.mkdirSync(path.dirname(watcherLog(dataPath)), { recursive: true });
|
|
82
|
-
|
|
107
|
+
writeFileAtomic(watcherPidFile(dataPath), String(process.pid));
|
|
83
108
|
const note = (message) => { try {
|
|
84
109
|
fs.appendFileSync(watcherLog(dataPath), new Date().toISOString() + ' ' + message + '\n');
|
|
85
110
|
}
|
|
86
111
|
catch { /* ignore */ } };
|
|
87
112
|
const sync = (final) => {
|
|
88
113
|
try {
|
|
89
|
-
for (const finding of checkRepo(dataPath))
|
|
114
|
+
for (const finding of checkRepo(dataPath)) {
|
|
90
115
|
note('SECURITY: neutralised a git ' + finding.kind + ' added inside the sandbox: ' + finding.detail);
|
|
116
|
+
audit?.guard(finding.kind + ': ' + finding.detail);
|
|
117
|
+
}
|
|
91
118
|
}
|
|
92
119
|
catch (e) {
|
|
93
120
|
note('repo guard failed: ' + errMsg(e));
|
|
@@ -101,16 +128,80 @@ export const watch = async (dataPath) => {
|
|
|
101
128
|
note('sync failed: ' + errMsg(e));
|
|
102
129
|
}
|
|
103
130
|
};
|
|
131
|
+
// workspaceFilter: each filtered project is kept in step with its view from now until the sandbox closes.
|
|
132
|
+
// audit.enabled: programs, files, sessions and guard findings into the host-only audit log.
|
|
133
|
+
const auditSettings = readAuditSettings(storageOf(dataPath), dataPath);
|
|
134
|
+
const audit = auditSettings?.enabled ? new AuditCollector(dataPath, storageOf(dataPath), auditSettings) : null;
|
|
135
|
+
audit?.start();
|
|
136
|
+
const auditTimer = audit ? setInterval(() => { try {
|
|
137
|
+
audit.flush();
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
note('audit: ' + errMsg(e));
|
|
141
|
+
} }, 10000) : null;
|
|
142
|
+
// storage.markSandboxFiles: programs and scripts that appear in the projects get the "from the internet" mark.
|
|
143
|
+
const stopMarking = watchAndMark(readMarkedProjects(storageOf(dataPath), dataPath), (m) => note(m));
|
|
144
|
+
// network.forwardPorts: localhost on this PC reaches servers in the sandbox while it runs.
|
|
145
|
+
const stopForwards = startPortForwards(readForwards(storageOf(dataPath), dataPath), () => sandboxAddress(dataPath), (m) => note('port forward: ' + m));
|
|
146
|
+
const views = readActiveViews(storageOf(dataPath), dataPath);
|
|
147
|
+
const stops = views.flatMap((v) => {
|
|
148
|
+
try {
|
|
149
|
+
return [new WorkspaceView({ ...v, note: (m) => note('workspace ' + v.host + ': ' + m) }).watch()];
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
note('workspace ' + v.host + ': could not watch: ' + errMsg(e));
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
// sandbox.keepAwake, and the life record that tells the next launch how this run ended (host/stops.ts).
|
|
157
|
+
const awake = readLife(storageOf(dataPath), dataPath)?.keepAwake ? keepAwake(process.pid) : null;
|
|
104
158
|
try {
|
|
105
159
|
await sleep(30000);
|
|
106
160
|
while (isSandboxRunning()) {
|
|
161
|
+
beatLife(storageOf(dataPath), dataPath);
|
|
107
162
|
sync(false);
|
|
108
163
|
await sleep(WATCH_INTERVAL_MS);
|
|
109
164
|
}
|
|
165
|
+
try {
|
|
166
|
+
const life = readLife(storageOf(dataPath), dataPath);
|
|
167
|
+
const cause = life ? causeSince(life.lastSeen) : null;
|
|
168
|
+
endLife(storageOf(dataPath), dataPath, cause);
|
|
169
|
+
if (cause)
|
|
170
|
+
note('sandbox ended: ' + cause.text);
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
note('could not record how the sandbox ended: ' + errMsg(e));
|
|
174
|
+
}
|
|
110
175
|
await sleep(3000);
|
|
111
176
|
sync(true);
|
|
112
177
|
}
|
|
113
178
|
finally {
|
|
179
|
+
awake?.kill();
|
|
180
|
+
stops.forEach((stop) => stop());
|
|
181
|
+
stopForwards();
|
|
182
|
+
stopMarking();
|
|
183
|
+
if (auditTimer)
|
|
184
|
+
clearInterval(auditTimer);
|
|
185
|
+
try {
|
|
186
|
+
audit?.stop();
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
note('audit: ' + errMsg(e));
|
|
190
|
+
}
|
|
191
|
+
for (const v of views) {
|
|
192
|
+
try {
|
|
193
|
+
const s = new WorkspaceView(v).syncAll();
|
|
194
|
+
note('workspace ' + v.host + ': final sync ' + s.toHost + ' out, ' + s.toView + ' in');
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
note('workspace ' + v.host + ': final sync failed: ' + errMsg(e));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// For the next launch's storage.warnDataGb (measuring then would be slow).
|
|
201
|
+
try {
|
|
202
|
+
saveDataSize(storageOf(dataPath), dataPath, sizeOf(dataPath));
|
|
203
|
+
}
|
|
204
|
+
catch { /* best effort */ }
|
|
114
205
|
fs.rmSync(watcherPidFile(dataPath), { force: true });
|
|
115
206
|
}
|
|
116
207
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windows-development-sandbox",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A disposable Windows Sandbox for development, with or without an AI agent (Claude Code, Codex, Gemini, opencode, ...): the folder you run it from is the workspace, toolchains and databases for your project install themselves, and nothing else on your PC is reachable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"hooks",
|
|
38
38
|
"config.example.json",
|
|
39
39
|
".sandbox-config.example.json",
|
|
40
|
-
"README.md"
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
41
42
|
],
|
|
42
43
|
"scripts": {
|
|
43
44
|
"build": "tsc -p tsconfig.json && node scripts/bundle.mjs && node scripts/schemas.mjs",
|
|
44
45
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
45
46
|
"rebuild": "npm run clean && npm run build",
|
|
46
47
|
"test": "npm run build && node dist/bin/agent-sandbox.js self-test",
|
|
47
|
-
"prepare": "npm run build",
|
|
48
48
|
"prepack": "npm run rebuild",
|
|
49
49
|
"release:patch": "npm version patch && git push --follow-tags",
|
|
50
50
|
"release:minor": "npm version minor && git push --follow-tags",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@inquirer/prompts": "^7.10.1",
|
|
74
74
|
"commander": "^14.0.3",
|
|
75
|
+
"ignore": "^7.0.12",
|
|
75
76
|
"jsonc-parser": "^3.3.1",
|
|
76
77
|
"lodash": "^4.18.1",
|
|
77
78
|
"zod": "^4.6.5"
|
|
@@ -84,10 +85,10 @@
|
|
|
84
85
|
},
|
|
85
86
|
"repository": {
|
|
86
87
|
"type": "git",
|
|
87
|
-
"url": "git+https://github.com/JoshDiDuca/
|
|
88
|
+
"url": "git+https://github.com/JoshDiDuca/windows-development-sandbox.git"
|
|
88
89
|
},
|
|
89
|
-
"homepage": "https://github.com/JoshDiDuca/
|
|
90
|
+
"homepage": "https://github.com/JoshDiDuca/windows-development-sandbox#readme",
|
|
90
91
|
"bugs": {
|
|
91
|
-
"url": "https://github.com/JoshDiDuca/
|
|
92
|
+
"url": "https://github.com/JoshDiDuca/windows-development-sandbox/issues"
|
|
92
93
|
}
|
|
93
94
|
}
|