@greppleai/grip 0.1.4 → 0.1.6
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/CHANGELOG.md +47 -0
- package/README.md +2 -2
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/embedded-assets.d.ts.map +1 -1
- package/dist/bun/embedded-assets.js.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.js.map +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +27 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +117 -152
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +6 -11
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +19 -23
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/compression-detection-ledger.d.ts.map +1 -1
- package/dist/core/compaction/compression-detection-ledger.js.map +1 -1
- package/dist/core/compaction/compression-detector.d.ts +1 -0
- package/dist/core/compaction/compression-detector.d.ts.map +1 -1
- package/dist/core/compaction/compression-detector.js +10 -21
- package/dist/core/compaction/compression-detector.js.map +1 -1
- package/dist/core/compaction/compression-economics.d.ts.map +1 -1
- package/dist/core/compaction/compression-economics.js.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +18 -30
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +15 -16
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/grip-agent.d.ts.map +1 -1
- package/dist/core/grip-agent.js +11 -23
- package/dist/core/grip-agent.js.map +1 -1
- package/dist/core/grip-manifest.d.ts.map +1 -1
- package/dist/core/grip-manifest.js.map +1 -1
- package/dist/core/hooks/aggregate.d.ts.map +1 -1
- package/dist/core/hooks/aggregate.js.map +1 -1
- package/dist/core/hooks/config.d.ts.map +1 -1
- package/dist/core/hooks/config.js.map +1 -1
- package/dist/core/hooks/executor.d.ts.map +1 -1
- package/dist/core/hooks/executor.js.map +1 -1
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js.map +1 -1
- package/dist/core/hooks/matcher.d.ts.map +1 -1
- package/dist/core/hooks/matcher.js.map +1 -1
- package/dist/core/hooks/trust-store.d.ts.map +1 -1
- package/dist/core/hooks/trust-store.js +0 -3
- package/dist/core/hooks/trust-store.js.map +1 -1
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/instruction-resource-loader.d.ts.map +1 -1
- package/dist/core/instruction-resource-loader.js +0 -3
- package/dist/core/instruction-resource-loader.js.map +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +0 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/lsp/abort.d.ts.map +1 -1
- package/dist/core/lsp/abort.js.map +1 -1
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +8 -22
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/config-loader.d.ts.map +1 -1
- package/dist/core/lsp/config-loader.js.map +1 -1
- package/dist/core/lsp/config.d.ts.map +1 -1
- package/dist/core/lsp/config.js.map +1 -1
- package/dist/core/lsp/diagnostics.d.ts.map +1 -1
- package/dist/core/lsp/diagnostics.js.map +1 -1
- package/dist/core/lsp/file-sync.d.ts.map +1 -1
- package/dist/core/lsp/file-sync.js +7 -9
- package/dist/core/lsp/file-sync.js.map +1 -1
- package/dist/core/lsp/integration.d.ts.map +1 -1
- package/dist/core/lsp/integration.js.map +1 -1
- package/dist/core/lsp/language-map.d.ts.map +1 -1
- package/dist/core/lsp/language-map.js +2 -7
- package/dist/core/lsp/language-map.js.map +1 -1
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +18 -29
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/navigation.d.ts.map +1 -1
- package/dist/core/lsp/navigation.js.map +1 -1
- package/dist/core/lsp/portable-path.d.ts.map +1 -1
- package/dist/core/lsp/portable-path.js.map +1 -1
- package/dist/core/lsp/refactor.d.ts.map +1 -1
- package/dist/core/lsp/refactor.js.map +1 -1
- package/dist/core/lsp/transport.d.ts.map +1 -1
- package/dist/core/lsp/transport.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +5 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +0 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.js +4 -2
- package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-client.js +1 -5
- package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +5 -10
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +2 -9
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -1
- package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/session.js +27 -65
- package/dist/core/remote-workspace-protocol/session.js.map +1 -1
- package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +0 -48
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js.map +1 -1
- package/dist/core/sandbox/command.d.ts.map +1 -1
- package/dist/core/sandbox/command.js.map +1 -1
- package/dist/core/sandbox/config.d.ts.map +1 -1
- package/dist/core/sandbox/config.js.map +1 -1
- package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -1
- package/dist/core/sandbox/lima-guest-binary.js.map +1 -1
- package/dist/core/sandbox/lima.d.ts +2 -0
- package/dist/core/sandbox/lima.d.ts.map +1 -1
- package/dist/core/sandbox/lima.js +9 -15
- package/dist/core/sandbox/lima.js.map +1 -1
- package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -1
- package/dist/core/sandbox/shared-lima-roots.js.map +1 -1
- package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -1
- package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -1
- package/dist/core/session/constants.d.ts.map +1 -1
- package/dist/core/session/context-metadata.d.ts.map +1 -1
- package/dist/core/session/context-metadata.js.map +1 -1
- package/dist/core/session/context.d.ts.map +1 -1
- package/dist/core/session/context.js.map +1 -1
- package/dist/core/session/ids.d.ts.map +1 -1
- package/dist/core/session/ids.js.map +1 -1
- package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
- package/dist/core/session/in-memory-session-manager.js +0 -1
- package/dist/core/session/in-memory-session-manager.js.map +1 -1
- package/dist/core/session/in-memory-session.d.ts.map +1 -1
- package/dist/core/session/in-memory-session.js.map +1 -1
- package/dist/core/session/jsonl-errors.d.ts.map +1 -1
- package/dist/core/session/jsonl-errors.js +0 -11
- package/dist/core/session/jsonl-errors.js.map +1 -1
- package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
- package/dist/core/session/jsonl-helpers.js.map +1 -1
- package/dist/core/session/local-session-manager.d.ts.map +1 -1
- package/dist/core/session/local-session-manager.js +4 -6
- package/dist/core/session/local-session-manager.js.map +1 -1
- package/dist/core/session/local-session.d.ts.map +1 -1
- package/dist/core/session/local-session.js.map +1 -1
- package/dist/core/session/migrations.d.ts.map +1 -1
- package/dist/core/session/migrations.js.map +1 -1
- package/dist/core/session/remote-session-client.d.ts.map +1 -1
- package/dist/core/session/remote-session-client.js +0 -6
- package/dist/core/session/remote-session-client.js.map +1 -1
- package/dist/core/session/remote-session-manager.d.ts.map +1 -1
- package/dist/core/session/remote-session-manager.js +0 -3
- package/dist/core/session/remote-session-manager.js.map +1 -1
- package/dist/core/session/remote-session.d.ts.map +1 -1
- package/dist/core/session/remote-session.js +0 -1
- package/dist/core/session/remote-session.js.map +1 -1
- package/dist/core/session/session-manager.d.ts.map +1 -1
- package/dist/core/session/session.d.ts.map +1 -1
- package/dist/core/session/session.js +1 -5
- package/dist/core/session/session.js.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.js +7 -6
- package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.js +6 -14
- package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
- package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/remote-session-store.js +3 -8
- package/dist/core/session/stores/remote-session-store.js.map +1 -1
- package/dist/core/session/stores/session-store.d.ts.map +1 -1
- package/dist/core/session/types.d.ts.map +1 -1
- package/dist/core/session/usage-ledger.d.ts.map +1 -1
- package/dist/core/session/usage-ledger.js.map +1 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +0 -1
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +9 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/source-info.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +8 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/compress-context.d.ts.map +1 -1
- package/dist/core/tools/compress-context.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hash-store.d.ts.map +1 -1
- package/dist/core/tools/hash-store.js.map +1 -1
- package/dist/core/tools/hashline/apply.d.ts.map +1 -1
- package/dist/core/tools/hashline/apply.js.map +1 -1
- package/dist/core/tools/hashline/hash.d.ts.map +1 -1
- package/dist/core/tools/hashline/hash.js.map +1 -1
- package/dist/core/tools/hashline/parse.d.ts.map +1 -1
- package/dist/core/tools/hashline/parse.js.map +1 -1
- package/dist/core/tools/hashline/resolve.d.ts.map +1 -1
- package/dist/core/tools/hashline/resolve.js.map +1 -1
- package/dist/core/tools/hashline-utils.d.ts.map +1 -1
- package/dist/core/tools/hashline-utils.js.map +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/operations.d.ts +5 -0
- package/dist/core/tools/operations.d.ts.map +1 -1
- package/dist/core/tools/operations.js +26 -24
- package/dist/core/tools/operations.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +12 -18
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/replace-diff.d.ts.map +1 -1
- package/dist/core/tools/replace-diff.js.map +1 -1
- package/dist/core/tools/replace-normalize.d.ts.map +1 -1
- package/dist/core/tools/replace-normalize.js.map +1 -1
- package/dist/core/tools/replace-render.d.ts +1 -1
- package/dist/core/tools/replace-render.d.ts.map +1 -1
- package/dist/core/tools/replace-render.js.map +1 -1
- package/dist/core/tools/runtime.d.ts.map +1 -1
- package/dist/core/tools/runtime.js.map +1 -1
- package/dist/core/tools/session-history.d.ts.map +1 -1
- package/dist/core/tools/session-history.js.map +1 -1
- package/dist/core/tools/subagent-agents.d.ts.map +1 -1
- package/dist/core/tools/subagent-agents.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/workspace-tool-host.d.ts +1 -0
- package/dist/core/tools/workspace-tool-host.d.ts.map +1 -1
- package/dist/core/tools/workspace-tool-host.js +36 -22
- package/dist/core/tools/workspace-tool-host.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +0 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/workspace-identity.d.ts.map +1 -1
- package/dist/daemon/activity-budget.d.ts.map +1 -1
- package/dist/daemon/activity-budget.js +2 -3
- package/dist/daemon/activity-budget.js.map +1 -1
- package/dist/daemon/command.d.ts.map +1 -1
- package/dist/daemon/command.js.map +1 -1
- package/dist/daemon/config.d.ts +2 -0
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +4 -0
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/help.d.ts.map +1 -1
- package/dist/daemon/help.js +4 -3
- package/dist/daemon/help.js.map +1 -1
- package/dist/daemon/lsp-config.d.ts.map +1 -1
- package/dist/daemon/lsp-config.js.map +1 -1
- package/dist/daemon/outbound-budget.d.ts.map +1 -1
- package/dist/daemon/outbound-budget.js +2 -4
- package/dist/daemon/outbound-budget.js.map +1 -1
- package/dist/daemon/security.d.ts.map +1 -1
- package/dist/daemon/security.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shared-connection.d.ts.map +1 -1
- package/dist/daemon/shared-connection.js +10 -15
- package/dist/daemon/shared-connection.js.map +1 -1
- package/dist/daemon/shared-revision.d.ts.map +1 -1
- package/dist/daemon/shared-revision.js +2 -1
- package/dist/daemon/shared-revision.js.map +1 -1
- package/dist/daemon/shared-roots.d.ts.map +1 -1
- package/dist/daemon/shared-roots.js +0 -1
- package/dist/daemon/shared-roots.js.map +1 -1
- package/dist/daemon/workspace-runtime.d.ts +2 -0
- package/dist/daemon/workspace-runtime.d.ts.map +1 -1
- package/dist/daemon/workspace-runtime.js +43 -15
- package/dist/daemon/workspace-runtime.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +21 -17
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -9
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -3
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -3
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +6 -16
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -5
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +1 -8
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -6
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -7
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +2 -8
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +1 -9
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -3
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-execution.js +2 -5
- package/dist/modes/interactive/components/hook-execution.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -9
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/message-card.d.ts.map +1 -1
- package/dist/modes/interactive/components/message-card.js +0 -1
- package/dist/modes/interactive/components/message-card.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +26 -18
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +223 -210
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +3 -12
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +9 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +33 -58
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -4
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -2
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -24
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +18 -34
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +3 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +0 -4
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +14 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +223 -137
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +0 -7
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/dist/modes/rpc/jsonl.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +10 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/deprecation.d.ts.map +1 -1
- package/dist/utils/deprecation.js.map +1 -1
- package/dist/utils/directory-completions.d.ts.map +1 -1
- package/dist/utils/directory-completions.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/grip-user-agent.d.ts.map +1 -1
- package/dist/utils/grip-user-agent.js +1 -1
- package/dist/utils/grip-user-agent.js.map +1 -1
- package/dist/utils/html.d.ts.map +1 -1
- package/dist/utils/html.js.map +1 -1
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts.map +1 -1
- package/dist/utils/image-process.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/image-resize-worker.d.ts.map +1 -1
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/open-browser.d.ts.map +1 -1
- package/dist/utils/open-browser.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js +10 -5
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +1 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/dist/utils/windows-self-update.js.map +1 -1
- package/docs/keybindings.md +3 -1
- package/docs/providers.md +3 -1
- package/docs/sandbox.md +7 -1
- package/docs/sessions.md +1 -1
- package/docs/usage.md +39 -2
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +601 -833
- package/package.json +20 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../../src/core/sandbox/command.ts"],"names":[],"mappings":"AAiBA,SAAS,gBAAgB,CAAC,KAAa
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../../src/core/sandbox/command.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SandboxContainer, SandboxStartResult, SandboxStopResult } from \"./config.ts\";\n\nexport interface SandboxStartUserCommand {\n\tsubcommand: \"start\";\n\tname?: string;\n\ttemplate?: string;\n\tupdate?: boolean;\n}\n\nexport type SandboxUserCommand =\n\t| { subcommand: \"status\" }\n\t| { subcommand: \"clear\" }\n\t| { subcommand: \"attach\"; url: string }\n\t| SandboxStartUserCommand\n\t| { subcommand: \"list\" }\n\t| { subcommand: \"stop\"; target?: string };\n\nfunction splitCommandLine(input: string): string[] {\n\tconst tokens = input.match(/(?:[^\\s\"']+|\"[^\"]*\"|'[^']*')+/g) ?? [];\n\treturn tokens.map((token) => {\n\t\tif ((token.startsWith('\"') && token.endsWith('\"')) || (token.startsWith(\"'\") && token.endsWith(\"'\"))) {\n\t\t\treturn token.slice(1, -1);\n\t\t}\n\t\treturn token;\n\t});\n}\n\nfunction parseSandboxStartValue(\n\toption: string | undefined,\n\tvalue: string | undefined,\n): Pick<SandboxStartUserCommand, \"name\" | \"template\"> {\n\tif (option !== \"--name\" && option !== \"--template\") {\n\t\tthrow new Error(`Unsupported /sandbox start argument: ${option}`);\n\t}\n\tif (!value || value.startsWith(\"--\")) {\n\t\tthrow new Error(\"Usage: /sandbox start [--name <lima-instance>] [--template <lima-template>] [--update]\");\n\t}\n\treturn option === \"--name\" ? { name: value } : { template: value };\n}\n\nfunction parseSandboxStartCommand(tokens: string[]): SandboxUserCommand {\n\tconst fields: Pick<SandboxStartUserCommand, \"name\" | \"template\"> = {};\n\tlet update = false;\n\tfor (let index = 2; index < tokens.length; index++) {\n\t\tconst option = tokens[index];\n\t\tif (option === \"--update\") {\n\t\t\tif (update) throw new Error(\"Duplicate /sandbox start --update\");\n\t\t\tupdate = true;\n\t\t\tcontinue;\n\t\t}\n\t\tObject.assign(fields, parseSandboxStartValue(option, tokens[++index]));\n\t}\n\tif (update && (!fields.name || fields.template)) {\n\t\tthrow new Error(\"/sandbox start --update requires --name and cannot be combined with --template\");\n\t}\n\treturn {\n\t\tsubcommand: \"start\",\n\t\t...fields,\n\t\t...(update ? { update: true } : {}),\n\t};\n}\n\nexport function parseSandboxUserCommand(input: string): SandboxUserCommand {\n\tconst tokens = splitCommandLine(input.trim());\n\tif (tokens[0] !== \"/sandbox\") throw new Error(\"Sandbox command must start with /sandbox\");\n\n\tconst subcommand = tokens[1];\n\tswitch (subcommand) {\n\t\tcase undefined:\n\t\tcase \"status\":\n\t\t\tif (tokens.length > 2) throw new Error(\"Usage: /sandbox status\");\n\t\t\treturn { subcommand: \"status\" };\n\t\tcase \"clear\":\n\t\t\tif (tokens.length > 2) throw new Error(\"Usage: /sandbox clear\");\n\t\t\treturn { subcommand: \"clear\" };\n\t\tcase \"--attach\":\n\t\t\tif (tokens.length !== 3) throw new Error(\"Usage: /sandbox --attach <ws://url>\");\n\t\t\treturn { subcommand: \"attach\", url: tokens[2]! };\n\t\tcase \"start\":\n\t\t\treturn parseSandboxStartCommand(tokens);\n\t\tcase \"list\":\n\t\t\tif (tokens.length !== 2) throw new Error(\"Usage: /sandbox list\");\n\t\t\treturn { subcommand: \"list\" };\n\t\tcase \"stop\":\n\t\t\tif (tokens.length > 3) throw new Error(\"Usage: /sandbox stop [vm]\");\n\t\t\treturn tokens[2] ? { subcommand: \"stop\", target: tokens[2] } : { subcommand: \"stop\" };\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported /sandbox subcommand: ${subcommand}. Use status, clear, --attach, start, list, or stop.`,\n\t\t\t);\n\t}\n}\n\nexport function formatSandboxStartResult(result: SandboxStartResult): string {\n\treturn [\n\t\t`Sandbox started: ${result.containerName} (${result.containerId})`,\n\t\t`Workspace: ${result.workspaceRoot} -> ${result.workspaceMountPath}`,\n\t\t`Daemon: ${result.daemonUrlRedacted}`,\n\t\t\"Sandbox mode active: workspace tools/resources now route through the sandbox daemon.\",\n\t].join(\"\\n\");\n}\n\nexport function formatSandboxList(containers: SandboxContainer[]): string {\n\tif (containers.length === 0) return \"No Grip sandboxes found for this workspace.\";\n\treturn containers\n\t\t.map((container) => {\n\t\t\tconst endpoint = container.daemonEndpoint ? ` daemon=${container.daemonEndpoint}` : \"\";\n\t\t\tconst mount = container.workspaceMountPath ? ` workspace=${container.workspaceMountPath}` : \"\";\n\t\t\treturn `${container.id}\\t${container.name}\\t${container.state ?? container.status}\\t${container.image}${mount}${endpoint}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function formatSandboxStopResult(result: SandboxStopResult): string {\n\tif (result.status === \"not-found\") return result.message;\n\tif (result.status === \"already-stopped\")\n\t\treturn `Sandbox already stopped: ${result.container.name} (${result.container.id})`;\n\tif (result.status === \"removed\") return `Sandbox removed: ${result.container.name} (${result.container.id})`;\n\treturn `Sandbox stopped: ${result.container.name} (${result.container.id})`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/config.ts"],"names":[],"mappings":"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"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/sandbox/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer } from \"node:net\";\nimport type { SandboxSettings } from \"../settings-manager.ts\";\n\nexport const DEFAULT_SANDBOX_WORKSPACE_MOUNT = \"/workspace\";\nexport const DEFAULT_SANDBOX_DAEMON_PORT = 8787;\nexport const DEFAULT_SANDBOX_LIMA_BINARY = \"limactl\";\nexport const DEFAULT_SANDBOX_LIMA_TEMPLATE = \"template:docker-rootful\";\nexport const SANDBOX_LABEL_PREFIX = \"ai.greppleai.grip\";\n\nexport type SandboxCleanupBehavior = \"stop\" | \"remove\";\n\nexport type SandboxConfig = Required<SandboxSettings>;\n\nexport type SandboxConfigOverrides = SandboxSettings;\n\nexport interface SandboxEnvironment {\n\tGRIP_SANDBOX_LIMA?: string;\n\tGRIP_SANDBOX_GUEST_BINARY?: string;\n\tGRIP_SANDBOX_LIMA_TEMPLATE?: string;\n\tGRIP_SANDBOX_LIMA_INSTANCE_PREFIX?: string;\n\tGRIP_SANDBOX_WORKSPACE_MOUNT?: string;\n\tGRIP_SANDBOX_DAEMON_PORT?: string;\n\tGRIP_SANDBOX_DAEMON_HOST_BIND?: string;\n\tGRIP_SANDBOX_CLEANUP?: string;\n}\n\nexport interface SandboxStartOptions extends SandboxConfigOverrides {\n\tworkspaceRoot: string;\n\tsessionId?: string;\n\tname?: string;\n\tupdate?: boolean;\n}\n\nexport interface SandboxListOptions {\n\tworkspaceRoot: string;\n\tallWorkspaces?: boolean;\n}\n\nexport interface SandboxStopOptions {\n\tworkspaceRoot: string;\n\ttarget?: string;\n\tcurrentContainerId?: string;\n}\n\nexport interface SandboxContainer {\n\tid: string;\n\tname: string;\n\timage: string;\n\tstatus: string;\n\tstate: string | undefined;\n\tcreatedAt: string | undefined;\n\tworkspaceRoot: string | undefined;\n\tworkspaceMountPath: string | undefined;\n\tdaemonPort: number | undefined;\n\tdaemonEndpoint: string | undefined;\n\tlabels: Record<string, string>;\n}\n\nexport interface SandboxStartResult {\n\tcontainerId: string;\n\tcontainerName: string;\n\tworkspaceRoot: string;\n\tworkspaceMountPath: string;\n\tdaemonUrl: string;\n\tdaemonUrlRedacted: string;\n\ttoken: string;\n\tlabels: Record<string, string>;\n}\n\nexport type SandboxStopResult =\n\t| { status: \"stopped\"; container: SandboxContainer }\n\t| { status: \"removed\"; container: SandboxContainer }\n\t| { status: \"already-stopped\"; container: SandboxContainer }\n\t| { status: \"not-found\"; message: string };\n\nexport interface SandboxService {\n\tresolveConfig(overrides?: SandboxConfigOverrides): SandboxConfig;\n\tstart(options: SandboxStartOptions): Promise<SandboxStartResult>;\n\tlist(options: SandboxListOptions): Promise<SandboxContainer[]>;\n\tstop(options: SandboxStopOptions): Promise<SandboxStopResult>;\n}\n\nexport interface SandboxCommandResult {\n\texitCode: number | null;\n\tstdout: string;\n\tstderr: string;\n}\n\nexport interface SandboxCommandOptions {\n\tenv?: Record<string, string>;\n}\n\nexport interface SandboxRunner {\n\trun(command: string, args: string[], options?: SandboxCommandOptions): Promise<SandboxCommandResult>;\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n\tconst trimmed = value?.trim();\n\treturn trimmed ? trimmed : undefined;\n}\n\nfunction parsePositiveInteger(value: string | number | undefined, settingName: string): number | undefined {\n\tif (value === undefined) return undefined;\n\tconst text = String(value).trim();\n\tif (!/^\\d+$/.test(text)) throw new Error(`Invalid ${settingName}: expected a decimal integer`);\n\tconst parsed = Number(text);\n\tif (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 65535) {\n\t\tthrow new Error(`Invalid ${settingName}: expected a port from 1 to 65535`);\n\t}\n\treturn parsed;\n}\n\nfunction parseCleanup(value: string | undefined, settingName: string): SandboxCleanupBehavior | undefined {\n\tif (value === undefined) return undefined;\n\tif (value === \"stop\" || value === \"remove\") return value;\n\tthrow new Error(`Invalid ${settingName}: expected stop or remove`);\n}\n\nexport function redactSecrets(value: string): string {\n\treturn value\n\t\t.replace(/(GRIP_DAEMON_TOKEN=)[^\\s,;]+/g, \"$1[REDACTED]\")\n\t\t.replace(/(PI_DAEMON_TOKEN=)[^\\s,;]+/g, \"$1[REDACTED]\")\n\t\t.replace(/(Authorization:\\s*Bearer\\s+)[^\\s,;]+/gi, \"$1[REDACTED]\")\n\t\t.replace(/([?&]token=)[^\\s&]+/gi, \"$1[REDACTED]\");\n}\n\nexport function resolveSandboxConfig(\n\tsettings: SandboxSettings | undefined,\n\tenv: SandboxEnvironment = {},\n\toverrides: SandboxConfigOverrides = {},\n): SandboxConfig {\n\treturn {\n\t\tlimaBinary:\n\t\t\tnonEmpty(overrides.limaBinary) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA) ??\n\t\t\tnonEmpty(settings?.limaBinary) ??\n\t\t\tDEFAULT_SANDBOX_LIMA_BINARY,\n\t\tlimaTemplate:\n\t\t\tnonEmpty(overrides.limaTemplate) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA_TEMPLATE) ??\n\t\t\tnonEmpty(settings?.limaTemplate) ??\n\t\t\tDEFAULT_SANDBOX_LIMA_TEMPLATE,\n\t\tlimaInstanceNamePrefix:\n\t\t\tnonEmpty(overrides.limaInstanceNamePrefix) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA_INSTANCE_PREFIX) ??\n\t\t\tnonEmpty(settings?.limaInstanceNamePrefix) ??\n\t\t\t\"grip-sandbox\",\n\t\tworkspaceMountPath:\n\t\t\tnonEmpty(overrides.workspaceMountPath) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_WORKSPACE_MOUNT) ??\n\t\t\tnonEmpty(settings?.workspaceMountPath) ??\n\t\t\tDEFAULT_SANDBOX_WORKSPACE_MOUNT,\n\t\tdaemonPort:\n\t\t\toverrides.daemonPort ??\n\t\t\tparsePositiveInteger(env.GRIP_SANDBOX_DAEMON_PORT, \"GRIP_SANDBOX_DAEMON_PORT\") ??\n\t\t\tparsePositiveInteger(settings?.daemonPort, \"sandbox.daemonPort\") ??\n\t\t\tDEFAULT_SANDBOX_DAEMON_PORT,\n\t\tdaemonHostBind:\n\t\t\tnonEmpty(overrides.daemonHostBind) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_DAEMON_HOST_BIND) ??\n\t\t\tnonEmpty(settings?.daemonHostBind) ??\n\t\t\t\"127.0.0.1\",\n\t\tcleanup:\n\t\t\toverrides.cleanup ??\n\t\t\tparseCleanup(env.GRIP_SANDBOX_CLEANUP, \"GRIP_SANDBOX_CLEANUP\") ??\n\t\t\tparseCleanup(settings?.cleanup, \"sandbox.cleanup\") ??\n\t\t\t\"stop\",\n\t};\n}\n\nexport async function allocateSandboxDaemonPort(host: string, preferredPort: number): Promise<number> {\n\tconst reserve = (port: number): Promise<number | undefined> =>\n\t\tnew Promise((resolvePort) => {\n\t\t\tconst server = createServer();\n\t\t\tserver.unref();\n\t\t\tserver.once(\"error\", () => resolvePort(undefined));\n\t\t\tserver.listen({ host, port, exclusive: true }, () => {\n\t\t\t\tconst address = server.address();\n\t\t\t\tconst selectedPort = typeof address === \"object\" && address ? address.port : undefined;\n\t\t\t\tserver.close(() => resolvePort(selectedPort));\n\t\t\t});\n\t\t});\n\tconst preferred = await reserve(preferredPort);\n\tif (preferred !== undefined) return preferred;\n\tconst fallback = await reserve(0);\n\tif (fallback === undefined) throw new Error(`Unable to allocate a sandbox daemon port on ${host}`);\n\treturn fallback;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/sandbox/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,CAAC,MAAM,+BAA+B,GAAG,YAAY,CAAC;AAC5D,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAChD,MAAM,CAAC,MAAM,2BAA2B,GAAG,SAAS,CAAC;AACrD,MAAM,CAAC,MAAM,6BAA6B,GAAG,yBAAyB,CAAC;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAyFxD,SAAS,QAAQ,CAAC,KAAyB;IAC1C,MAAM,OAAO,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9B,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACtC,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAkC,EAAE,WAAmB;IACpF,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,WAAW,8BAA8B,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,KAAK,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,WAAW,WAAW,mCAAmC,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB,EAAE,WAAmB;IACnE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACzD,MAAM,IAAI,KAAK,CAAC,WAAW,WAAW,2BAA2B,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IAC1C,OAAO,KAAK;SACV,OAAO,CAAC,+BAA+B,EAAE,cAAc,CAAC;SACxD,OAAO,CAAC,6BAA6B,EAAE,cAAc,CAAC;SACtD,OAAO,CAAC,wCAAwC,EAAE,cAAc,CAAC;SACjE,OAAO,CAAC,uBAAuB,EAAE,cAAc,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAAqC,EACrC,GAAG,GAAuB,EAAE,EAC5B,SAAS,GAA2B,EAAE;IAEtC,OAAO;QACN,UAAU,EACT,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC;YAC9B,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC;YAC/B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;YAC9B,2BAA2B;QAC5B,YAAY,EACX,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC;YAChC,QAAQ,CAAC,GAAG,CAAC,0BAA0B,CAAC;YACxC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;YAChC,6BAA6B;QAC9B,sBAAsB,EACrB,QAAQ,CAAC,SAAS,CAAC,sBAAsB,CAAC;YAC1C,QAAQ,CAAC,GAAG,CAAC,iCAAiC,CAAC;YAC/C,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;YAC1C,cAAc;QACf,kBAAkB,EACjB,QAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC;YACtC,QAAQ,CAAC,GAAG,CAAC,4BAA4B,CAAC;YAC1C,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;YACtC,+BAA+B;QAChC,UAAU,EACT,SAAS,CAAC,UAAU;YACpB,oBAAoB,CAAC,GAAG,CAAC,wBAAwB,EAAE,0BAA0B,CAAC;YAC9E,oBAAoB,CAAC,QAAQ,EAAE,UAAU,EAAE,oBAAoB,CAAC;YAChE,2BAA2B;QAC5B,cAAc,EACb,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC;YAClC,QAAQ,CAAC,GAAG,CAAC,6BAA6B,CAAC;YAC3C,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;YAClC,WAAW;QACZ,OAAO,EACN,SAAS,CAAC,OAAO;YACjB,YAAY,CAAC,GAAG,CAAC,oBAAoB,EAAE,sBAAsB,CAAC;YAC9D,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,iBAAiB,CAAC;YAClD,MAAM;KACP,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAAY,EAAE,aAAqB;IAClF,MAAM,OAAO,GAAG,CAAC,IAAY,EAA+B,EAAE,CAC7D,IAAI,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE;YACnD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,YAAY,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YACvF,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IACJ,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,EAAE,CAAC,CAAC;IACnG,OAAO,QAAQ,CAAC;AACjB,CAAC","sourcesContent":["import { createServer } from \"node:net\";\nimport type { SandboxSettings } from \"../settings-manager.ts\";\n\nexport const DEFAULT_SANDBOX_WORKSPACE_MOUNT = \"/workspace\";\nexport const DEFAULT_SANDBOX_DAEMON_PORT = 8787;\nexport const DEFAULT_SANDBOX_LIMA_BINARY = \"limactl\";\nexport const DEFAULT_SANDBOX_LIMA_TEMPLATE = \"template:docker-rootful\";\nexport const SANDBOX_LABEL_PREFIX = \"ai.greppleai.grip\";\n\nexport type SandboxCleanupBehavior = \"stop\" | \"remove\";\n\nexport type SandboxConfig = Required<SandboxSettings>;\n\nexport type SandboxConfigOverrides = SandboxSettings;\n\nexport interface SandboxEnvironment {\n\tGRIP_SANDBOX_LIMA?: string;\n\tGRIP_SANDBOX_GUEST_BINARY?: string;\n\tGRIP_SANDBOX_LIMA_TEMPLATE?: string;\n\tGRIP_SANDBOX_LIMA_INSTANCE_PREFIX?: string;\n\tGRIP_SANDBOX_WORKSPACE_MOUNT?: string;\n\tGRIP_SANDBOX_DAEMON_PORT?: string;\n\tGRIP_SANDBOX_DAEMON_HOST_BIND?: string;\n\tGRIP_SANDBOX_CLEANUP?: string;\n}\n\nexport interface SandboxStartOptions extends SandboxConfigOverrides {\n\tworkspaceRoot: string;\n\tsessionId?: string;\n\tname?: string;\n\tupdate?: boolean;\n}\n\nexport interface SandboxListOptions {\n\tworkspaceRoot: string;\n\tallWorkspaces?: boolean;\n}\n\nexport interface SandboxStopOptions {\n\tworkspaceRoot: string;\n\ttarget?: string;\n\tcurrentContainerId?: string;\n}\n\nexport interface SandboxContainer {\n\tid: string;\n\tname: string;\n\timage: string;\n\tstatus: string;\n\tstate: string | undefined;\n\tcreatedAt: string | undefined;\n\tworkspaceRoot: string | undefined;\n\tworkspaceMountPath: string | undefined;\n\tdaemonPort: number | undefined;\n\tdaemonEndpoint: string | undefined;\n\tlabels: Record<string, string>;\n}\n\nexport interface SandboxStartResult {\n\tcontainerId: string;\n\tcontainerName: string;\n\tworkspaceRoot: string;\n\tworkspaceMountPath: string;\n\tdaemonUrl: string;\n\tdaemonUrlRedacted: string;\n\ttoken: string;\n\tlabels: Record<string, string>;\n}\n\nexport type SandboxStopResult =\n\t| { status: \"stopped\"; container: SandboxContainer }\n\t| { status: \"removed\"; container: SandboxContainer }\n\t| { status: \"already-stopped\"; container: SandboxContainer }\n\t| { status: \"not-found\"; message: string };\n\nexport interface SandboxService {\n\tresolveConfig(overrides?: SandboxConfigOverrides): SandboxConfig;\n\tstart(options: SandboxStartOptions): Promise<SandboxStartResult>;\n\tlist(options: SandboxListOptions): Promise<SandboxContainer[]>;\n\tstop(options: SandboxStopOptions): Promise<SandboxStopResult>;\n}\n\nexport interface SandboxCommandResult {\n\texitCode: number | null;\n\tstdout: string;\n\tstderr: string;\n}\n\nexport interface SandboxCommandOptions {\n\tenv?: Record<string, string>;\n}\n\nexport interface SandboxRunner {\n\trun(command: string, args: string[], options?: SandboxCommandOptions): Promise<SandboxCommandResult>;\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n\tconst trimmed = value?.trim();\n\treturn trimmed ? trimmed : undefined;\n}\n\nfunction parsePositiveInteger(value: string | number | undefined, settingName: string): number | undefined {\n\tif (value === undefined) return undefined;\n\tconst text = String(value).trim();\n\tif (!/^\\d+$/.test(text)) throw new Error(`Invalid ${settingName}: expected a decimal integer`);\n\tconst parsed = Number(text);\n\tif (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 65535) {\n\t\tthrow new Error(`Invalid ${settingName}: expected a port from 1 to 65535`);\n\t}\n\treturn parsed;\n}\n\nfunction parseCleanup(value: string | undefined, settingName: string): SandboxCleanupBehavior | undefined {\n\tif (value === undefined) return undefined;\n\tif (value === \"stop\" || value === \"remove\") return value;\n\tthrow new Error(`Invalid ${settingName}: expected stop or remove`);\n}\n\nexport function redactSecrets(value: string): string {\n\treturn value\n\t\t.replace(/(GRIP_DAEMON_TOKEN=)[^\\s,;]+/g, \"$1[REDACTED]\")\n\t\t.replace(/(PI_DAEMON_TOKEN=)[^\\s,;]+/g, \"$1[REDACTED]\")\n\t\t.replace(/(Authorization:\\s*Bearer\\s+)[^\\s,;]+/gi, \"$1[REDACTED]\")\n\t\t.replace(/([?&]token=)[^\\s&]+/gi, \"$1[REDACTED]\");\n}\n\nexport function resolveSandboxConfig(\n\tsettings: SandboxSettings | undefined,\n\tenv: SandboxEnvironment = {},\n\toverrides: SandboxConfigOverrides = {},\n): SandboxConfig {\n\treturn {\n\t\tlimaBinary:\n\t\t\tnonEmpty(overrides.limaBinary) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA) ??\n\t\t\tnonEmpty(settings?.limaBinary) ??\n\t\t\tDEFAULT_SANDBOX_LIMA_BINARY,\n\t\tlimaTemplate:\n\t\t\tnonEmpty(overrides.limaTemplate) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA_TEMPLATE) ??\n\t\t\tnonEmpty(settings?.limaTemplate) ??\n\t\t\tDEFAULT_SANDBOX_LIMA_TEMPLATE,\n\t\tlimaInstanceNamePrefix:\n\t\t\tnonEmpty(overrides.limaInstanceNamePrefix) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_LIMA_INSTANCE_PREFIX) ??\n\t\t\tnonEmpty(settings?.limaInstanceNamePrefix) ??\n\t\t\t\"grip-sandbox\",\n\t\tworkspaceMountPath:\n\t\t\tnonEmpty(overrides.workspaceMountPath) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_WORKSPACE_MOUNT) ??\n\t\t\tnonEmpty(settings?.workspaceMountPath) ??\n\t\t\tDEFAULT_SANDBOX_WORKSPACE_MOUNT,\n\t\tdaemonPort:\n\t\t\toverrides.daemonPort ??\n\t\t\tparsePositiveInteger(env.GRIP_SANDBOX_DAEMON_PORT, \"GRIP_SANDBOX_DAEMON_PORT\") ??\n\t\t\tparsePositiveInteger(settings?.daemonPort, \"sandbox.daemonPort\") ??\n\t\t\tDEFAULT_SANDBOX_DAEMON_PORT,\n\t\tdaemonHostBind:\n\t\t\tnonEmpty(overrides.daemonHostBind) ??\n\t\t\tnonEmpty(env.GRIP_SANDBOX_DAEMON_HOST_BIND) ??\n\t\t\tnonEmpty(settings?.daemonHostBind) ??\n\t\t\t\"127.0.0.1\",\n\t\tcleanup:\n\t\t\toverrides.cleanup ??\n\t\t\tparseCleanup(env.GRIP_SANDBOX_CLEANUP, \"GRIP_SANDBOX_CLEANUP\") ??\n\t\t\tparseCleanup(settings?.cleanup, \"sandbox.cleanup\") ??\n\t\t\t\"stop\",\n\t};\n}\n\nexport async function allocateSandboxDaemonPort(host: string, preferredPort: number): Promise<number> {\n\tconst reserve = (port: number): Promise<number | undefined> =>\n\t\tnew Promise((resolvePort) => {\n\t\t\tconst server = createServer();\n\t\t\tserver.unref();\n\t\t\tserver.once(\"error\", () => resolvePort(undefined));\n\t\t\tserver.listen({ host, port, exclusive: true }, () => {\n\t\t\t\tconst address = server.address();\n\t\t\t\tconst selectedPort = typeof address === \"object\" && address ? address.port : undefined;\n\t\t\t\tserver.close(() => resolvePort(selectedPort));\n\t\t\t});\n\t\t});\n\tconst preferred = await reserve(preferredPort);\n\tif (preferred !== undefined) return preferred;\n\tconst fallback = await reserve(0);\n\tif (fallback === undefined) throw new Error(`Unable to allocate a sandbox daemon port on ${host}`);\n\treturn fallback;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lima-guest-binary.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/lima-guest-binary.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,0FAA0F;AAC1F,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyBrF;AAqCD,mGAAmG;AACnG,wBAAsB,uBAAuB,CAC5C,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,MAAM,OAAO,CAAC,IAAI,CAAkB,GAC/C,OAAO,CAAC,IAAI,CAAC,CAmEf"
|
|
1
|
+
{"version":3,"file":"lima-guest-binary.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/lima-guest-binary.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,0FAA0F;AAC1F,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyBrF;AAqCD,mGAAmG;AACnG,wBAAsB,uBAAuB,CAC5C,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,MAAM,OAAO,CAAC,IAAI,CAAkB,GAC/C,OAAO,CAAC,IAAI,CAAC,CAmEf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lima-guest-binary.js","sourceRoot":"","sources":["../../../src/core/sandbox/lima-guest-binary.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { open, realpath, stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { SandboxRunner } from \"./config.ts\";\n\nfunction quote(value: string): string {\n\treturn `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nexport interface LocalGuestBinary {\n\tpath: string;\n\tarch: string;\n\tsha256: string;\n}\n\n/** Refuse macOS executables in Linux VMs, even when the host CPU architecture matches. */\nexport async function inspectLocalGuestBinary(path: string): Promise<LocalGuestBinary> {\n\tconst absolute = await realpath(resolve(path));\n\tconst file = await stat(absolute);\n\tif (!file.isFile()) throw new Error(\"GRIP_SANDBOX_GUEST_BINARY must be a regular file\");\n\tconst handle = await open(absolute, \"r\");\n\tlet header: Buffer;\n\ttry {\n\t\theader = Buffer.alloc(20);\n\t\tif ((await handle.read(header, 0, 20, 0)).bytesRead !== 20) throw new Error(\"Invalid Linux guest binary\");\n\t} finally {\n\t\tawait handle.close();\n\t}\n\tif (header.toString(\"hex\", 0, 4) !== \"7f454c46\" || header[4] !== 2 || header[5] !== 1) {\n\t\tthrow new Error(\"GRIP_SANDBOX_GUEST_BINARY must be a 64-bit Linux ELF executable\");\n\t}\n\tconst arch = { 62: \"x86_64\", 183: \"aarch64\" }[header.readUInt16LE(18)];\n\tif (!arch) throw new Error(\"Unsupported Linux guest binary architecture\");\n\tconst digest = createHash(\"sha256\");\n\tfor await (const chunk of createReadStream(absolute)) digest.update(chunk);\n\t// Reject a file changed during validation rather than copying bytes with an unverified digest.\n\tconst after = await stat(absolute);\n\tif (file.dev !== after.dev || file.ino !== after.ino || file.size !== after.size || file.mtimeMs !== after.mtimeMs) {\n\t\tthrow new Error(\"Local guest binary changed during validation; rebuild and retry\");\n\t}\n\treturn { path: absolute, arch, sha256: digest.digest(\"hex\") };\n}\n\nconst noDaemon = (removeStalePid: boolean) =>\n\t[\n\t\t\"test -r /proc/1/comm || exit 40\",\n\t\t\"for process in /proc/[0-9]*; do\",\n\t\t' test -d \"$process\" || continue',\n\t\t' comm=\"$(cat \"$process/comm\" 2>/dev/null)\" || { test ! -e \"$process\" || exit 40; continue; }',\n\t\t' if test \"$comm\" = grip; then exit 41; fi',\n\t\t' case \"$comm\" in node|bun) ;; *) continue;; esac',\n\t\t' cmdline=\"$(tr \"\\\\000\" \" \" <\"$process/cmdline\" 2>/dev/null)\" || { test ! -e \"$process\" || exit 40; continue; }',\n\t\t' case \"$cmdline\" in *\"/grip --daemon\"*|*\"/grip/dist/cli\"*) exit 41;; esac',\n\t\t\"done\",\n\t\t'test ! -e \"$HOME/.cache/grip/shared-lima\" && test ! -L \"$HOME/.cache/grip/shared-lima\" || exit 42',\n\t\t'for marker in \"$HOME/.cache/grip\"/sandbox-daemon-*.pid; do',\n\t\t' if test -e \"$marker\" || test -L \"$marker\"; then',\n\t\t' test -f \"$marker\" && test ! -L \"$marker\" && test \"$(stat -c %u \"$marker\")\" = \"$(id -u)\" || exit 42',\n\t\t' pid=\"$(cat \"$marker\")\" || exit 42',\n\t\t' case \"$pid\" in \"\"|0|*[!0-9]*) exit 42;; esac',\n\t\t' test ! -e \"/proc/$pid\" || exit 42',\n\t\t\" fi\",\n\t\t\"done\",\n\t\t...(removeStalePid\n\t\t\t? [\n\t\t\t\t\t'for marker in \"$HOME/.cache/grip\"/sandbox-daemon-*.pid; do',\n\t\t\t\t\t' if test -e \"$marker\" || test -L \"$marker\"; then',\n\t\t\t\t\t' test -f \"$marker\" && test ! -L \"$marker\" && test \"$(stat -c %u \"$marker\")\" = \"$(id -u)\" || exit 42',\n\t\t\t\t\t' pid=\"$(cat \"$marker\")\" || exit 42',\n\t\t\t\t\t' case \"$pid\" in \"\"|0|*[!0-9]*) exit 42;; esac',\n\t\t\t\t\t' test ! -e \"/proc/$pid\" || exit 42',\n\t\t\t\t\t' rm -- \"$marker\" || exit 42',\n\t\t\t\t\t\" fi\",\n\t\t\t\t\t\"done\",\n\t\t\t\t]\n\t\t\t: []),\n\t].join(\"\\n\");\n\n/** Called only for explicitly requested local-development installs. No remote download or sudo. */\nexport async function installLocalGuestBinary(\n\trunner: SandboxRunner,\n\tlimaBinary: string,\n\tname: string,\n\tlocal: LocalGuestBinary,\n\tversion: string,\n\tassertOwner: () => Promise<void> = async () => {},\n): Promise<void> {\n\tif (!/^[a-z0-9][a-z0-9-]*$/.test(name)) throw new Error(\"Invalid Lima instance name for local binary copy\");\n\tconst shell = async (script: string) => runner.run(limaBinary, [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script]);\n\tawait assertOwner();\n\tconst probe = await shell(\n\t\t[\n\t\t\t\"set -eu\",\n\t\t\t'test \"$(uname -s)\" = Linux',\n\t\t\t`test \"$(uname -m)\" = ${quote(local.arch)}`,\n\t\t\t'target=\"$HOME/.local/bin/grip\"',\n\t\t\t'if test ! -L \"$HOME/.local\" && test ! -L \"$HOME/.local/bin\" && test -f \"$target\" && test ! -L \"$target\"; then',\n\t\t\t` if test \"$(sha256sum \"$target\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)} && test \"$(\"$target\" --version)\" = ${quote(version)}; then`,\n\t\t\t\" printf 'GRIP_GUEST_BINARY_MATCH\\\\n'\",\n\t\t\t\" exit 0\",\n\t\t\t\" fi\",\n\t\t\t\"fi\",\n\t\t\tnoDaemon(false),\n\t\t].join(\"\\n\"),\n\t);\n\tif (probe.exitCode !== 0)\n\t\tthrow new Error(\n\t\t\t\"Lima guest architecture or Grip daemon state is incompatible/uncertain; local binary was not copied\",\n\t\t);\n\tif (probe.stdout.trim() === \"GRIP_GUEST_BINARY_MATCH\") {\n\t\tawait assertOwner();\n\t\treturn;\n\t}\n\tconst stage = `/tmp/grip-guest-${randomBytes(12).toString(\"hex\")}`;\n\tconst created = await shell(`set -eu; umask 077; mkdir ${quote(stage)}; test ! -L ${quote(stage)}`);\n\tif (created.exitCode !== 0) throw new Error(\"Could not reserve a private guest binary staging directory\");\n\ttry {\n\t\tawait assertOwner();\n\t\tconst copied = await runner.run(limaBinary, [\"copy\", local.path, `${name}:${stage}/grip`]);\n\t\tif (copied.exitCode !== 0) throw new Error(\"Lima guest binary copy failed; installed binary was not changed\");\n\t\tawait assertOwner();\n\t\tconst script = [\n\t\t\t\"set -eu\",\n\t\t\t\"umask 077\",\n\t\t\t`stage=${quote(stage)}`,\n\t\t\t'test -f \"$stage/grip\" && test ! -L \"$stage/grip\"',\n\t\t\t`test \"$(sha256sum \"$stage/grip\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)}`,\n\t\t\t'chmod 700 \"$stage/grip\"',\n\t\t\t`test \"$(\"$stage/grip\" --version)\" = ${quote(version)}`,\n\t\t\t'mkdir -p \"$HOME/.cache/grip\"',\n\t\t\t'mode_lock=\"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t'mkdir \"$mode_lock\" || exit 43',\n\t\t\t\"trap 'rmdir \\\"$mode_lock\\\" 2>/dev/null || true' EXIT\",\n\t\t\tnoDaemon(true),\n\t\t\t'mkdir -p \"$HOME/.local/bin\"',\n\t\t\t'test ! -L \"$HOME/.local\" && test ! -L \"$HOME/.local/bin\"',\n\t\t\t'target=\"$HOME/.local/bin/grip\"',\n\t\t\t'test ! -L \"$target\" && { test ! -e \"$target\" || test -f \"$target\"; }',\n\t\t\t'tmp=\"$HOME/.local/bin/.grip-install-$(basename \"$stage\")\"',\n\t\t\t'test ! -e \"$tmp\" && test ! -L \"$tmp\"',\n\t\t\t'cp \"$stage/grip\" \"$tmp\"; chmod 700 \"$tmp\"',\n\t\t\t`test \"$(sha256sum \"$tmp\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)}`,\n\t\t\t'mv -f \"$tmp\" \"$target\"',\n\t\t].join(\"\\n\");\n\t\tconst installed = await shell(script);\n\t\tif (installed.exitCode !== 0)\n\t\t\tthrow new Error(\"Lima guest binary install failed or is uncertain; inspect guest state before retrying\");\n\t} finally {\n\t\t// Never remove an uncertain target; the private staging directory is the only cleanup target.\n\t\tawait shell(`test -d ${quote(stage)} && rm -f ${quote(`${stage}/grip`)} && rmdir ${quote(stage)}`).catch(\n\t\t\t() => undefined,\n\t\t);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lima-guest-binary.js","sourceRoot":"","sources":["../../../src/core/sandbox/lima-guest-binary.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { open, realpath, stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { SandboxRunner } from \"./config.ts\";\n\nfunction quote(value: string): string {\n\treturn `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nexport interface LocalGuestBinary {\n\tpath: string;\n\tarch: string;\n\tsha256: string;\n}\n\n/** Refuse macOS executables in Linux VMs, even when the host CPU architecture matches. */\nexport async function inspectLocalGuestBinary(path: string): Promise<LocalGuestBinary> {\n\tconst absolute = await realpath(resolve(path));\n\tconst file = await stat(absolute);\n\tif (!file.isFile()) throw new Error(\"GRIP_SANDBOX_GUEST_BINARY must be a regular file\");\n\tconst handle = await open(absolute, \"r\");\n\tlet header: Buffer;\n\ttry {\n\t\theader = Buffer.alloc(20);\n\t\tif ((await handle.read(header, 0, 20, 0)).bytesRead !== 20) throw new Error(\"Invalid Linux guest binary\");\n\t} finally {\n\t\tawait handle.close();\n\t}\n\tif (header.toString(\"hex\", 0, 4) !== \"7f454c46\" || header[4] !== 2 || header[5] !== 1) {\n\t\tthrow new Error(\"GRIP_SANDBOX_GUEST_BINARY must be a 64-bit Linux ELF executable\");\n\t}\n\tconst arch = { 62: \"x86_64\", 183: \"aarch64\" }[header.readUInt16LE(18)];\n\tif (!arch) throw new Error(\"Unsupported Linux guest binary architecture\");\n\tconst digest = createHash(\"sha256\");\n\tfor await (const chunk of createReadStream(absolute)) digest.update(chunk);\n\t// Reject a file changed during validation rather than copying bytes with an unverified digest.\n\tconst after = await stat(absolute);\n\tif (file.dev !== after.dev || file.ino !== after.ino || file.size !== after.size || file.mtimeMs !== after.mtimeMs) {\n\t\tthrow new Error(\"Local guest binary changed during validation; rebuild and retry\");\n\t}\n\treturn { path: absolute, arch, sha256: digest.digest(\"hex\") };\n}\n\nconst noDaemon = (removeStalePid: boolean) =>\n\t[\n\t\t\"test -r /proc/1/comm || exit 40\",\n\t\t\"for process in /proc/[0-9]*; do\",\n\t\t' test -d \"$process\" || continue',\n\t\t' comm=\"$(cat \"$process/comm\" 2>/dev/null)\" || { test ! -e \"$process\" || exit 40; continue; }',\n\t\t' if test \"$comm\" = grip; then exit 41; fi',\n\t\t' case \"$comm\" in node|bun) ;; *) continue;; esac',\n\t\t' cmdline=\"$(tr \"\\\\000\" \" \" <\"$process/cmdline\" 2>/dev/null)\" || { test ! -e \"$process\" || exit 40; continue; }',\n\t\t' case \"$cmdline\" in *\"/grip --daemon\"*|*\"/grip/dist/cli\"*) exit 41;; esac',\n\t\t\"done\",\n\t\t'test ! -e \"$HOME/.cache/grip/shared-lima\" && test ! -L \"$HOME/.cache/grip/shared-lima\" || exit 42',\n\t\t'for marker in \"$HOME/.cache/grip\"/sandbox-daemon-*.pid; do',\n\t\t' if test -e \"$marker\" || test -L \"$marker\"; then',\n\t\t' test -f \"$marker\" && test ! -L \"$marker\" && test \"$(stat -c %u \"$marker\")\" = \"$(id -u)\" || exit 42',\n\t\t' pid=\"$(cat \"$marker\")\" || exit 42',\n\t\t' case \"$pid\" in \"\"|0|*[!0-9]*) exit 42;; esac',\n\t\t' test ! -e \"/proc/$pid\" || exit 42',\n\t\t\" fi\",\n\t\t\"done\",\n\t\t...(removeStalePid\n\t\t\t? [\n\t\t\t\t\t'for marker in \"$HOME/.cache/grip\"/sandbox-daemon-*.pid; do',\n\t\t\t\t\t' if test -e \"$marker\" || test -L \"$marker\"; then',\n\t\t\t\t\t' test -f \"$marker\" && test ! -L \"$marker\" && test \"$(stat -c %u \"$marker\")\" = \"$(id -u)\" || exit 42',\n\t\t\t\t\t' pid=\"$(cat \"$marker\")\" || exit 42',\n\t\t\t\t\t' case \"$pid\" in \"\"|0|*[!0-9]*) exit 42;; esac',\n\t\t\t\t\t' test ! -e \"/proc/$pid\" || exit 42',\n\t\t\t\t\t' rm -- \"$marker\" || exit 42',\n\t\t\t\t\t\" fi\",\n\t\t\t\t\t\"done\",\n\t\t\t\t]\n\t\t\t: []),\n\t].join(\"\\n\");\n\n/** Called only for explicitly requested local-development installs. No remote download or sudo. */\nexport async function installLocalGuestBinary(\n\trunner: SandboxRunner,\n\tlimaBinary: string,\n\tname: string,\n\tlocal: LocalGuestBinary,\n\tversion: string,\n\tassertOwner: () => Promise<void> = async () => {},\n): Promise<void> {\n\tif (!/^[a-z0-9][a-z0-9-]*$/.test(name)) throw new Error(\"Invalid Lima instance name for local binary copy\");\n\tconst shell = async (script: string) => runner.run(limaBinary, [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script]);\n\tawait assertOwner();\n\tconst probe = await shell(\n\t\t[\n\t\t\t\"set -eu\",\n\t\t\t'test \"$(uname -s)\" = Linux',\n\t\t\t`test \"$(uname -m)\" = ${quote(local.arch)}`,\n\t\t\t'target=\"$HOME/.local/bin/grip\"',\n\t\t\t'if test ! -L \"$HOME/.local\" && test ! -L \"$HOME/.local/bin\" && test -f \"$target\" && test ! -L \"$target\"; then',\n\t\t\t` if test \"$(sha256sum \"$target\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)} && test \"$(\"$target\" --version)\" = ${quote(version)}; then`,\n\t\t\t\" printf 'GRIP_GUEST_BINARY_MATCH\\\\n'\",\n\t\t\t\" exit 0\",\n\t\t\t\" fi\",\n\t\t\t\"fi\",\n\t\t\tnoDaemon(false),\n\t\t].join(\"\\n\"),\n\t);\n\tif (probe.exitCode !== 0)\n\t\tthrow new Error(\n\t\t\t\"Lima guest architecture or Grip daemon state is incompatible/uncertain; local binary was not copied\",\n\t\t);\n\tif (probe.stdout.trim() === \"GRIP_GUEST_BINARY_MATCH\") {\n\t\tawait assertOwner();\n\t\treturn;\n\t}\n\tconst stage = `/tmp/grip-guest-${randomBytes(12).toString(\"hex\")}`;\n\tconst created = await shell(`set -eu; umask 077; mkdir ${quote(stage)}; test ! -L ${quote(stage)}`);\n\tif (created.exitCode !== 0) throw new Error(\"Could not reserve a private guest binary staging directory\");\n\ttry {\n\t\tawait assertOwner();\n\t\tconst copied = await runner.run(limaBinary, [\"copy\", local.path, `${name}:${stage}/grip`]);\n\t\tif (copied.exitCode !== 0) throw new Error(\"Lima guest binary copy failed; installed binary was not changed\");\n\t\tawait assertOwner();\n\t\tconst script = [\n\t\t\t\"set -eu\",\n\t\t\t\"umask 077\",\n\t\t\t`stage=${quote(stage)}`,\n\t\t\t'test -f \"$stage/grip\" && test ! -L \"$stage/grip\"',\n\t\t\t`test \"$(sha256sum \"$stage/grip\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)}`,\n\t\t\t'chmod 700 \"$stage/grip\"',\n\t\t\t`test \"$(\"$stage/grip\" --version)\" = ${quote(version)}`,\n\t\t\t'mkdir -p \"$HOME/.cache/grip\"',\n\t\t\t'mode_lock=\"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t'mkdir \"$mode_lock\" || exit 43',\n\t\t\t\"trap 'rmdir \\\"$mode_lock\\\" 2>/dev/null || true' EXIT\",\n\t\t\tnoDaemon(true),\n\t\t\t'mkdir -p \"$HOME/.local/bin\"',\n\t\t\t'test ! -L \"$HOME/.local\" && test ! -L \"$HOME/.local/bin\"',\n\t\t\t'target=\"$HOME/.local/bin/grip\"',\n\t\t\t'test ! -L \"$target\" && { test ! -e \"$target\" || test -f \"$target\"; }',\n\t\t\t'tmp=\"$HOME/.local/bin/.grip-install-$(basename \"$stage\")\"',\n\t\t\t'test ! -e \"$tmp\" && test ! -L \"$tmp\"',\n\t\t\t'cp \"$stage/grip\" \"$tmp\"; chmod 700 \"$tmp\"',\n\t\t\t`test \"$(sha256sum \"$tmp\" | cut -d ' ' -f 1)\" = ${quote(local.sha256)}`,\n\t\t\t'mv -f \"$tmp\" \"$target\"',\n\t\t].join(\"\\n\");\n\t\tconst installed = await shell(script);\n\t\tif (installed.exitCode !== 0)\n\t\t\tthrow new Error(\"Lima guest binary install failed or is uncertain; inspect guest state before retrying\");\n\t} finally {\n\t\t// Never remove an uncertain target; the private staging directory is the only cleanup target.\n\t\tawait shell(`test -d ${quote(stage)} && rm -f ${quote(`${stage}/grip`)} && rmdir ${quote(stage)}`).catch(\n\t\t\t() => undefined,\n\t\t);\n\t}\n}\n"]}
|
|
@@ -39,9 +39,11 @@ export declare class LimaSandboxService {
|
|
|
39
39
|
inspectSharedInstance(options: SharedLimaInstanceOptions): Promise<SharedLimaInstanceInspection>;
|
|
40
40
|
/** Reinspect and reuse the supervised guest daemon under the exclusive named-VM owner lock. */
|
|
41
41
|
ensureSharedDaemon(options: SharedLimaInstanceOptions, owner: SharedLimaOwnerLock, updated?: boolean): Promise<string>;
|
|
42
|
+
/** Update only a verified supervised daemon. Staging happens before disconnecting peers. */
|
|
42
43
|
private updateSharedDaemon;
|
|
43
44
|
private startInstance;
|
|
44
45
|
private ensureGrip;
|
|
46
|
+
/** A legacy named attach or stop must not rotate or kill a shared guest daemon. */
|
|
45
47
|
private assertNoSharedGuestState;
|
|
46
48
|
private startDaemon;
|
|
47
49
|
private prepareExistingInstance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lima.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/lima.ts"],"names":[],"mappings":"AAOA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AACvH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAGX,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAA8B,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAErG,MAAM,WAAW,4BAA6B,SAAQ,0BAA0B;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACzC,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACpD;AA0KD,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0D;IAC1F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2D;IACzF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmC;IAEpE,YAAY,OAAO,GAAE,yBAA8B,EAOlD;IAED,aAAa,CAAC,SAAS,GAAE,sBAA2B,GAAG,aAAa,CAEnE;YAEa,WAAW;IAmBzB,+FAA+F;IACzF,qBAAqB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAwCrG;IACD,+FAA+F;IACzF,kBAAkB,CACvB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,mBAAmB,EAC1B,OAAO,UAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CA8GjB;YAGa,kBAAkB;YA4GlB,aAAa;YAuBb,UAAU;YA8BV,wBAAwB;YAcxB,WAAW;YA2BX,uBAAuB;YAqBvB,uBAAuB;IAU/B,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8DrE;YAEa,uBAAuB;IA8C/B,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAQnE;YAEa,UAAU;IAOlB,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuClE;YAEa,mBAAmB;IAyB3B,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAU1C;CACD","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { realpath } from \"node:fs/promises\";\nimport { createConnection } from \"node:net\";\nimport { basename, resolve } from \"node:path\";\nimport { VERSION } from \"../../config.ts\";\nimport { DAEMON_WEBSOCKET_PATH } from \"../../daemon/config.ts\";\nimport { spawnProcess } from \"../../utils/child-process.ts\";\nimport { acquireSharedLimaOwnerLock, type SharedLimaOwnerLock } from \"../remote-workspace-protocol/lima-owner-lock.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\nimport type {\n\tSandboxCommandOptions,\n\tSandboxCommandResult,\n\tSandboxConfig,\n\tSandboxConfigOverrides,\n\tSandboxContainer,\n\tSandboxListOptions,\n\tSandboxRunner,\n\tSandboxStartOptions,\n\tSandboxStartResult,\n\tSandboxStopOptions,\n\tSandboxStopResult,\n} from \"./config.ts\";\nimport { allocateSandboxDaemonPort, redactSecrets, resolveSandboxConfig, SANDBOX_LABEL_PREFIX } from \"./config.ts\";\nimport { inspectLocalGuestBinary, installLocalGuestBinary, type LocalGuestBinary } from \"./lima-guest-binary.ts\";\nimport { resolveSharedLimaWorkspace, type SharedLimaWorkspaceBinding } from \"./shared-lima-roots.ts\";\nimport { stageSharedGuestBinary } from \"./update-shared-guest-binary.ts\";\nexport interface SharedLimaInstanceInspection extends SharedLimaWorkspaceBinding {\n\tinstanceName: string;\n\tdaemonUrl: string;\n}\n\nexport interface SharedLimaInstanceOptions {\n\tinstanceName: string;\n\thostParent: string;\n\thostRoot: string;\n}\n\nexport interface ManagedLimaInstance {\n\tworkspaceRoot: string;\n\tdaemonPort: number;\n\townerId?: string;\n\tmanaged: boolean;\n}\n\nexport interface LimaSandboxServiceOptions {\n\tsettingsManager?: Pick<SettingsManager, \"getSandboxSettings\">;\n\tenv?: NodeJS.ProcessEnv;\n\trunner?: SandboxRunner;\n\tportAllocator?: (host: string, preferredPort: number) => Promise<number>;\n\treadinessWaiter?: (host: string, port: number) => Promise<void>;\n\tmanagedInstances?: Map<string, ManagedLimaInstance>;\n}\n\ninterface LimaMount {\n\tlocation?: string;\n\tmountPoint?: string;\n\twritable?: boolean;\n}\n\ninterface LimaPortForward {\n\tguestPort?: number;\n\thostPort?: number;\n\thostIP?: string;\n}\n\ninterface LimaConfig {\n\tmounts?: LimaMount[];\n\tportForwards?: LimaPortForward[];\n}\n\ninterface LimaListRecord {\n\tname?: string;\n\tstatus?: string;\n\tarch?: string;\n\tvmType?: string;\n\tdir?: string;\n\tconfig?: LimaConfig;\n}\n\ninterface KnownLimaRecord {\n\trecord: LimaListRecord | undefined;\n}\n\nclass ProcessLimaRunner implements SandboxRunner {\n\trun(command: string, args: string[], options: SandboxCommandOptions = {}): Promise<SandboxCommandResult> {\n\t\treturn new Promise((resolveCommand, reject) => {\n\t\t\tconst child = spawnProcess(command, args, {\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\tenv: { ...process.env, ...options.env },\n\t\t\t});\n\t\t\tlet stdout = \"\";\n\t\t\tlet stderr = \"\";\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tstdout += chunk.toString(\"utf8\");\n\t\t\t});\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tstderr += chunk.toString(\"utf8\");\n\t\t\t});\n\t\t\tchild.once(\"error\", reject);\n\t\t\tchild.once(\"close\", (exitCode) => resolveCommand({ exitCode, stdout, stderr }));\n\t\t});\n\t}\n}\n\nfunction shellQuote(value: string): string {\n\treturn `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction parseLimaRecords(output: string): LimaListRecord[] {\n\tconst text = output.trim();\n\tif (!text) return [];\n\ttry {\n\t\tconst parsed = JSON.parse(text) as unknown;\n\t\treturn Array.isArray(parsed) ? (parsed as LimaListRecord[]) : [parsed as LimaListRecord];\n\t} catch {\n\t\treturn text\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.filter(Boolean)\n\t\t\t.map((line) => JSON.parse(line) as LimaListRecord);\n\t}\n}\n\nfunction ensureLimaSuccessful(binary: string, result: SandboxCommandResult, args: string[]): void {\n\tif (result.exitCode === 0) return;\n\tconst detail = result.stderr.trim() || result.stdout.trim() || `exit code ${result.exitCode ?? \"unknown\"}`;\n\tthrow new Error(redactSecrets(`Lima command failed: ${binary} ${args.join(\" \")}: ${detail}`));\n}\n\nfunction daemonConnectionHost(host: string): string {\n\tif (host === \"0.0.0.0\") return \"127.0.0.1\";\n\tif (host === \"::\") return \"::1\";\n\treturn host;\n}\n\nfunction urlHost(host: string): string {\n\treturn host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host;\n}\n\nasync function canConnect(host: string, port: number): Promise<boolean> {\n\treturn new Promise((resolveConnection) => {\n\t\tconst socket = createConnection({ host, port });\n\t\tlet settled = false;\n\t\tconst finish = (connected: boolean): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tsocket.destroy();\n\t\t\tresolveConnection(connected);\n\t\t};\n\t\tsocket.setTimeout(250, () => finish(false));\n\t\tsocket.once(\"connect\", () => finish(true));\n\t\tsocket.once(\"error\", () => finish(false));\n\t});\n}\n\nasync function waitForLimaDaemon(host: string, port: number): Promise<void> {\n\tconst deadline = Date.now() + 30_000;\n\twhile (Date.now() < deadline) {\n\t\tif (await canConnect(daemonConnectionHost(host), port)) return;\n\t\tawait new Promise((resolveDelay) => setTimeout(resolveDelay, 100));\n\t}\n\tthrow new Error(`Lima sandbox daemon did not become reachable on ${daemonConnectionHost(host)}:${port}`);\n}\n\nfunction createInstanceName(\n\tconfig: SandboxConfig,\n\tworkspaceRoot: string,\n\tsessionId: string,\n\tdaemonPort: number,\n): string {\n\tconst clean = (value: string): string =>\n\t\tvalue\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9-]+/g, \"-\")\n\t\t\t.replace(/^-+|-+$/g, \"\") || \"workspace\";\n\tconst hash = createHash(\"sha256\").update(resolve(workspaceRoot)).digest(\"hex\").slice(0, 12);\n\treturn `${clean(config.limaInstanceNamePrefix)}-${clean(basename(resolve(workspaceRoot)))}-${hash}-${clean(sessionId).slice(0, 8).replace(/-+$/, \"\")}-p${daemonPort}-${randomBytes(4).toString(\"hex\")}`;\n}\n\nfunction findWorkspaceMount(record: LimaListRecord, workspaceMountPath: string): LimaMount | undefined {\n\treturn record.config?.mounts?.find((mount) => mount.mountPoint === workspaceMountPath);\n}\n\nfunction findDaemonForward(record: LimaListRecord, preferredPort?: number): LimaPortForward | undefined {\n\tconst namePort = Number(record.name?.match(/-p(\\d+)-[a-f0-9]+$/)?.[1]);\n\tconst daemonPort = Number.isInteger(namePort) && namePort > 0 ? namePort : preferredPort;\n\tconst forwards = record.config?.portForwards?.filter(\n\t\t(forward) => forward.guestPort === forward.hostPort && forward.hostPort !== undefined,\n\t);\n\treturn (\n\t\tforwards?.find((forward) => forward.guestPort === daemonPort) ??\n\t\t(forwards?.length === 1 ? forwards[0] : undefined)\n\t);\n}\n\nfunction toSandboxContainer(record: LimaListRecord, workspaceMountPath: string): SandboxContainer {\n\tconst mount = findWorkspaceMount(record, workspaceMountPath);\n\tconst forward = findDaemonForward(record);\n\tconst daemonEndpoint = forward?.hostPort\n\t\t? `ws://${urlHost(daemonConnectionHost(forward.hostIP || \"127.0.0.1\"))}:${forward.hostPort}${DAEMON_WEBSOCKET_PATH}`\n\t\t: undefined;\n\treturn {\n\t\tid: record.name ?? \"\",\n\t\tname: record.name ?? \"\",\n\t\timage: `lima:${record.vmType ?? \"vm\"}/${record.arch ?? \"unknown\"}`,\n\t\tstatus: record.status ?? \"\",\n\t\tstate: record.status?.toLowerCase(),\n\t\tcreatedAt: undefined,\n\t\tworkspaceRoot: mount?.location ? resolve(mount.location) : undefined,\n\t\tworkspaceMountPath: mount?.mountPoint,\n\t\tdaemonPort: forward?.guestPort,\n\t\tdaemonEndpoint,\n\t\tlabels: { [`${SANDBOX_LABEL_PREFIX}.runtime`]: \"lima\", [`${SANDBOX_LABEL_PREFIX}.version`]: VERSION },\n\t};\n}\n\nfunction selectLimaSandbox(instances: SandboxContainer[], target: string | undefined): SandboxContainer | undefined {\n\tif (!target) return instances.length === 1 ? instances[0] : undefined;\n\treturn instances.find((instance) => instance.name === target || instance.id.startsWith(target));\n}\ntype LegacyLimaGuestStateOperation = \"attach\" | \"stop\";\n\nexport class LimaSandboxService {\n\tprivate readonly settingsManager: Pick<SettingsManager, \"getSandboxSettings\"> | undefined;\n\tprivate readonly env: NodeJS.ProcessEnv;\n\tprivate readonly runner: SandboxRunner;\n\tprivate readonly portAllocator: (host: string, preferredPort: number) => Promise<number>;\n\tprivate readonly readinessWaiter: (host: string, port: number) => Promise<void>;\n\tprivate readonly managedInstances: Map<string, ManagedLimaInstance>;\n\n\tconstructor(options: LimaSandboxServiceOptions = {}) {\n\t\tthis.settingsManager = options.settingsManager;\n\t\tthis.env = options.env ?? process.env;\n\t\tthis.runner = options.runner ?? new ProcessLimaRunner();\n\t\tthis.portAllocator = options.portAllocator ?? allocateSandboxDaemonPort;\n\t\tthis.readinessWaiter = options.readinessWaiter ?? waitForLimaDaemon;\n\t\tthis.managedInstances = options.managedInstances ?? new Map();\n\t}\n\n\tresolveConfig(overrides: SandboxConfigOverrides = {}): SandboxConfig {\n\t\treturn resolveSandboxConfig(this.settingsManager?.getSandboxSettings(), this.env, overrides);\n\t}\n\n\tprivate async listRecords(config: SandboxConfig, name?: string): Promise<LimaListRecord[]> {\n\t\tconst args = [\"list\", \"--json\", ...(name ? [name] : [])];\n\t\ttry {\n\t\t\tconst result = await this.runner.run(config.limaBinary, args);\n\t\t\tif (\n\t\t\t\tname &&\n\t\t\t\tresult.exitCode !== 0 &&\n\t\t\t\t/unmatched|not found|does not exist/i.test(`${result.stderr}\\n${result.stdout}`)\n\t\t\t) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tensureLimaSuccessful(config.limaBinary, result, args);\n\t\t\treturn parseLimaRecords(result.stdout);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(redactSecrets(`Lima is unavailable or not reachable via ${config.limaBinary}: ${message}`));\n\t\t}\n\t}\n\n\t/** Read-only validation: no VM creation, daemon restart, token rotation or ownership claim. */\n\tasync inspectSharedInstance(options: SharedLimaInstanceOptions): Promise<SharedLimaInstanceInspection> {\n\t\tconst config = this.resolveConfig();\n\t\tconst { instanceName } = options;\n\t\tif (!/^[a-z0-9][a-z0-9-]*$/.test(instanceName)) throw new Error(\"Invalid shared Lima instance name\");\n\t\tif (config.daemonHostBind !== \"127.0.0.1\" && config.daemonHostBind !== \"::1\") {\n\t\t\tthrow new Error(\"Shared Lima daemon forward must bind to loopback\");\n\t\t}\n\t\tconst binding = await resolveSharedLimaWorkspace(options.hostParent, config.workspaceMountPath, options.hostRoot);\n\t\tconst records = await this.listRecords(config, instanceName);\n\t\tif (records.length !== 1 || records[0]?.name !== instanceName) {\n\t\t\tthrow new Error(`Shared Lima instance ${instanceName} does not exist by exact name`);\n\t\t}\n\t\tconst record = records[0];\n\t\tif (record.status?.toLowerCase() !== \"running\") {\n\t\t\tthrow new Error(`Shared Lima instance ${instanceName} is not running`);\n\t\t}\n\t\tconst mounts = record.config?.mounts?.filter((mount) => mount.mountPoint === binding.guestParent) ?? [];\n\t\tif (mounts.length !== 1 || !mounts[0]?.writable || !mounts[0].location) {\n\t\t\tthrow new Error(`Shared Lima instance ${instanceName} requires one writable fixed parent mount`);\n\t\t}\n\t\tif ((await realpath(mounts[0].location)) !== binding.hostParent) {\n\t\t\tthrow new Error(`Shared Lima instance ${instanceName} mounts a different host parent`);\n\t\t}\n\t\tconst forwards =\n\t\t\trecord.config?.portForwards?.filter(\n\t\t\t\t(forward) => forward.guestPort === config.daemonPort || forward.hostPort === config.daemonPort,\n\t\t\t) ?? [];\n\t\tif (\n\t\t\tforwards.length !== 1 ||\n\t\t\tforwards[0]?.guestPort !== config.daemonPort ||\n\t\t\tforwards[0].hostPort !== config.daemonPort ||\n\t\t\tforwards[0].hostIP !== config.daemonHostBind\n\t\t) {\n\t\t\tthrow new Error(`Shared Lima instance ${instanceName} requires one matching loopback daemon forward`);\n\t\t}\n\t\treturn {\n\t\t\t...binding,\n\t\t\tinstanceName,\n\t\t\tdaemonUrl: `ws://${urlHost(config.daemonHostBind)}:${config.daemonPort}${DAEMON_WEBSOCKET_PATH}`,\n\t\t};\n\t}\n\t/** Reinspect and reuse the supervised guest daemon under the exclusive named-VM owner lock. */\n\tasync ensureSharedDaemon(\n\t\toptions: SharedLimaInstanceOptions,\n\t\towner: SharedLimaOwnerLock,\n\t\tupdated = false,\n\t): Promise<string> {\n\t\tif (owner.instanceName !== options.instanceName) throw new Error(\"Shared Lima owner lock names a different VM\");\n\t\tawait owner.assertHeld();\n\t\tawait this.inspectSharedInstance(options);\n\t\tconst config = this.resolveConfig();\n\t\tconst local = this.env.GRIP_SANDBOX_GUEST_BINARY\n\t\t\t? await inspectLocalGuestBinary(this.env.GRIP_SANDBOX_GUEST_BINARY)\n\t\t\t: undefined;\n\t\tconst versionArgs = [\n\t\t\t\"shell\",\n\t\t\t\"--tty=false\",\n\t\t\toptions.instanceName,\n\t\t\t\"sh\",\n\t\t\t\"-lc\",\n\t\t\tlocal || updated ? '\"$HOME/.local/bin/grip\" --version' : \"grip --version\",\n\t\t];\n\t\tconst version = await this.runner.run(config.limaBinary, versionArgs);\n\t\tif (version.exitCode !== 0 || version.stdout.trim() !== VERSION) {\n\t\t\tthrow new Error(\"Shared Lima grip version mismatch or binary missing; install the matching version manually\");\n\t\t}\n\t\tawait owner.assertHeld();\n\t\tconst directory = \"$HOME/.cache/grip/shared-lima\";\n\t\t// /proc start time plus boot ID distinguishes a recycled PID or a rebooted guest.\n\t\t// kill -0 also succeeds for zombies, which must never be reused as a live daemon.\n\t\tconst processStartTime = `awk '{ sub(/^.*\\\\) /, \"\"); if ($1 == \"Z\" || $1 == \"X\") exit 1; print $20 }'`;\n\t\tconst script = [\n\t\t\t\"set -eu\",\n\t\t\t\"umask 077\",\n\t\t\t`directory=\"${directory}\"`,\n\t\t\t// Both current modes reserve the guest transition; a crashed reservation is operator-owned.\n\t\t\t'mkdir -p \"$HOME/.cache/grip\"',\n\t\t\t'mode_lock=\"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t'mkdir \"$mode_lock\" || exit 28',\n\t\t\t\"trap 'rmdir \\\"$mode_lock\\\" 2>/dev/null || true' EXIT\",\n\t\t\t// A legacy per-session daemon may own this VM or its port. Do not start a second daemon.\n\t\t\t'for legacy_file in \"$HOME/.cache/grip\"/sandbox-daemon-*.pid \"$HOME/.cache/grip\"/sandbox-daemon-*.log; do',\n\t\t\t' if test -e \"$legacy_file\" || test -L \"$legacy_file\"; then exit 27; fi',\n\t\t\t\"done\",\n\t\t\t// A transient user service must outlive the Lima SSH session. Do not mutate\n\t\t\t// private state unless the guest manager is running and linger was enabled by an operator.\n\t\t\t\"command -v systemd-run >/dev/null && systemctl --user show-environment >/dev/null || exit 29\",\n\t\t\t'test \"$(loginctl show-user \"$(id -un)\" --property=Linger --value)\" = yes || exit 29',\n\t\t\t`mkdir -p \"$directory\"; test ! -L \"$directory\"; chmod 700 \"$directory\"`,\n\t\t\t'rmdir \"$mode_lock\" || exit 28',\n\t\t\t\"trap - EXIT\",\n\t\t\t`token_file=\"$directory/daemon-${config.daemonPort}.token\"`,\n\t\t\t`pid_file=\"$directory/daemon-${config.daemonPort}.pid\"`,\n\t\t\t`identity_file=\"$directory/daemon-${config.daemonPort}.identity\"`,\n\t\t\t`log_file=\"$directory/daemon-${config.daemonPort}.log\"`,\n\t\t\t`start_lock=\"$directory/daemon-${config.daemonPort}.starting\"`,\n\t\t\t`unit=\"grip-shared-lima-${config.daemonPort}.service\"`,\n\t\t\t'test ! -L \"$token_file\"; test ! -L \"$pid_file\"; test ! -L \"$identity_file\"; test ! -L \"$log_file\"',\n\t\t\t'if test -e \"$log_file\"; then test -f \"$log_file\" && test \"$(stat -c %a \"$log_file\")\" = 600 || exit 22; fi',\n\t\t\t'test ! -e \"$start_lock\" && test ! -L \"$start_lock\" || exit 26',\n\t\t\t'if test -e \"$token_file\" || test -e \"$pid_file\" || test -e \"$identity_file\"; then',\n\t\t\t' test -f \"$token_file\" && test -f \"$pid_file\" && test -f \"$identity_file\" || exit 21',\n\t\t\t' test \"$(stat -c %a \"$token_file\")\" = 600 || exit 22',\n\t\t\t' test \"$(stat -c %a \"$pid_file\")\" = 600 || exit 22',\n\t\t\t' test \"$(stat -c %a \"$identity_file\")\" = 600 || exit 22',\n\t\t\t' pid=\"$(cat \"$pid_file\")\"',\n\t\t\t\" case \\\"$pid\\\" in ''|*[!0-9]*) exit 23;; esac\",\n\t\t\t' kill -0 \"$pid\" || exit 24',\n\t\t\t` start_time=\"$(${processStartTime} \"/proc/$pid/stat\")\" || exit 25`,\n\t\t\t' boot_id=\"$(cat /proc/sys/kernel/random/boot_id)\" || exit 25',\n\t\t\t' test -n \"$start_time\" && test -n \"$boot_id\" && test \"$(cat \"$identity_file\")\" = \"$boot_id:$start_time\" || exit 25',\n\t\t\t' test \"$(systemctl --user show -P MainPID \"$unit\")\" = \"$pid\" && systemctl --user is-active --quiet \"$unit\" || exit 25',\n\t\t\t' token=\"$(cat \"$token_file\")\"',\n\t\t\t\"else\",\n\t\t\t' mkdir \"$start_lock\" || exit 26',\n\t\t\t\" trap 'rmdir \\\"$start_lock\\\" 2>/dev/null || true' EXIT\",\n\t\t\t\" token=\\\"$(head -c 32 /dev/urandom | base64 | tr -d '\\\\n')\\\"\",\n\t\t\t' printf \\'%s\\' \"$token\" >\"$token_file\"',\n\t\t\t' chmod 600 \"$token_file\"',\n\t\t\t// The systemd user manager owns the process. It reads the private token file\n\t\t\t// inside the unit, never from a systemd-run argument or environment property.\n\t\t\tlocal\n\t\t\t\t? ' grip_bin=\"$HOME/.local/bin/grip\"; test -x \"$grip_bin\"'\n\t\t\t\t: ' grip_bin=\"$(command -v grip)\"; case \"$grip_bin\" in /*) ;; *) exit 25;; esac',\n\t\t\t` systemd-run --user --unit=\"$unit\" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN=\"$(cat \"$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.token\")\"; test -n \"$GRIP_DAEMON_TOKEN\"; export GRIP_DAEMON_TOKEN; exec \"$1\" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd \"$2\" --daemon-shared-parent \"$2\" --daemon-allow-root --daemon-allow-process-exec >\"$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.log\" 2>&1 </dev/null' sh \"$grip_bin\" ${shellQuote(config.workspaceMountPath)} >/dev/null`,\n\t\t\t' pid=\"\"; attempts=0',\n\t\t\t' while test \"$attempts\" -lt 50; do',\n\t\t\t' pid=\"$(systemctl --user show -P MainPID \"$unit\")\" || exit 25',\n\t\t\t' case \"$pid\" in \"\"|0) sleep 0.1;; *[!0-9]*) exit 25;; *) break;; esac',\n\t\t\t\" attempts=$((attempts + 1))\",\n\t\t\t\" done\",\n\t\t\t' case \"$pid\" in \"\"|0|*[!0-9]*) exit 25;; esac',\n\t\t\t' systemctl --user is-active --quiet \"$unit\" || exit 25',\n\t\t\t' printf \\'%s\\' \"$pid\" >\"$pid_file\"',\n\t\t\t' chmod 600 \"$pid_file\"',\n\t\t\t` start_time=\"$(${processStartTime} \"/proc/$pid/stat\")\" || exit 25`,\n\t\t\t' boot_id=\"$(cat /proc/sys/kernel/random/boot_id)\" || exit 25',\n\t\t\t' test -n \"$start_time\" && test -n \"$boot_id\" || exit 25',\n\t\t\t' printf \\'%s:%s\\' \"$boot_id\" \"$start_time\" >\"$identity_file\"',\n\t\t\t' chmod 600 \"$identity_file\"',\n\t\t\t' rmdir \"$start_lock\" || exit 26',\n\t\t\t\" trap - EXIT\",\n\t\t\t\"fi\",\n\t\t\t\"printf 'GRIP_SHARED_TOKEN=%s\\\\n' \\\"$token\\\"\",\n\t\t].join(\"\\n\");\n\t\tconst args = [\"shell\", \"--tty=false\", options.instanceName, \"sh\", \"-lc\", script];\n\t\tconst result = await this.runner.run(config.limaBinary, args);\n\t\t// Never include stdout/stderr from a credential-bearing shell in an error.\n\t\tif (result.exitCode !== 0)\n\t\t\tthrow new Error(\"Shared Lima daemon state is uncertain; reconcile guest PID/token files manually\");\n\t\tconst token = result.stdout.match(/(?:^|\\n)GRIP_SHARED_TOKEN=([A-Za-z0-9+/]{43}=)(?:\\r?\\n|$)/)?.[1];\n\t\tif (!token) throw new Error(\"Shared Lima daemon did not return a valid credential; reconcile manually\");\n\t\tawait this.readinessWaiter(config.daemonHostBind, config.daemonPort);\n\t\t// Readiness can outlive the owner. Never hand a guest credential to a lost owner.\n\t\tawait owner.assertHeld();\n\t\treturn token;\n\t}\n\n\t/** Update only a verified supervised daemon. Staging happens before disconnecting peers. */\n\tprivate async updateSharedDaemon(options: SharedLimaInstanceOptions, owner: SharedLimaOwnerLock): Promise<void> {\n\t\tawait owner.assertHeld();\n\t\tawait this.inspectSharedInstance(options);\n\t\tconst config = this.resolveConfig();\n\t\tconst name = options.instanceName;\n\t\tconst port = config.daemonPort;\n\t\tif (!this.env.GRIP_SANDBOX_GUEST_BINARY && process.argv[1]?.endsWith(\"/packages/coding-agent/src/cli.ts\")) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Development sandbox update requires GRIP_SANDBOX_GUEST_BINARY pointing to a built Linux Grip executable\",\n\t\t\t);\n\t\t}\n\t\tconst local = this.env.GRIP_SANDBOX_GUEST_BINARY\n\t\t\t? await inspectLocalGuestBinary(this.env.GRIP_SANDBOX_GUEST_BINARY)\n\t\t\t: undefined;\n\t\tconst shell = (script: string) =>\n\t\t\tthis.runner.run(config.limaBinary, [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script]);\n\t\tconst directory = \"$HOME/.cache/grip/shared-lima\";\n\t\tconst unit = `grip-shared-lima-${port}.service`;\n\t\tconst verify = [\n\t\t\t\"set -eu\",\n\t\t\t`directory=\"${directory}\"`,\n\t\t\t`unit=${shellQuote(unit)}`,\n\t\t\t'test -d \"$directory\" && test ! -L \"$directory\"',\n\t\t\t'test ! -e \"$HOME/.cache/grip/daemon-mode.lock\" && test ! -L \"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t`token_file=\"$directory/daemon-${port}.token\"`,\n\t\t\t`pid_file=\"$directory/daemon-${port}.pid\"`,\n\t\t\t`identity_file=\"$directory/daemon-${port}.identity\"`,\n\t\t\t'for file in \"$token_file\" \"$pid_file\" \"$identity_file\"; do test -f \"$file\" && test ! -L \"$file\" && test \"$(stat -c %a \"$file\")\" = 600; done',\n\t\t\t'pid=\"$(cat \"$pid_file\")\"; case \"$pid\" in \"\"|0|*[!0-9]*) exit 45;; esac',\n\t\t\t'kill -0 \"$pid\"',\n\t\t\t`start_time=\"$(awk '{ sub(/^.*\\\\) /, \"\"); if ($1 == \"Z\" || $1 == \"X\") exit 1; print $20 }' \"/proc/$pid/stat\")\"`,\n\t\t\t'boot_id=\"$(cat /proc/sys/kernel/random/boot_id)\"',\n\t\t\t'test -n \"$start_time\" && test \"$(cat \"$identity_file\")\" = \"$boot_id:$start_time\"',\n\t\t\t'test \"$(systemctl --user show -P MainPID \"$unit\")\" = \"$pid\" && systemctl --user is-active --quiet \"$unit\"',\n\t\t\t'case \"$(systemctl --user show -P ExecStart \"$unit\")\" in *\"$HOME/.local/bin/grip\"*) ;; *) exit 46;; esac',\n\t\t];\n\t\tconst preflight = await shell(verify.join(\"\\n\"));\n\t\tif (preflight.exitCode !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Shared Lima daemon identity or binary path is uncertain; update refused without disconnecting clients\",\n\t\t\t);\n\t\t}\n\t\tconst staged = await stageSharedGuestBinary(this.runner, config.limaBinary, name, unit, VERSION, local);\n\t\ttry {\n\t\t\tawait owner.assertHeld();\n\t\t\tconst stop = await shell(\n\t\t\t\t[\n\t\t\t\t\t...verify,\n\t\t\t\t\t'mkdir \"$HOME/.cache/grip/daemon-mode.lock\" || exit 45',\n\t\t\t\t\t'trap \\u0027rmdir \"$HOME/.cache/grip/daemon-mode.lock\" 2>/dev/null || true\\u0027 EXIT',\n\t\t\t\t\t'systemctl --user stop \"$unit\"',\n\t\t\t\t\t'test \"$(systemctl --user show -P MainPID \"$unit\")\" = 0',\n\t\t\t\t\t'! kill -0 \"$pid\" 2>/dev/null',\n\t\t\t\t].join(\"\\n\"),\n\t\t\t);\n\t\t\tif (stop.exitCode !== 0)\n\t\t\t\tthrow new Error(\"Shared daemon stop is uncertain; inspect the guest before retrying update\");\n\t\t\tawait owner.assertHeld();\n\t\t\tawait staged.install();\n\t\t\tawait owner.assertHeld();\n\t\t\tconst restart = await shell(\n\t\t\t\t[\n\t\t\t\t\t\"set -eu\",\n\t\t\t\t\t`directory=\"${directory}\"`,\n\t\t\t\t\t`unit=${shellQuote(unit)}`,\n\t\t\t\t\t'test -d \"$directory\" && test ! -L \"$directory\"',\n\t\t\t\t\t`token_file=\"$directory/daemon-${port}.token\"`,\n\t\t\t\t\t`pid_file=\"$directory/daemon-${port}.pid\"`,\n\t\t\t\t\t`identity_file=\"$directory/daemon-${port}.identity\"`,\n\t\t\t\t\t'for file in \"$token_file\" \"$pid_file\" \"$identity_file\"; do test -f \"$file\" && test ! -L \"$file\" && test \"$(stat -c %a \"$file\")\" = 600; done',\n\t\t\t\t\t'test ! -e \"$HOME/.cache/grip/daemon-mode.lock\" && test ! -L \"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t\t\t'mkdir \"$HOME/.cache/grip/daemon-mode.lock\" || exit 45',\n\t\t\t\t\t'trap \\u0027rmdir \"$HOME/.cache/grip/daemon-mode.lock\" 2>/dev/null || true\\u0027 EXIT',\n\t\t\t\t\t'old_pid=\"$(cat \"$pid_file\")\"; case \"$old_pid\" in \"\"|0|*[!0-9]*) exit 45;; esac',\n\t\t\t\t\t'! kill -0 \"$old_pid\" 2>/dev/null',\n\t\t\t\t\t`test \"$(\"$HOME/.local/bin/grip\" --version)\" = ${shellQuote(VERSION)}`,\n\t\t\t\t\t'load=\"$(systemctl --user show -P LoadState \"$unit\" 2>/dev/null || true)\"',\n\t\t\t\t\t'case \"$load\" in',\n\t\t\t\t\t' loaded) test \"$(systemctl --user show -P MainPID \"$unit\")\" = 0; systemctl --user start \"$unit\" ;;',\n\t\t\t\t\t' not-found|\"\")',\n\t\t\t\t\t` systemd-run --user --unit=\"$unit\" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN=\"$(cat \"$HOME/.cache/grip/shared-lima/daemon-${port}.token\")\"; test -n \"$GRIP_DAEMON_TOKEN\"; export GRIP_DAEMON_TOKEN; exec \"$1\" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${port} --daemon-cwd \"$2\" --daemon-shared-parent \"$2\" --daemon-allow-root --daemon-allow-process-exec >\"$HOME/.cache/grip/shared-lima/daemon-${port}.log\" 2>&1 </dev/null' sh \"$HOME/.local/bin/grip\" ${shellQuote(config.workspaceMountPath)} >/dev/null ;;`,\n\t\t\t\t\t\" *) exit 45 ;;\",\n\t\t\t\t\t\"esac\",\n\t\t\t\t\t'pid=\"\"; attempts=0',\n\t\t\t\t\t'while test \"$attempts\" -lt 50; do',\n\t\t\t\t\t' pid=\"$(systemctl --user show -P MainPID \"$unit\")\" || exit 45',\n\t\t\t\t\t' case \"$pid\" in \"\"|0) sleep 0.1;; *[!0-9]*) exit 45;; *) break;; esac',\n\t\t\t\t\t\" attempts=$((attempts + 1))\",\n\t\t\t\t\t\"done\",\n\t\t\t\t\t'case \"$pid\" in \"\"|0|*[!0-9]*) exit 45;; esac',\n\t\t\t\t\t'kill -0 \"$pid\"; systemctl --user is-active --quiet \"$unit\"',\n\t\t\t\t\t`start_time=\"$(awk '{ sub(/^.*\\\\) /, \"\"); if ($1 == \"Z\" || $1 == \"X\") exit 1; print $20 }' \"/proc/$pid/stat\")\"`,\n\t\t\t\t\t'boot_id=\"$(cat /proc/sys/kernel/random/boot_id)\"',\n\t\t\t\t\t'test -n \"$start_time\" && test -n \"$boot_id\"',\n\t\t\t\t\t'printf \"%s\" \"$pid\" >\"$pid_file\"',\n\t\t\t\t\t'printf \"%s:%s\" \"$boot_id\" \"$start_time\" >\"$identity_file\"',\n\t\t\t\t\t'chmod 600 \"$pid_file\" \"$identity_file\"',\n\t\t\t\t].join(\"\\n\"),\n\t\t\t);\n\t\t\tif (restart.exitCode !== 0)\n\t\t\t\tthrow new Error(\"Shared daemon restart is uncertain; inspect the guest before retrying update\");\n\t\t\tawait this.readinessWaiter(config.daemonHostBind, port);\n\t\t\tawait owner.assertHeld();\n\t\t} finally {\n\t\t\tawait staged.cleanup();\n\t\t}\n\t}\n\n\tprivate async startInstance(\n\t\tconfig: SandboxConfig,\n\t\tworkspaceRoot: string,\n\t\tname: string,\n\t\tdaemonPort: number,\n\t): Promise<void> {\n\t\tconst mountExpression = `.mounts = [{\"location\":${JSON.stringify(workspaceRoot)},\"mountPoint\":${JSON.stringify(config.workspaceMountPath)},\"writable\":true}]`;\n\t\tconst forwardExpression = `.portForwards += [{\"guestPort\":${daemonPort},\"hostPort\":${daemonPort},\"hostIP\":${JSON.stringify(config.daemonHostBind)}}]`;\n\t\tconst args = [\n\t\t\t\"start\",\n\t\t\t\"--tty=false\",\n\t\t\t\"--name\",\n\t\t\tname,\n\t\t\t\"--mount-none\",\n\t\t\t\"--set\",\n\t\t\tmountExpression,\n\t\t\t\"--set\",\n\t\t\tforwardExpression,\n\t\t\tconfig.limaTemplate,\n\t\t];\n\t\tensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);\n\t}\n\n\tprivate async ensureGrip(\n\t\tconfig: SandboxConfig,\n\t\tname: string,\n\t\tmanaged: boolean,\n\t\tlocal?: LocalGuestBinary,\n\t): Promise<void> {\n\t\tif (local) {\n\t\t\tawait installLocalGuestBinary(this.runner, config.limaBinary, name, local, VERSION);\n\t\t\treturn;\n\t\t}\n\t\tconst checkArgs = [\n\t\t\t\"shell\",\n\t\t\t\"--tty=false\",\n\t\t\tname,\n\t\t\t\"sh\",\n\t\t\t\"-lc\",\n\t\t\t'command -v grip >/dev/null || test -x \"$HOME/.local/bin/grip\"',\n\t\t];\n\t\tconst check = await this.runner.run(config.limaBinary, checkArgs);\n\t\tif (check.exitCode === 0) return;\n\t\tif (!managed) {\n\t\t\tthrow new Error(\n\t\t\t\t`Lima instance ${name} does not provide grip; install the matching Linux release in the VM first`,\n\t\t\t);\n\t\t}\n\t\tconst script = `set -eu; tmp=\"$(mktemp)\"; trap 'rm -f \"$tmp\"' EXIT; curl -fsSL -o \"$tmp\" https://raw.githubusercontent.com/greppleai/grip/main/install.sh; GRIP_VERSION=${shellQuote(`v${VERSION}`)} sh \"$tmp\"; test -x \"$HOME/.local/bin/grip\"`;\n\t\tconst args = [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script];\n\t\tensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);\n\t}\n\t/** A legacy named attach or stop must not rotate or kill a shared guest daemon. */\n\tprivate async assertNoSharedGuestState(\n\t\tconfig: SandboxConfig,\n\t\tname: string,\n\t\toperation: LegacyLimaGuestStateOperation = \"attach\",\n\t): Promise<void> {\n\t\tconst script = 'test ! -e \"$HOME/.cache/grip/shared-lima\" && test ! -L \"$HOME/.cache/grip/shared-lima\"';\n\t\tconst args = [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script];\n\t\tconst result = await this.runner.run(config.limaBinary, args);\n\t\t// A guest shell failure is ambiguous too; never guess that shared state is absent.\n\t\tif (result.exitCode !== 0) {\n\t\t\tthrow new Error(`Lima named VM may host a shared daemon; legacy ${operation} refused; reconcile manually`);\n\t\t}\n\t}\n\n\tprivate async startDaemon(config: SandboxConfig, name: string): Promise<string> {\n\t\tconst pidFile = `.cache/grip/sandbox-daemon-${config.daemonPort}.pid`;\n\t\tconst logFile = `.cache/grip/sandbox-daemon-${config.daemonPort}.log`;\n\t\tconst script = [\n\t\t\t\"set -eu\",\n\t\t\t\"umask 077\",\n\t\t\t`mkdir -p \"$HOME/.cache/grip\"`,\n\t\t\t'mode_lock=\"$HOME/.cache/grip/daemon-mode.lock\"',\n\t\t\t'mkdir \"$mode_lock\" || exit 28',\n\t\t\t\"trap 'rmdir \\\"$mode_lock\\\" 2>/dev/null || true' EXIT\",\n\t\t\t'test ! -e \"$HOME/.cache/grip/shared-lima\" && test ! -L \"$HOME/.cache/grip/shared-lima\" || exit 29',\n\t\t\t`if test -f \"$HOME/${pidFile}\"; then old_pid=\"$(cat \"$HOME/${pidFile}\")\"; kill \"$old_pid\" 2>/dev/null || true; fi`,\n\t\t\t`token=\"$(head -c 32 /dev/urandom | base64 | tr -d '\\\\n')\"`,\n\t\t\t`nohup env GRIP_DAEMON_TOKEN=\"$token\" \"${this.env.GRIP_SANDBOX_GUEST_BINARY ? \"$HOME/.local/bin/grip\" : '$(command -v grip || printf %s \"$HOME/.local/bin/grip\")'}\" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd ${shellQuote(config.workspaceMountPath)} --daemon-allow-root --daemon-allow-process-exec >\"$HOME/${logFile}\" 2>&1 </dev/null &`,\n\t\t\t`echo $! >\"$HOME/${pidFile}\"`,\n\t\t\t'rmdir \"$mode_lock\" || exit 28',\n\t\t\t\"trap - EXIT\",\n\t\t\t`printf 'GRIP_SANDBOX_TOKEN=%s\\\\n' \"$token\"`,\n\t\t].join(\"\\n\");\n\t\tconst args = [\"shell\", \"--tty=false\", \"--workdir\", config.workspaceMountPath, name, \"sh\", \"-lc\", script];\n\t\tconst result = await this.runner.run(config.limaBinary, args);\n\t\tensureLimaSuccessful(config.limaBinary, result, args);\n\t\tconst token = result.stdout.match(/(?:^|\\n)GRIP_SANDBOX_TOKEN=([^\\r\\n]+)/)?.[1];\n\t\tif (!token) throw new Error(`Lima instance ${name} started the daemon without returning an authentication token`);\n\t\treturn token;\n\t}\n\n\tprivate async prepareExistingInstance(\n\t\tconfig: SandboxConfig,\n\t\trecord: LimaListRecord,\n\t\tname: string,\n\t\tworkspaceRoot: string,\n\t): Promise<void> {\n\t\tconst mount = findWorkspaceMount(record, config.workspaceMountPath);\n\t\tif (!mount || resolve(mount.location ?? \"\") !== workspaceRoot || !mount.writable) {\n\t\t\tthrow new Error(\n\t\t\t\t`Lima instance ${name} must mount ${workspaceRoot} read-write at ${config.workspaceMountPath}`,\n\t\t\t);\n\t\t}\n\t\tconst status = record.status?.toLowerCase();\n\t\tif (status === \"running\") return;\n\t\tif (status !== \"stopped\") {\n\t\t\tthrow new Error(`Lima instance ${name} is in an uncertain state; refusing to resume`);\n\t\t}\n\t\tconst args = [\"start\", \"--tty=false\", name];\n\t\tensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);\n\t}\n\n\tprivate async findExactLegacyInstance(config: SandboxConfig, name?: string): Promise<LimaListRecord | undefined> {\n\t\tif (!name) return undefined;\n\t\tconst records = await this.listRecords(config, name);\n\t\tif (records.length === 0) return undefined;\n\t\tif (records.length !== 1 || records[0]?.name !== name) {\n\t\t\tthrow new Error(\"Lima instance lookup did not return one exact name; refusing to attach or create\");\n\t\t}\n\t\treturn records[0];\n\t}\n\n\tasync start(options: SandboxStartOptions): Promise<SandboxStartResult> {\n\t\tconst requestedName = options.name?.trim();\n\t\tif (!requestedName) {\n\t\t\tif (options.update) throw new Error(\"Sandbox update requires a named running shared VM\");\n\t\t\treturn this.startWithLegacyInstance(options);\n\t\t}\n\t\t// Coordinate VM resume/create as well as guest daemon launch with a named shared owner.\n\t\t// A stale lock is ambiguous, not permission to start an existing VM.\n\t\tconst owner = await acquireSharedLimaOwnerLock(requestedName);\n\t\ttry {\n\t\t\tconst config = this.resolveConfig(options);\n\t\t\tconst existing = await this.findExactLegacyInstance(config, requestedName);\n\t\t\tif (options.update && existing?.status?.toLowerCase() !== \"running\") {\n\t\t\t\tthrow new Error(\"Sandbox update requires an existing running shared VM\");\n\t\t\t}\n\t\t\tif (existing?.status?.toLowerCase() !== \"running\") {\n\t\t\t\treturn await this.startWithLegacyInstance(options, { record: existing });\n\t\t\t}\n\t\t\t// Select the guest mode before any legacy setup. An unreadable or ambiguous\n\t\t\t// marker is not permission to start a per-session daemon in this VM.\n\t\t\tconst probe = await this.runner.run(config.limaBinary, [\n\t\t\t\t\"shell\",\n\t\t\t\t\"--tty=false\",\n\t\t\t\trequestedName,\n\t\t\t\t\"sh\",\n\t\t\t\t\"-lc\",\n\t\t\t\t'if test -e \"$HOME/.cache/grip/shared-lima\" || test -L \"$HOME/.cache/grip/shared-lima\"; then if test -d \"$HOME/.cache/grip/shared-lima\" && test ! -L \"$HOME/.cache/grip/shared-lima\"; then printf \"GRIP_SHARED_GUEST\\\\n\"; else exit 42; fi; else printf \"GRIP_LEGACY_GUEST\\\\n\"; fi',\n\t\t\t]);\n\t\t\tif (probe.exitCode !== 0) throw new Error(\"Lima guest daemon mode is uncertain; refusing named attach\");\n\t\t\tif (probe.stdout.trim() === \"GRIP_LEGACY_GUEST\") {\n\t\t\t\tif (options.update)\n\t\t\t\t\tthrow new Error(\"Sandbox update requires a supervised shared guest; legacy guest is unchanged\");\n\t\t\t\treturn await this.startWithLegacyInstance(options, { record: existing });\n\t\t\t}\n\t\t\tif (probe.stdout.trim() !== \"GRIP_SHARED_GUEST\") {\n\t\t\t\tthrow new Error(\"Lima guest daemon mode is uncertain; refusing named attach\");\n\t\t\t}\n\t\t\tawait owner.assertHeld();\n\t\t\tconst mount = findWorkspaceMount(existing, config.workspaceMountPath);\n\t\t\tif (!mount?.location) throw new Error(\"Shared Lima instance mount is unavailable; refusing attach\");\n\t\t\tconst sharedOptions = {\n\t\t\t\tinstanceName: requestedName,\n\t\t\t\thostParent: resolve(mount.location),\n\t\t\t\thostRoot: resolve(options.workspaceRoot),\n\t\t\t};\n\t\t\tconst inspection = await this.inspectSharedInstance(sharedOptions);\n\t\t\tif (options.update) await this.updateSharedDaemon(sharedOptions, owner);\n\t\t\tconst token = await this.ensureSharedDaemon(sharedOptions, owner, options.update);\n\t\t\tconst daemonUrl = `grip+${inspection.daemonUrl}?root=${encodeURIComponent(inspection.guestRoot)}`;\n\t\t\treturn {\n\t\t\t\tcontainerId: requestedName,\n\t\t\t\tcontainerName: requestedName,\n\t\t\t\tworkspaceRoot: inspection.hostRoot,\n\t\t\t\tworkspaceMountPath: inspection.guestRoot,\n\t\t\t\tdaemonUrl,\n\t\t\t\tdaemonUrlRedacted: inspection.daemonUrl,\n\t\t\t\ttoken,\n\t\t\t\tlabels: { [`${SANDBOX_LABEL_PREFIX}.runtime`]: \"lima\", [`${SANDBOX_LABEL_PREFIX}.version`]: VERSION },\n\t\t\t};\n\t\t} finally {\n\t\t\tawait owner.release();\n\t\t}\n\t}\n\n\tprivate async startWithLegacyInstance(\n\t\toptions: SandboxStartOptions,\n\t\tknown?: KnownLimaRecord,\n\t): Promise<SandboxStartResult> {\n\t\tconst workspaceRoot = resolve(options.workspaceRoot);\n\t\tconst local = this.env.GRIP_SANDBOX_GUEST_BINARY\n\t\t\t? await inspectLocalGuestBinary(this.env.GRIP_SANDBOX_GUEST_BINARY)\n\t\t\t: undefined;\n\t\tconst config = this.resolveConfig(options);\n\t\tconst requestedName = options.name?.trim();\n\t\tconst managed = !requestedName;\n\t\tconst existing = known ? known.record : await this.findExactLegacyInstance(config, requestedName);\n\t\tif (existing) await this.prepareExistingInstance(config, existing, requestedName!, workspaceRoot);\n\t\tconst configuredForward = existing ? findDaemonForward(existing, config.daemonPort) : undefined;\n\t\tif (configuredForward && configuredForward.guestPort !== configuredForward.hostPort) {\n\t\t\tthrow new Error(\n\t\t\t\t`Lima instance ${requestedName} must forward the sandbox daemon on the same guest and host port`,\n\t\t\t);\n\t\t}\n\t\tconst daemonPort =\n\t\t\tconfiguredForward?.hostPort ?? (await this.portAllocator(config.daemonHostBind, config.daemonPort));\n\t\tconst name =\n\t\t\trequestedName ?? createInstanceName(config, workspaceRoot, options.sessionId ?? \"session\", daemonPort);\n\t\tconst effectiveConfig = { ...config, daemonPort };\n\t\tif (!existing) await this.startInstance(effectiveConfig, workspaceRoot, name, daemonPort);\n\t\t// A failed guest install/start can have changed state; never delete an uncertain VM.\n\t\tif (existing) await this.assertNoSharedGuestState(effectiveConfig, name);\n\t\tawait this.ensureGrip(effectiveConfig, name, !existing, local);\n\t\tconst token = await this.startDaemon(effectiveConfig, name);\n\t\tawait this.readinessWaiter(config.daemonHostBind, daemonPort);\n\t\t// A failed readiness check is not proof that this daemon is ours to stop.\n\t\t// Leave uncertain guest state for explicit operator reconciliation.\n\t\tthis.managedInstances.set(name, { workspaceRoot, daemonPort, ownerId: options.sessionId, managed });\n\t\tconst daemonUrl = `ws://${urlHost(daemonConnectionHost(config.daemonHostBind))}:${daemonPort}${DAEMON_WEBSOCKET_PATH}`;\n\t\treturn {\n\t\t\tcontainerId: name,\n\t\t\tcontainerName: name,\n\t\t\tworkspaceRoot,\n\t\t\tworkspaceMountPath: config.workspaceMountPath,\n\t\t\tdaemonUrl,\n\t\t\tdaemonUrlRedacted: daemonUrl,\n\t\t\ttoken,\n\t\t\tlabels: { [`${SANDBOX_LABEL_PREFIX}.runtime`]: \"lima\", [`${SANDBOX_LABEL_PREFIX}.version`]: VERSION },\n\t\t};\n\t}\n\n\tasync list(options: SandboxListOptions): Promise<SandboxContainer[]> {\n\t\tconst config = this.resolveConfig();\n\t\tconst workspaceRoot = resolve(options.workspaceRoot);\n\t\treturn (await this.listRecords(config))\n\t\t\t.map((record) => toSandboxContainer(record, config.workspaceMountPath))\n\t\t\t.filter(\n\t\t\t\t(instance) => instance.workspaceRoot && (options.allWorkspaces || instance.workspaceRoot === workspaceRoot),\n\t\t\t);\n\t}\n\n\tprivate async stopDaemon(config: SandboxConfig, name: string, daemonPort: number): Promise<void> {\n\t\tconst pidFile = `.cache/grip/sandbox-daemon-${daemonPort}.pid`;\n\t\tconst script = `if test -f \"$HOME/${pidFile}\"; then pid=\"$(cat \"$HOME/${pidFile}\")\"; kill \"$pid\" 2>/dev/null || true; rm -f \"$HOME/${pidFile}\"; fi`;\n\t\tconst args = [\"shell\", \"--tty=false\", name, \"sh\", \"-lc\", script];\n\t\tensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);\n\t}\n\n\tasync stop(options: SandboxStopOptions): Promise<SandboxStopResult> {\n\t\tconst config = this.resolveConfig();\n\t\tconst instances = await this.list({ workspaceRoot: options.workspaceRoot });\n\t\tconst selected = selectLimaSandbox(instances, options.target ?? options.currentContainerId);\n\t\tif (!selected) return { status: \"not-found\", message: \"No matching Grip Lima sandbox found\" };\n\t\tif (instances.filter((instance) => instance.name === selected.name).length !== 1) {\n\t\t\tthrow new Error(\"Lima sandbox identity is ambiguous; refusing to stop a VM or daemon\");\n\t\t}\n\t\tconst tracked = this.managedInstances.get(selected.name);\n\t\t// Names and Lima's list output do not establish ownership. In particular, a\n\t\t// shared named VM can have the ordinary sandbox prefix without being ours.\n\t\t// Only a VM started by this session may be stopped or have its daemon touched.\n\t\tif (!tracked || tracked.workspaceRoot !== selected.workspaceRoot || tracked.daemonPort !== selected.daemonPort) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Lima sandbox ownership is unknown or daemon port changed; refusing to stop an untracked VM or daemon\",\n\t\t\t);\n\t\t}\n\t\t// A shared guest must never lose its daemon or VM to a legacy\n\t\t// in-process record. Resolve the selected VM again under the host owner lock.\n\t\tconst owner = await acquireSharedLimaOwnerLock(selected.name);\n\t\ttry {\n\t\t\tconst matches = (await this.list({ workspaceRoot: options.workspaceRoot })).filter(\n\t\t\t\t(instance) => instance.name === selected.name,\n\t\t\t);\n\t\t\tconst current = matches[0];\n\t\t\tif (\n\t\t\t\tmatches.length !== 1 ||\n\t\t\t\t!current ||\n\t\t\t\tcurrent.id !== selected.id ||\n\t\t\t\tcurrent.state !== selected.state ||\n\t\t\t\tcurrent.workspaceRoot !== selected.workspaceRoot ||\n\t\t\t\tcurrent.daemonPort !== selected.daemonPort\n\t\t\t) {\n\t\t\t\tthrow new Error(\"Lima sandbox identity changed during stop; refusing to touch the VM or daemon\");\n\t\t\t}\n\t\t\treturn await this.stopTrackedInstance(config, current, tracked);\n\t\t} finally {\n\t\t\tawait owner.release();\n\t\t}\n\t}\n\n\tprivate async stopTrackedInstance(\n\t\tconfig: SandboxConfig,\n\t\tselected: SandboxContainer,\n\t\ttracked: ManagedLimaInstance,\n\t): Promise<SandboxStopResult> {\n\t\tconst ownsInstance = tracked.managed;\n\t\tif (selected.state !== \"running\") {\n\t\t\tif (ownsInstance && config.cleanup === \"remove\") {\n\t\t\t\t// An already stopped VM cannot be probed without resuming it. Its\n\t\t\t\t// in-memory record is not proof it was never repurposed externally.\n\t\t\t\tthrow new Error(\"Lima sandbox is stopped; refusing to delete an unverifiable VM; reconcile manually\");\n\t\t\t}\n\t\t\tthis.managedInstances.delete(selected.name);\n\t\t\treturn { status: \"already-stopped\", container: selected };\n\t\t}\n\t\tawait this.assertNoSharedGuestState(config, selected.name, \"stop\");\n\t\tawait this.stopDaemon(config, selected.name, tracked?.daemonPort ?? selected.daemonPort ?? config.daemonPort);\n\t\tif (ownsInstance) {\n\t\t\tconst args = config.cleanup === \"remove\" ? [\"delete\", \"--force\", selected.name] : [\"stop\", selected.name];\n\t\t\tensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);\n\t\t}\n\t\tthis.managedInstances.delete(selected.name);\n\t\treturn { status: ownsInstance && config.cleanup === \"remove\" ? \"removed\" : \"stopped\", container: selected };\n\t}\n\n\tasync stopManagedInstances(): Promise<void> {\n\t\tconst failures: unknown[] = [];\n\t\tfor (const [name, instance] of [...this.managedInstances]) {\n\t\t\ttry {\n\t\t\t\tawait this.stop({ workspaceRoot: instance.workspaceRoot, target: name, currentContainerId: name });\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) throw new AggregateError(failures, \"Failed to stop managed Lima sandbox instances\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lima.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/lima.ts"],"names":[],"mappings":"AAOA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AACvH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAGX,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAA8B,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAErG,MAAM,WAAW,4BAA6B,SAAQ,0BAA0B;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACzC,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACpD;AA0KD,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0D;IAC1F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2D;IACzF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmC;IAEpE,YAAY,OAAO,GAAE,yBAA8B,EAOlD;IAED,aAAa,CAAC,SAAS,GAAE,sBAA2B,GAAG,aAAa,CAEnE;YAEa,WAAW;IAmBzB,+FAA+F;IACzF,qBAAqB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAwCrG;IACD,+FAA+F;IACzF,kBAAkB,CACvB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,mBAAmB,EAC1B,OAAO,UAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CA8GjB;IAED,4FAA4F;YAC9E,kBAAkB;YA4GlB,aAAa;YAuBb,UAAU;IA2BxB,mFAAmF;YACrE,wBAAwB;YAcxB,WAAW;YA2BX,uBAAuB;YAqBvB,uBAAuB;IAU/B,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8DrE;YAEa,uBAAuB;IA8C/B,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAQnE;YAEa,UAAU;IAOlB,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuClE;YAEa,mBAAmB;IAyB3B,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAU1C;CACD"}
|
|
@@ -133,12 +133,6 @@ function selectLimaSandbox(instances, target) {
|
|
|
133
133
|
return instances.find((instance) => instance.name === target || instance.id.startsWith(target));
|
|
134
134
|
}
|
|
135
135
|
export class LimaSandboxService {
|
|
136
|
-
settingsManager;
|
|
137
|
-
env;
|
|
138
|
-
runner;
|
|
139
|
-
portAllocator;
|
|
140
|
-
readinessWaiter;
|
|
141
|
-
managedInstances;
|
|
142
136
|
constructor(options = {}) {
|
|
143
137
|
this.settingsManager = options.settingsManager;
|
|
144
138
|
this.env = options.env ?? process.env;
|
|
@@ -285,7 +279,7 @@ export class LimaSandboxService {
|
|
|
285
279
|
local
|
|
286
280
|
? ' grip_bin="$HOME/.local/bin/grip"; test -x "$grip_bin"'
|
|
287
281
|
: ' grip_bin="$(command -v grip)"; case "$grip_bin" in /*) ;; *) exit 25;; esac',
|
|
288
|
-
` systemd-run --user --unit="$unit" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN="$(cat "$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.token")"; test -n "$GRIP_DAEMON_TOKEN"; export GRIP_DAEMON_TOKEN; exec "$1" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd "$2" --daemon-shared-parent "$2" --daemon-allow-root --daemon-allow-process-exec >"$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.log" 2>&1 </dev/null' sh "$grip_bin" ${shellQuote(config.workspaceMountPath)} >/dev/null`,
|
|
282
|
+
` systemd-run --user --unit="$unit" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN="$(cat "$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.token")"; test -n "$GRIP_DAEMON_TOKEN"; export GRIP_DAEMON_TOKEN; exec "$1" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd "$2" --daemon-shared-parent "$2" --daemon-allow-root --daemon-allow-process-exec --daemon-allow-full-filesystem >"$HOME/.cache/grip/shared-lima/daemon-${config.daemonPort}.log" 2>&1 </dev/null' sh "$grip_bin" ${shellQuote(config.workspaceMountPath)} >/dev/null`,
|
|
289
283
|
' pid=""; attempts=0',
|
|
290
284
|
' while test "$attempts" -lt 50; do',
|
|
291
285
|
' pid="$(systemctl --user show -P MainPID "$unit")" || exit 25',
|
|
@@ -392,7 +386,7 @@ export class LimaSandboxService {
|
|
|
392
386
|
'case "$load" in',
|
|
393
387
|
' loaded) test "$(systemctl --user show -P MainPID "$unit")" = 0; systemctl --user start "$unit" ;;',
|
|
394
388
|
' not-found|"")',
|
|
395
|
-
` systemd-run --user --unit="$unit" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN="$(cat "$HOME/.cache/grip/shared-lima/daemon-${port}.token")"; test -n "$GRIP_DAEMON_TOKEN"; export GRIP_DAEMON_TOKEN; exec "$1" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${port} --daemon-cwd "$2" --daemon-shared-parent "$2" --daemon-allow-root --daemon-allow-process-exec >"$HOME/.cache/grip/shared-lima/daemon-${port}.log" 2>&1 </dev/null' sh "$HOME/.local/bin/grip" ${shellQuote(config.workspaceMountPath)} >/dev/null ;;`,
|
|
389
|
+
` systemd-run --user --unit="$unit" --property=Restart=no --property=KillMode=control-group -- sh -c 'set -eu; umask 077; GRIP_DAEMON_TOKEN="$(cat "$HOME/.cache/grip/shared-lima/daemon-${port}.token")"; test -n "$GRIP_DAEMON_TOKEN"; export GRIP_DAEMON_TOKEN; exec "$1" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${port} --daemon-cwd "$2" --daemon-shared-parent "$2" --daemon-allow-root --daemon-allow-process-exec --daemon-allow-full-filesystem >"$HOME/.cache/grip/shared-lima/daemon-${port}.log" 2>&1 </dev/null' sh "$HOME/.local/bin/grip" ${shellQuote(config.workspaceMountPath)} >/dev/null ;;`,
|
|
396
390
|
" *) exit 45 ;;",
|
|
397
391
|
"esac",
|
|
398
392
|
'pid=""; attempts=0',
|
|
@@ -436,7 +430,7 @@ export class LimaSandboxService {
|
|
|
436
430
|
];
|
|
437
431
|
ensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);
|
|
438
432
|
}
|
|
439
|
-
async ensureGrip(config, name,
|
|
433
|
+
async ensureGrip(config, name, existing, local) {
|
|
440
434
|
if (local) {
|
|
441
435
|
await installLocalGuestBinary(this.runner, config.limaBinary, name, local, VERSION);
|
|
442
436
|
return;
|
|
@@ -452,10 +446,10 @@ export class LimaSandboxService {
|
|
|
452
446
|
const check = await this.runner.run(config.limaBinary, checkArgs);
|
|
453
447
|
if (check.exitCode === 0)
|
|
454
448
|
return;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
const script = `set -eu; tmp="$(mktemp)"; trap 'rm -f "$tmp"' EXIT; curl -fsSL -o "$tmp" https://raw.githubusercontent.com/greppleai/grip/main/install.sh;
|
|
449
|
+
// Existing named VMs can be bootstrapped too. Keep managed VMs pinned to
|
|
450
|
+
// the host release; use the latest published release for user-owned VMs.
|
|
451
|
+
const version = existing ? "" : `GRIP_VERSION=${shellQuote(`v${VERSION}`)} `;
|
|
452
|
+
const script = `set -eu; tmp="$(mktemp)"; trap 'rm -f "$tmp"' EXIT; curl -fsSL -o "$tmp" https://raw.githubusercontent.com/greppleai/grip/main/install.sh; ${version}sh "$tmp"; test -x "$HOME/.local/bin/grip"`;
|
|
459
453
|
const args = ["shell", "--tty=false", name, "sh", "-lc", script];
|
|
460
454
|
ensureLimaSuccessful(config.limaBinary, await this.runner.run(config.limaBinary, args), args);
|
|
461
455
|
}
|
|
@@ -482,7 +476,7 @@ export class LimaSandboxService {
|
|
|
482
476
|
'test ! -e "$HOME/.cache/grip/shared-lima" && test ! -L "$HOME/.cache/grip/shared-lima" || exit 29',
|
|
483
477
|
`if test -f "$HOME/${pidFile}"; then old_pid="$(cat "$HOME/${pidFile}")"; kill "$old_pid" 2>/dev/null || true; fi`,
|
|
484
478
|
`token="$(head -c 32 /dev/urandom | base64 | tr -d '\\n')"`,
|
|
485
|
-
`nohup env GRIP_DAEMON_TOKEN="$token" "${this.env.GRIP_SANDBOX_GUEST_BINARY ? "$HOME/.local/bin/grip" : '$(command -v grip || printf %s "$HOME/.local/bin/grip")'}" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd ${shellQuote(config.workspaceMountPath)} --daemon-allow-root --daemon-allow-process-exec >"$HOME/${logFile}" 2>&1 </dev/null &`,
|
|
479
|
+
`nohup env GRIP_DAEMON_TOKEN="$token" "${this.env.GRIP_SANDBOX_GUEST_BINARY ? "$HOME/.local/bin/grip" : '$(command -v grip || printf %s "$HOME/.local/bin/grip")'}" --daemon --daemon-host 127.0.0.1 --daemon-allow-insecure-transport --daemon-port ${config.daemonPort} --daemon-cwd ${shellQuote(config.workspaceMountPath)} --daemon-allow-root --daemon-allow-process-exec --daemon-allow-full-filesystem >"$HOME/${logFile}" 2>&1 </dev/null &`,
|
|
486
480
|
`echo $! >"$HOME/${pidFile}"`,
|
|
487
481
|
'rmdir "$mode_lock" || exit 28',
|
|
488
482
|
"trap - EXIT",
|
|
@@ -612,7 +606,7 @@ export class LimaSandboxService {
|
|
|
612
606
|
// A failed guest install/start can have changed state; never delete an uncertain VM.
|
|
613
607
|
if (existing)
|
|
614
608
|
await this.assertNoSharedGuestState(effectiveConfig, name);
|
|
615
|
-
await this.ensureGrip(effectiveConfig, name,
|
|
609
|
+
await this.ensureGrip(effectiveConfig, name, !!existing, local);
|
|
616
610
|
const token = await this.startDaemon(effectiveConfig, name);
|
|
617
611
|
await this.readinessWaiter(config.daemonHostBind, daemonPort);
|
|
618
612
|
// A failed readiness check is not proof that this daemon is ours to stop.
|