@cuna_labs/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +169 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/dist/api/capability-evidence.d.ts +19 -0
- package/dist/api/capability-evidence.d.ts.map +1 -0
- package/dist/api/capability-evidence.js +38 -0
- package/dist/api/capability-evidence.js.map +1 -0
- package/dist/api/client.d.ts +167 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +937 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/contracts.d.ts +345 -0
- package/dist/api/contracts.d.ts.map +1 -0
- package/dist/api/contracts.js +976 -0
- package/dist/api/contracts.js.map +1 -0
- package/dist/api/execution-workspaces.d.ts +17 -0
- package/dist/api/execution-workspaces.d.ts.map +1 -0
- package/dist/api/execution-workspaces.js +46 -0
- package/dist/api/execution-workspaces.js.map +1 -0
- package/dist/api/http.d.ts +76 -0
- package/dist/api/http.d.ts.map +1 -0
- package/dist/api/http.js +838 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/managed-executions.d.ts +37 -0
- package/dist/api/managed-executions.d.ts.map +1 -0
- package/dist/api/managed-executions.js +80 -0
- package/dist/api/managed-executions.js.map +1 -0
- package/dist/api/observer-v2-schema.d.ts +206 -0
- package/dist/api/observer-v2-schema.d.ts.map +1 -0
- package/dist/api/observer-v2-schema.js +264 -0
- package/dist/api/observer-v2-schema.js.map +1 -0
- package/dist/api/observer-v2.d.ts +33 -0
- package/dist/api/observer-v2.d.ts.map +1 -0
- package/dist/api/observer-v2.js +60 -0
- package/dist/api/observer-v2.js.map +1 -0
- package/dist/api/owner-observe-grants-v2-schema.d.ts +678 -0
- package/dist/api/owner-observe-grants-v2-schema.d.ts.map +1 -0
- package/dist/api/owner-observe-grants-v2-schema.js +887 -0
- package/dist/api/owner-observe-grants-v2-schema.js.map +1 -0
- package/dist/api/owner-observe-grants-v2.d.ts +268 -0
- package/dist/api/owner-observe-grants-v2.d.ts.map +1 -0
- package/dist/api/owner-observe-grants-v2.js +604 -0
- package/dist/api/owner-observe-grants-v2.js.map +1 -0
- package/dist/api/provider-v2-schema.d.ts +293 -0
- package/dist/api/provider-v2-schema.d.ts.map +1 -0
- package/dist/api/provider-v2-schema.js +381 -0
- package/dist/api/provider-v2-schema.js.map +1 -0
- package/dist/api/provider-v2.d.ts +55 -0
- package/dist/api/provider-v2.d.ts.map +1 -0
- package/dist/api/provider-v2.js +54 -0
- package/dist/api/provider-v2.js.map +1 -0
- package/dist/api/remote-workspace.d.ts +29 -0
- package/dist/api/remote-workspace.d.ts.map +1 -0
- package/dist/api/remote-workspace.js +62 -0
- package/dist/api/remote-workspace.js.map +1 -0
- package/dist/api/supervisor-live-update.d.ts +248 -0
- package/dist/api/supervisor-live-update.d.ts.map +1 -0
- package/dist/api/supervisor-live-update.js +434 -0
- package/dist/api/supervisor-live-update.js.map +1 -0
- package/dist/api/terminal-reason.d.ts +5 -0
- package/dist/api/terminal-reason.d.ts.map +1 -0
- package/dist/api/terminal-reason.js +12 -0
- package/dist/api/terminal-reason.js.map +1 -0
- package/dist/auth/browser-handoff.d.ts +59 -0
- package/dist/auth/browser-handoff.d.ts.map +1 -0
- package/dist/auth/browser-handoff.js +33 -0
- package/dist/auth/browser-handoff.js.map +1 -0
- package/dist/auth/browser.d.ts +11 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +47 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/human-client.d.ts +39 -0
- package/dist/auth/human-client.d.ts.map +1 -0
- package/dist/auth/human-client.js +66 -0
- package/dist/auth/human-client.js.map +1 -0
- package/dist/auth/human-contracts.d.ts +52 -0
- package/dist/auth/human-contracts.d.ts.map +1 -0
- package/dist/auth/human-contracts.js +229 -0
- package/dist/auth/human-contracts.js.map +1 -0
- package/dist/auth/human-session.d.ts +48 -0
- package/dist/auth/human-session.d.ts.map +1 -0
- package/dist/auth/human-session.js +902 -0
- package/dist/auth/human-session.js.map +1 -0
- package/dist/auth/onboarding-state.d.ts +31 -0
- package/dist/auth/onboarding-state.d.ts.map +1 -0
- package/dist/auth/onboarding-state.js +52 -0
- package/dist/auth/onboarding-state.js.map +1 -0
- package/dist/auth/pkce.d.ts +15 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +19 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/bin/cuna.d.ts +3 -0
- package/dist/bin/cuna.d.ts.map +1 -0
- package/dist/bin/cuna.js +4 -0
- package/dist/bin/cuna.js.map +1 -0
- package/dist/build-identity.d.ts +20 -0
- package/dist/build-identity.d.ts.map +1 -0
- package/dist/build-identity.js +77 -0
- package/dist/build-identity.js.map +1 -0
- package/dist/cli/command-help.d.ts +9 -0
- package/dist/cli/command-help.d.ts.map +1 -0
- package/dist/cli/command-help.js +324 -0
- package/dist/cli/command-help.js.map +1 -0
- package/dist/cli/help.d.ts +40 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +256 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/output.d.ts +28 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +95 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/parser.d.ts +65 -0
- package/dist/cli/parser.d.ts.map +1 -0
- package/dist/cli/parser.js +294 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/cli/process-entrypoint.d.ts +18 -0
- package/dist/cli/process-entrypoint.d.ts.map +1 -0
- package/dist/cli/process-entrypoint.js +26 -0
- package/dist/cli/process-entrypoint.js.map +1 -0
- package/dist/cli/run.d.ts +114 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +1969 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/commands/commands.d.ts +74 -0
- package/dist/commands/commands.d.ts.map +1 -0
- package/dist/commands/commands.js +2814 -0
- package/dist/commands/commands.js.map +1 -0
- package/dist/config/config.d.ts +86 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +323 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/infra-contract-witness.d.ts +29 -0
- package/dist/config/infra-contract-witness.d.ts.map +1 -0
- package/dist/config/infra-contract-witness.js +30 -0
- package/dist/config/infra-contract-witness.js.map +1 -0
- package/dist/core/browser-url.d.ts +2 -0
- package/dist/core/browser-url.d.ts.map +1 -0
- package/dist/core/browser-url.js +20 -0
- package/dist/core/browser-url.js.map +1 -0
- package/dist/core/deployed-wire-compatibility.d.ts +15 -0
- package/dist/core/deployed-wire-compatibility.d.ts.map +1 -0
- package/dist/core/deployed-wire-compatibility.js +15 -0
- package/dist/core/deployed-wire-compatibility.js.map +1 -0
- package/dist/core/errors.d.ts +59 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +82 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/exit-codes.d.ts +68 -0
- package/dist/core/exit-codes.d.ts.map +1 -0
- package/dist/core/exit-codes.js +84 -0
- package/dist/core/exit-codes.js.map +1 -0
- package/dist/core/instant.d.ts +60 -0
- package/dist/core/instant.d.ts.map +1 -0
- package/dist/core/instant.js +90 -0
- package/dist/core/instant.js.map +1 -0
- package/dist/core/namespace.d.ts +171 -0
- package/dist/core/namespace.d.ts.map +1 -0
- package/dist/core/namespace.js +227 -0
- package/dist/core/namespace.js.map +1 -0
- package/dist/core/observation-budget.d.ts +185 -0
- package/dist/core/observation-budget.d.ts.map +1 -0
- package/dist/core/observation-budget.js +209 -0
- package/dist/core/observation-budget.js.map +1 -0
- package/dist/core/product-web.d.ts +81 -0
- package/dist/core/product-web.d.ts.map +1 -0
- package/dist/core/product-web.js +87 -0
- package/dist/core/product-web.js.map +1 -0
- package/dist/core/validation.d.ts +90 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +199 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/credentials/contracts.d.ts +82 -0
- package/dist/credentials/contracts.d.ts.map +1 -0
- package/dist/credentials/contracts.js +2 -0
- package/dist/credentials/contracts.js.map +1 -0
- package/dist/credentials/errors.d.ts +19 -0
- package/dist/credentials/errors.d.ts.map +1 -0
- package/dist/credentials/errors.js +16 -0
- package/dist/credentials/errors.js.map +1 -0
- package/dist/credentials/index.d.ts +6 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +6 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/local-session.d.ts +101 -0
- package/dist/credentials/local-session.d.ts.map +1 -0
- package/dist/credentials/local-session.js +839 -0
- package/dist/credentials/local-session.js.map +1 -0
- package/dist/credentials/secret-material.d.ts +17 -0
- package/dist/credentials/secret-material.d.ts.map +1 -0
- package/dist/credentials/secret-material.js +49 -0
- package/dist/credentials/secret-material.js.map +1 -0
- package/dist/credentials/vault.d.ts +41 -0
- package/dist/credentials/vault.d.ts.map +1 -0
- package/dist/credentials/vault.js +719 -0
- package/dist/credentials/vault.js.map +1 -0
- package/dist/daemon/endpoint.d.ts +29 -0
- package/dist/daemon/endpoint.d.ts.map +1 -0
- package/dist/daemon/endpoint.js +66 -0
- package/dist/daemon/endpoint.js.map +1 -0
- package/dist/daemon/journal.d.ts +62 -0
- package/dist/daemon/journal.d.ts.map +1 -0
- package/dist/daemon/journal.js +299 -0
- package/dist/daemon/journal.js.map +1 -0
- package/dist/daemon/lease.d.ts +25 -0
- package/dist/daemon/lease.d.ts.map +1 -0
- package/dist/daemon/lease.js +94 -0
- package/dist/daemon/lease.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +14 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +29 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/protocol.d.ts +65 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +194 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +29 -0
- package/dist/daemon/supervisor.d.ts.map +1 -0
- package/dist/daemon/supervisor.js +87 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/daemon/views.d.ts +31 -0
- package/dist/daemon/views.d.ts.map +1 -0
- package/dist/daemon/views.js +86 -0
- package/dist/daemon/views.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/journey/api-effects.d.ts +59 -0
- package/dist/journey/api-effects.d.ts.map +1 -0
- package/dist/journey/api-effects.js +386 -0
- package/dist/journey/api-effects.js.map +1 -0
- package/dist/journey/derived-identity.d.ts +91 -0
- package/dist/journey/derived-identity.d.ts.map +1 -0
- package/dist/journey/derived-identity.js +123 -0
- package/dist/journey/derived-identity.js.map +1 -0
- package/dist/journey/index.d.ts +6 -0
- package/dist/journey/index.d.ts.map +1 -0
- package/dist/journey/index.js +6 -0
- package/dist/journey/index.js.map +1 -0
- package/dist/journey/intent.d.ts +36 -0
- package/dist/journey/intent.d.ts.map +1 -0
- package/dist/journey/intent.js +191 -0
- package/dist/journey/intent.js.map +1 -0
- package/dist/journey/orchestrator.d.ts +140 -0
- package/dist/journey/orchestrator.d.ts.map +1 -0
- package/dist/journey/orchestrator.js +415 -0
- package/dist/journey/orchestrator.js.map +1 -0
- package/dist/journey/provider-launch-intent.d.ts +12 -0
- package/dist/journey/provider-launch-intent.d.ts.map +1 -0
- package/dist/journey/provider-launch-intent.js +40 -0
- package/dist/journey/provider-launch-intent.js.map +1 -0
- package/dist/journey/remote-workspace.d.ts +34 -0
- package/dist/journey/remote-workspace.d.ts.map +1 -0
- package/dist/journey/remote-workspace.js +91 -0
- package/dist/journey/remote-workspace.js.map +1 -0
- package/dist/journey/root-entry.d.ts +56 -0
- package/dist/journey/root-entry.d.ts.map +1 -0
- package/dist/journey/root-entry.js +19 -0
- package/dist/journey/root-entry.js.map +1 -0
- package/dist/journey/selection.d.ts +165 -0
- package/dist/journey/selection.d.ts.map +1 -0
- package/dist/journey/selection.js +565 -0
- package/dist/journey/selection.js.map +1 -0
- package/dist/journey/session-failure.d.ts +4 -0
- package/dist/journey/session-failure.d.ts.map +1 -0
- package/dist/journey/session-failure.js +28 -0
- package/dist/journey/session-failure.js.map +1 -0
- package/dist/journey/workspace-effects.d.ts +30 -0
- package/dist/journey/workspace-effects.d.ts.map +1 -0
- package/dist/journey/workspace-effects.js +348 -0
- package/dist/journey/workspace-effects.js.map +1 -0
- package/dist/local-actions/broker.d.ts +32 -0
- package/dist/local-actions/broker.d.ts.map +1 -0
- package/dist/local-actions/broker.js +400 -0
- package/dist/local-actions/broker.js.map +1 -0
- package/dist/local-actions/browser-action.d.ts +78 -0
- package/dist/local-actions/browser-action.d.ts.map +1 -0
- package/dist/local-actions/browser-action.js +307 -0
- package/dist/local-actions/browser-action.js.map +1 -0
- package/dist/local-actions/callback-relay.d.ts +45 -0
- package/dist/local-actions/callback-relay.d.ts.map +1 -0
- package/dist/local-actions/callback-relay.js +265 -0
- package/dist/local-actions/callback-relay.js.map +1 -0
- package/dist/local-actions/clipboard.d.ts +3 -0
- package/dist/local-actions/clipboard.d.ts.map +1 -0
- package/dist/local-actions/clipboard.js +18 -0
- package/dist/local-actions/clipboard.js.map +1 -0
- package/dist/local-actions/contracts.d.ts +63 -0
- package/dist/local-actions/contracts.d.ts.map +1 -0
- package/dist/local-actions/contracts.js +18 -0
- package/dist/local-actions/contracts.js.map +1 -0
- package/dist/local-actions/desktop-presentation.d.ts +141 -0
- package/dist/local-actions/desktop-presentation.d.ts.map +1 -0
- package/dist/local-actions/desktop-presentation.js +253 -0
- package/dist/local-actions/desktop-presentation.js.map +1 -0
- package/dist/local-actions/device-selection.d.ts +43 -0
- package/dist/local-actions/device-selection.d.ts.map +1 -0
- package/dist/local-actions/device-selection.js +154 -0
- package/dist/local-actions/device-selection.js.map +1 -0
- package/dist/local-actions/executor.d.ts +49 -0
- package/dist/local-actions/executor.d.ts.map +1 -0
- package/dist/local-actions/executor.js +329 -0
- package/dist/local-actions/executor.js.map +1 -0
- package/dist/local-actions/file-transfers.d.ts +141 -0
- package/dist/local-actions/file-transfers.d.ts.map +1 -0
- package/dist/local-actions/file-transfers.js +446 -0
- package/dist/local-actions/file-transfers.js.map +1 -0
- package/dist/local-actions/foreground-notifications.d.ts +45 -0
- package/dist/local-actions/foreground-notifications.d.ts.map +1 -0
- package/dist/local-actions/foreground-notifications.js +163 -0
- package/dist/local-actions/foreground-notifications.js.map +1 -0
- package/dist/local-actions/git-signing.d.ts +39 -0
- package/dist/local-actions/git-signing.d.ts.map +1 -0
- package/dist/local-actions/git-signing.js +135 -0
- package/dist/local-actions/git-signing.js.map +1 -0
- package/dist/local-actions/index.d.ts +19 -0
- package/dist/local-actions/index.d.ts.map +1 -0
- package/dist/local-actions/index.js +19 -0
- package/dist/local-actions/index.js.map +1 -0
- package/dist/local-actions/local-service-actions.d.ts +87 -0
- package/dist/local-actions/local-service-actions.d.ts.map +1 -0
- package/dist/local-actions/local-service-actions.js +347 -0
- package/dist/local-actions/local-service-actions.js.map +1 -0
- package/dist/local-actions/loopback.d.ts +5 -0
- package/dist/local-actions/loopback.d.ts.map +1 -0
- package/dist/local-actions/loopback.js +15 -0
- package/dist/local-actions/loopback.js.map +1 -0
- package/dist/local-actions/policy-store.d.ts +7 -0
- package/dist/local-actions/policy-store.d.ts.map +1 -0
- package/dist/local-actions/policy-store.js +70 -0
- package/dist/local-actions/policy-store.js.map +1 -0
- package/dist/local-actions/policy.d.ts +21 -0
- package/dist/local-actions/policy.d.ts.map +1 -0
- package/dist/local-actions/policy.js +43 -0
- package/dist/local-actions/policy.js.map +1 -0
- package/dist/local-actions/private-port-forward.d.ts +36 -0
- package/dist/local-actions/private-port-forward.d.ts.map +1 -0
- package/dist/local-actions/private-port-forward.js +154 -0
- package/dist/local-actions/private-port-forward.js.map +1 -0
- package/dist/local-actions/provider-mcp-config.d.ts +101 -0
- package/dist/local-actions/provider-mcp-config.d.ts.map +1 -0
- package/dist/local-actions/provider-mcp-config.js +166 -0
- package/dist/local-actions/provider-mcp-config.js.map +1 -0
- package/dist/local-actions/providers.d.ts +12 -0
- package/dist/local-actions/providers.d.ts.map +1 -0
- package/dist/local-actions/providers.js +42 -0
- package/dist/local-actions/providers.js.map +1 -0
- package/dist/local-actions/schemas.d.ts +4 -0
- package/dist/local-actions/schemas.d.ts.map +1 -0
- package/dist/local-actions/schemas.js +314 -0
- package/dist/local-actions/schemas.js.map +1 -0
- package/dist/local-actions/sensitive-consent.d.ts +32 -0
- package/dist/local-actions/sensitive-consent.d.ts.map +1 -0
- package/dist/local-actions/sensitive-consent.js +47 -0
- package/dist/local-actions/sensitive-consent.js.map +1 -0
- package/dist/machines/command-launch.d.ts +17 -0
- package/dist/machines/command-launch.d.ts.map +1 -0
- package/dist/machines/command-launch.js +52 -0
- package/dist/machines/command-launch.js.map +1 -0
- package/dist/machines/execution-receipt.d.ts +18 -0
- package/dist/machines/execution-receipt.d.ts.map +1 -0
- package/dist/machines/execution-receipt.js +87 -0
- package/dist/machines/execution-receipt.js.map +1 -0
- package/dist/machines/executions-screen.d.ts +6 -0
- package/dist/machines/executions-screen.d.ts.map +1 -0
- package/dist/machines/executions-screen.js +410 -0
- package/dist/machines/executions-screen.js.map +1 -0
- package/dist/machines/explorer.d.ts +75 -0
- package/dist/machines/explorer.d.ts.map +1 -0
- package/dist/machines/explorer.js +1726 -0
- package/dist/machines/explorer.js.map +1 -0
- package/dist/machines/live-supervisor-update.d.ts +325 -0
- package/dist/machines/live-supervisor-update.d.ts.map +1 -0
- package/dist/machines/live-supervisor-update.js +513 -0
- package/dist/machines/live-supervisor-update.js.map +1 -0
- package/dist/machines/machine-first.d.ts +123 -0
- package/dist/machines/machine-first.d.ts.map +1 -0
- package/dist/machines/machine-first.js +119 -0
- package/dist/machines/machine-first.js.map +1 -0
- package/dist/machines/opencode-supervisor.d.ts +51 -0
- package/dist/machines/opencode-supervisor.d.ts.map +1 -0
- package/dist/machines/opencode-supervisor.js +124 -0
- package/dist/machines/opencode-supervisor.js.map +1 -0
- package/dist/machines/pagination.d.ts +4 -0
- package/dist/machines/pagination.d.ts.map +1 -0
- package/dist/machines/pagination.js +7 -0
- package/dist/machines/pagination.js.map +1 -0
- package/dist/machines/provider-availability.d.ts +42 -0
- package/dist/machines/provider-availability.d.ts.map +1 -0
- package/dist/machines/provider-availability.js +82 -0
- package/dist/machines/provider-availability.js.map +1 -0
- package/dist/machines/provider-screen.d.ts +12 -0
- package/dist/machines/provider-screen.d.ts.map +1 -0
- package/dist/machines/provider-screen.js +129 -0
- package/dist/machines/provider-screen.js.map +1 -0
- package/dist/machines/session-actionability.d.ts +86 -0
- package/dist/machines/session-actionability.d.ts.map +1 -0
- package/dist/machines/session-actionability.js +125 -0
- package/dist/machines/session-actionability.js.map +1 -0
- package/dist/machines/session-visibility.d.ts +139 -0
- package/dist/machines/session-visibility.d.ts.map +1 -0
- package/dist/machines/session-visibility.js +109 -0
- package/dist/machines/session-visibility.js.map +1 -0
- package/dist/platform/adapter.d.ts +62 -0
- package/dist/platform/adapter.d.ts.map +1 -0
- package/dist/platform/adapter.js +240 -0
- package/dist/platform/adapter.js.map +1 -0
- package/dist/platform/support.d.ts +12 -0
- package/dist/platform/support.d.ts.map +1 -0
- package/dist/platform/support.js +25 -0
- package/dist/platform/support.js.map +1 -0
- package/dist/pty/contracts.d.ts +45 -0
- package/dist/pty/contracts.d.ts.map +1 -0
- package/dist/pty/contracts.js +2 -0
- package/dist/pty/contracts.js.map +1 -0
- package/dist/pty/evidence-gate.d.ts +14 -0
- package/dist/pty/evidence-gate.d.ts.map +1 -0
- package/dist/pty/evidence-gate.js +35 -0
- package/dist/pty/evidence-gate.js.map +1 -0
- package/dist/pty/index.d.ts +5 -0
- package/dist/pty/index.d.ts.map +1 -0
- package/dist/pty/index.js +5 -0
- package/dist/pty/index.js.map +1 -0
- package/dist/pty/node-host-terminal.d.ts +14 -0
- package/dist/pty/node-host-terminal.d.ts.map +1 -0
- package/dist/pty/node-host-terminal.js +173 -0
- package/dist/pty/node-host-terminal.js.map +1 -0
- package/dist/pty/node-process.d.ts +26 -0
- package/dist/pty/node-process.d.ts.map +1 -0
- package/dist/pty/node-process.js +102 -0
- package/dist/pty/node-process.js.map +1 -0
- package/dist/runtime/api-terminal-control-plane.d.ts +7 -0
- package/dist/runtime/api-terminal-control-plane.d.ts.map +1 -0
- package/dist/runtime/api-terminal-control-plane.js +95 -0
- package/dist/runtime/api-terminal-control-plane.js.map +1 -0
- package/dist/runtime/backoff.d.ts +17 -0
- package/dist/runtime/backoff.d.ts.map +1 -0
- package/dist/runtime/backoff.js +61 -0
- package/dist/runtime/backoff.js.map +1 -0
- package/dist/runtime/boundary.d.ts +171 -0
- package/dist/runtime/boundary.d.ts.map +1 -0
- package/dist/runtime/boundary.js +1858 -0
- package/dist/runtime/boundary.js.map +1 -0
- package/dist/runtime/capability-gate.d.ts +25 -0
- package/dist/runtime/capability-gate.d.ts.map +1 -0
- package/dist/runtime/capability-gate.js +77 -0
- package/dist/runtime/capability-gate.js.map +1 -0
- package/dist/runtime/contracts.d.ts +25 -0
- package/dist/runtime/contracts.d.ts.map +1 -0
- package/dist/runtime/contracts.js +66 -0
- package/dist/runtime/contracts.js.map +1 -0
- package/dist/runtime/errors.d.ts +20 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +22 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +9 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/node-foreground-session.d.ts +50 -0
- package/dist/runtime/node-foreground-session.d.ts.map +1 -0
- package/dist/runtime/node-foreground-session.js +431 -0
- package/dist/runtime/node-foreground-session.js.map +1 -0
- package/dist/runtime/node-websocket-connector.d.ts +6 -0
- package/dist/runtime/node-websocket-connector.d.ts.map +1 -0
- package/dist/runtime/node-websocket-connector.js +344 -0
- package/dist/runtime/node-websocket-connector.js.map +1 -0
- package/dist/runtime/observer-screen.d.ts +6 -0
- package/dist/runtime/observer-screen.d.ts.map +1 -0
- package/dist/runtime/observer-screen.js +144 -0
- package/dist/runtime/observer-screen.js.map +1 -0
- package/dist/runtime/owner-grant-operations.d.ts +136 -0
- package/dist/runtime/owner-grant-operations.d.ts.map +1 -0
- package/dist/runtime/owner-grant-operations.js +216 -0
- package/dist/runtime/owner-grant-operations.js.map +1 -0
- package/dist/runtime/owner-grants-screen.d.ts +40 -0
- package/dist/runtime/owner-grants-screen.d.ts.map +1 -0
- package/dist/runtime/owner-grants-screen.js +987 -0
- package/dist/runtime/owner-grants-screen.js.map +1 -0
- package/dist/runtime/terminal-transport.d.ts +85 -0
- package/dist/runtime/terminal-transport.d.ts.map +1 -0
- package/dist/runtime/terminal-transport.js +152 -0
- package/dist/runtime/terminal-transport.js.map +1 -0
- package/dist/sync/continuous-sync-supervisor.d.ts +107 -0
- package/dist/sync/continuous-sync-supervisor.d.ts.map +1 -0
- package/dist/sync/continuous-sync-supervisor.js +1117 -0
- package/dist/sync/continuous-sync-supervisor.js.map +1 -0
- package/dist/sync/index.d.ts +9 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +9 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/journal.d.ts +57 -0
- package/dist/sync/journal.d.ts.map +1 -0
- package/dist/sync/journal.js +685 -0
- package/dist/sync/journal.js.map +1 -0
- package/dist/sync/revisions.d.ts +118 -0
- package/dist/sync/revisions.d.ts.map +1 -0
- package/dist/sync/revisions.js +364 -0
- package/dist/sync/revisions.js.map +1 -0
- package/dist/sync/supervisor.d.ts +107 -0
- package/dist/sync/supervisor.d.ts.map +1 -0
- package/dist/sync/supervisor.js +246 -0
- package/dist/sync/supervisor.js.map +1 -0
- package/dist/sync/workspace-sync-client.d.ts +18 -0
- package/dist/sync/workspace-sync-client.d.ts.map +1 -0
- package/dist/sync/workspace-sync-client.js +150 -0
- package/dist/sync/workspace-sync-client.js.map +1 -0
- package/dist/sync/workspace-sync-coordinator.d.ts +76 -0
- package/dist/sync/workspace-sync-coordinator.d.ts.map +1 -0
- package/dist/sync/workspace-sync-coordinator.js +621 -0
- package/dist/sync/workspace-sync-coordinator.js.map +1 -0
- package/dist/sync/workspace-sync-product-service.d.ts +79 -0
- package/dist/sync/workspace-sync-product-service.d.ts.map +1 -0
- package/dist/sync/workspace-sync-product-service.js +398 -0
- package/dist/sync/workspace-sync-product-service.js.map +1 -0
- package/dist/sync/workspace-sync-protocol.d.ts +145 -0
- package/dist/sync/workspace-sync-protocol.d.ts.map +1 -0
- package/dist/sync/workspace-sync-protocol.js +347 -0
- package/dist/sync/workspace-sync-protocol.js.map +1 -0
- package/dist/terminal/appbar.d.ts +40 -0
- package/dist/terminal/appbar.d.ts.map +1 -0
- package/dist/terminal/appbar.js +55 -0
- package/dist/terminal/appbar.js.map +1 -0
- package/dist/terminal/cell-width.d.ts +3 -0
- package/dist/terminal/cell-width.d.ts.map +1 -0
- package/dist/terminal/cell-width.js +53 -0
- package/dist/terminal/cell-width.js.map +1 -0
- package/dist/terminal/codec.d.ts +107 -0
- package/dist/terminal/codec.d.ts.map +1 -0
- package/dist/terminal/codec.js +538 -0
- package/dist/terminal/codec.js.map +1 -0
- package/dist/terminal/foreground.d.ts +135 -0
- package/dist/terminal/foreground.d.ts.map +1 -0
- package/dist/terminal/foreground.js +2097 -0
- package/dist/terminal/foreground.js.map +1 -0
- package/dist/terminal/generated/terminal-wire-v1.d.ts +26 -0
- package/dist/terminal/generated/terminal-wire-v1.d.ts.map +1 -0
- package/dist/terminal/generated/terminal-wire-v1.js +27 -0
- package/dist/terminal/generated/terminal-wire-v1.js.map +1 -0
- package/dist/terminal/mode.d.ts +33 -0
- package/dist/terminal/mode.d.ts.map +1 -0
- package/dist/terminal/mode.js +99 -0
- package/dist/terminal/mode.js.map +1 -0
- package/dist/terminal/passthrough.d.ts +47 -0
- package/dist/terminal/passthrough.d.ts.map +1 -0
- package/dist/terminal/passthrough.js +666 -0
- package/dist/terminal/passthrough.js.map +1 -0
- package/dist/terminal/resume.d.ts +58 -0
- package/dist/terminal/resume.d.ts.map +1 -0
- package/dist/terminal/resume.js +185 -0
- package/dist/terminal/resume.js.map +1 -0
- package/dist/terminal/viewport.d.ts +93 -0
- package/dist/terminal/viewport.d.ts.map +1 -0
- package/dist/terminal/viewport.js +266 -0
- package/dist/terminal/viewport.js.map +1 -0
- package/dist/terminal/workbench.d.ts +32 -0
- package/dist/terminal/workbench.d.ts.map +1 -0
- package/dist/terminal/workbench.js +316 -0
- package/dist/terminal/workbench.js.map +1 -0
- package/dist/terminal/xterm-vte.d.ts +49 -0
- package/dist/terminal/xterm-vte.d.ts.map +1 -0
- package/dist/terminal/xterm-vte.js +602 -0
- package/dist/terminal/xterm-vte.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace/binding-path.d.ts +17 -0
- package/dist/workspace/binding-path.d.ts.map +1 -0
- package/dist/workspace/binding-path.js +91 -0
- package/dist/workspace/binding-path.js.map +1 -0
- package/dist/workspace/binding-store.d.ts +107 -0
- package/dist/workspace/binding-store.d.ts.map +1 -0
- package/dist/workspace/binding-store.js +783 -0
- package/dist/workspace/binding-store.js.map +1 -0
- package/dist/workspace/binding.d.ts +35 -0
- package/dist/workspace/binding.d.ts.map +1 -0
- package/dist/workspace/binding.js +70 -0
- package/dist/workspace/binding.js.map +1 -0
- package/dist/workspace/errors.d.ts +4 -0
- package/dist/workspace/errors.d.ts.map +1 -0
- package/dist/workspace/errors.js +19 -0
- package/dist/workspace/errors.js.map +1 -0
- package/dist/workspace/exclusion.d.ts +21 -0
- package/dist/workspace/exclusion.d.ts.map +1 -0
- package/dist/workspace/exclusion.js +243 -0
- package/dist/workspace/exclusion.js.map +1 -0
- package/dist/workspace/index.d.ts +8 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +8 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/lifecycle.d.ts +56 -0
- package/dist/workspace/lifecycle.d.ts.map +1 -0
- package/dist/workspace/lifecycle.js +94 -0
- package/dist/workspace/lifecycle.js.map +1 -0
- package/dist/workspace/manifest.d.ts +47 -0
- package/dist/workspace/manifest.d.ts.map +1 -0
- package/dist/workspace/manifest.js +243 -0
- package/dist/workspace/manifest.js.map +1 -0
- package/dist/workspace/paths.d.ts +14 -0
- package/dist/workspace/paths.d.ts.map +1 -0
- package/dist/workspace/paths.js +67 -0
- package/dist/workspace/paths.js.map +1 -0
- package/dist/workspace/schema.d.ts +15 -0
- package/dist/workspace/schema.d.ts.map +1 -0
- package/dist/workspace/schema.js +33 -0
- package/dist/workspace/schema.js.map +1 -0
- package/dist/workspace/selection-screen.d.ts +4 -0
- package/dist/workspace/selection-screen.d.ts.map +1 -0
- package/dist/workspace/selection-screen.js +216 -0
- package/dist/workspace/selection-screen.js.map +1 -0
- package/dist/workspace/selection-service.d.ts +16 -0
- package/dist/workspace/selection-service.d.ts.map +1 -0
- package/dist/workspace/selection-service.js +65 -0
- package/dist/workspace/selection-service.js.map +1 -0
- package/node_modules/@xterm/headless/README.md +31 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.js +2 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.js.map +1 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.mjs.map +7 -0
- package/node_modules/@xterm/headless/package.json +29 -0
- package/node_modules/@xterm/headless/typings/xterm-headless.d.ts +1385 -0
- package/package.json +75 -0
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { constants as fileConstants } from "node:fs";
|
|
3
|
+
import { chmod, lstat, mkdir, open, readdir, realpath, rename, unlink, } from "node:fs/promises";
|
|
4
|
+
import { createConnection, createServer } from "node:net";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
7
|
+
import { instantOrNull, sameInstant } from "../core/instant.js";
|
|
8
|
+
import { assertPublicId } from "../core/validation.js";
|
|
9
|
+
import { assertCanonicalWorkspaceRootUnchanged, assertPathWithinBoundary, captureCanonicalWorkspaceRoot, sameCanonicalPath, sameWorkspaceRootIdentity, } from "./binding-path.js";
|
|
10
|
+
import { workspaceError } from "./errors.js";
|
|
11
|
+
const METADATA_DIRECTORY = ".cuna";
|
|
12
|
+
const BINDING_FILE = "workspace.json";
|
|
13
|
+
const RECORD_TYPE = "cuna.workspace-binding.v2";
|
|
14
|
+
const EXECUTION_RECORD_TYPE = "cuna.workspace-binding.v3";
|
|
15
|
+
const MAXIMUM_RECORD_BYTES = 65_536;
|
|
16
|
+
const DIGEST = /^[a-f0-9]{64}$/u;
|
|
17
|
+
const PROFILE_CONTROL = /[\p{Cc}\p{Cf}]/u;
|
|
18
|
+
const TEMPORARY_RECORD = /^\.workspace\.json\.\d+\.[0-9a-f-]{36}\.tmp$/u;
|
|
19
|
+
export async function discoverWorkspaceBindingMarker(input) {
|
|
20
|
+
let current = await canonicalStartDirectory(input.startPath);
|
|
21
|
+
const explicitBoundary = input.boundaryPath === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: await captureCanonicalWorkspaceRoot(input.boundaryPath);
|
|
24
|
+
if (explicitBoundary !== undefined)
|
|
25
|
+
assertPathWithinBoundary(explicitBoundary.path, current.path);
|
|
26
|
+
while (true) {
|
|
27
|
+
const marker = await markerAt(current);
|
|
28
|
+
if (marker !== undefined)
|
|
29
|
+
return marker;
|
|
30
|
+
if (explicitBoundary !== undefined && sameCanonicalPath(current.path, explicitBoundary.path))
|
|
31
|
+
return undefined;
|
|
32
|
+
const parentPath = dirname(current.path);
|
|
33
|
+
if (sameCanonicalPath(parentPath, current.path))
|
|
34
|
+
return undefined;
|
|
35
|
+
if (explicitBoundary !== undefined)
|
|
36
|
+
assertPathWithinBoundary(explicitBoundary.path, parentPath);
|
|
37
|
+
const parent = await captureCanonicalWorkspaceRoot(parentPath);
|
|
38
|
+
// Do not silently cross a mount boundary: a parent filesystem is a
|
|
39
|
+
// different physical authority even when it is lexically adjacent.
|
|
40
|
+
if (parent.identity.device !== current.identity.device)
|
|
41
|
+
return undefined;
|
|
42
|
+
current = parent;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function loadWorkspaceBinding(input) {
|
|
46
|
+
const marker = await discoverWorkspaceBindingMarker({
|
|
47
|
+
startPath: input.startPath,
|
|
48
|
+
...(input.boundaryPath === undefined ? {} : { boundaryPath: input.boundaryPath }),
|
|
49
|
+
});
|
|
50
|
+
if (marker === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
const record = await readBindingRecord(marker);
|
|
53
|
+
assertExpectedAuthority(record, input.expected);
|
|
54
|
+
const relocationRequired = !sameCanonicalPath(record.canonicalLocalRoot, marker.workspaceRoot.path);
|
|
55
|
+
return Object.freeze({ marker, record, relocationRequired });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Loads only integrity-checked local intent for the authenticated owner. Remote
|
|
59
|
+
* machine, policy and generation fields remain untrusted until the caller
|
|
60
|
+
* reconciles the complete tuple with the canonical WorkspaceBinding service.
|
|
61
|
+
*/
|
|
62
|
+
export async function loadWorkspaceBindingIntent(input) {
|
|
63
|
+
const marker = await discoverWorkspaceBindingMarker({
|
|
64
|
+
startPath: input.startPath,
|
|
65
|
+
...(input.boundaryPath === undefined ? {} : { boundaryPath: input.boundaryPath }),
|
|
66
|
+
});
|
|
67
|
+
if (marker === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
const record = await readBindingRecord(marker);
|
|
70
|
+
if (record.profileId !== input.profileId ||
|
|
71
|
+
record.userId !== input.userId ||
|
|
72
|
+
record.workspaceId !== input.workspaceId) {
|
|
73
|
+
throw ownerMismatch();
|
|
74
|
+
}
|
|
75
|
+
const relocationRequired = !sameCanonicalPath(record.canonicalLocalRoot, marker.workspaceRoot.path);
|
|
76
|
+
return Object.freeze({ marker, record, relocationRequired });
|
|
77
|
+
}
|
|
78
|
+
export async function persistWorkspaceBinding(input) {
|
|
79
|
+
const root = await captureCanonicalWorkspaceRoot(input.root);
|
|
80
|
+
const lock = await acquireBindingWriterLock(root.identity);
|
|
81
|
+
try {
|
|
82
|
+
await assertCanonicalWorkspaceRootUnchanged(root);
|
|
83
|
+
const metadataDirectory = await prepareMetadataDirectory(root);
|
|
84
|
+
const marker = Object.freeze({
|
|
85
|
+
workspaceRoot: root,
|
|
86
|
+
metadataDirectory,
|
|
87
|
+
recordPath: join(metadataDirectory, BINDING_FILE),
|
|
88
|
+
});
|
|
89
|
+
const current = await readOptionalBindingRecord(marker);
|
|
90
|
+
assertCompareAndSwap(current, input.expected);
|
|
91
|
+
validateDraft(input.binding);
|
|
92
|
+
if (input.rebind === true) {
|
|
93
|
+
if (current === undefined)
|
|
94
|
+
throw staleBinding("rebind_without_record");
|
|
95
|
+
assertRebindIdentity(current, input.binding);
|
|
96
|
+
}
|
|
97
|
+
else if (current !== undefined) {
|
|
98
|
+
assertStableBindingIdentity(current, input.binding);
|
|
99
|
+
}
|
|
100
|
+
const now = input.now ?? new Date();
|
|
101
|
+
if (!Number.isFinite(now.getTime()))
|
|
102
|
+
throw corruptRecord("invalid_timestamp");
|
|
103
|
+
if (current !== undefined && now.getTime() < Date.parse(current.recordUpdatedAt)) {
|
|
104
|
+
throw corruptRecord("clock_rollback");
|
|
105
|
+
}
|
|
106
|
+
if (current?.recordRevision === Number.MAX_SAFE_INTEGER) {
|
|
107
|
+
throw staleBinding("record_revision_exhausted");
|
|
108
|
+
}
|
|
109
|
+
// Only a writer that has proven the current CAS may discard a previous
|
|
110
|
+
// uncommitted temporary image. The authoritative retry input recreates the
|
|
111
|
+
// intended next record; readers instead stop and expose recovery_required.
|
|
112
|
+
await cleanInterruptedTemporaryRecords(metadataDirectory);
|
|
113
|
+
const body = createRecordBody(root, input.binding, current, now);
|
|
114
|
+
const record = freezeRecord({ ...body, integrityDigest: digestRecord(body) });
|
|
115
|
+
await atomicCommitRecord(marker, current, record);
|
|
116
|
+
return record;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await lock.close();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export function workspaceBindingCompareAndSwap(record) {
|
|
123
|
+
return Object.freeze({
|
|
124
|
+
recordRevision: record.recordRevision,
|
|
125
|
+
generation: record.generation,
|
|
126
|
+
integrityDigest: record.integrityDigest,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function canonicalStartDirectory(input) {
|
|
130
|
+
if (input.includes("\0"))
|
|
131
|
+
throw unsafeStore("start_path_invalid");
|
|
132
|
+
const requested = resolve(input);
|
|
133
|
+
const entry = await lstat(requested);
|
|
134
|
+
if (entry.isSymbolicLink())
|
|
135
|
+
throw unsafeStore("start_path_linked");
|
|
136
|
+
if (entry.isDirectory())
|
|
137
|
+
return captureCanonicalWorkspaceRoot(requested);
|
|
138
|
+
if (!entry.isFile())
|
|
139
|
+
throw unsafeStore("start_path_type");
|
|
140
|
+
const physicalFile = await realpath(requested);
|
|
141
|
+
if (!sameCanonicalPath(physicalFile, requested))
|
|
142
|
+
throw unsafeStore("start_path_linked");
|
|
143
|
+
return captureCanonicalWorkspaceRoot(dirname(requested));
|
|
144
|
+
}
|
|
145
|
+
async function markerAt(root) {
|
|
146
|
+
await assertCanonicalWorkspaceRootUnchanged(root);
|
|
147
|
+
const metadataDirectory = join(root.path, METADATA_DIRECTORY);
|
|
148
|
+
try {
|
|
149
|
+
await assertPrivateDirectory(metadataDirectory);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
if (error.code === "ENOENT")
|
|
153
|
+
return undefined;
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
const recordPath = join(metadataDirectory, BINDING_FILE);
|
|
157
|
+
try {
|
|
158
|
+
await assertPrivateRegularFile(recordPath);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (error.code === "ENOENT") {
|
|
162
|
+
await assertNoInterruptedTemporaryRecords(metadataDirectory);
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
await assertNoInterruptedTemporaryRecords(metadataDirectory);
|
|
168
|
+
await assertCanonicalWorkspaceRootUnchanged(root);
|
|
169
|
+
return Object.freeze({ workspaceRoot: root, metadataDirectory, recordPath });
|
|
170
|
+
}
|
|
171
|
+
async function readBindingRecord(marker) {
|
|
172
|
+
await assertMarkerAuthority(marker);
|
|
173
|
+
const text = await readSecureTextFile(marker.recordPath);
|
|
174
|
+
let value;
|
|
175
|
+
try {
|
|
176
|
+
value = JSON.parse(text);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
throw corruptRecord("invalid_json");
|
|
180
|
+
}
|
|
181
|
+
const record = decodeRecord(value);
|
|
182
|
+
await assertMarkerAuthority(marker);
|
|
183
|
+
if (!sameWorkspaceRootIdentity(record.rootIdentity, marker.workspaceRoot.identity)) {
|
|
184
|
+
throw ownerMismatch();
|
|
185
|
+
}
|
|
186
|
+
if (!sameCanonicalPath(record.canonicalLocalRoot, marker.workspaceRoot.path) &&
|
|
187
|
+
!sameWorkspaceRootIdentity(record.rootIdentity, marker.workspaceRoot.identity)) {
|
|
188
|
+
throw ownerMismatch();
|
|
189
|
+
}
|
|
190
|
+
return record;
|
|
191
|
+
}
|
|
192
|
+
async function readOptionalBindingRecord(marker) {
|
|
193
|
+
try {
|
|
194
|
+
return await readBindingRecord(marker);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (error.code === "ENOENT")
|
|
198
|
+
return undefined;
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function decodeRecord(value) {
|
|
203
|
+
try {
|
|
204
|
+
const executionRecord = value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 3;
|
|
205
|
+
const source = exactObject(value, [
|
|
206
|
+
"schemaVersion", "minimumReaderVersion", "minimumWriterVersion", "recordType",
|
|
207
|
+
"recordRevision", "profileId", "userId", "workspaceId", "bindingId", "projectId",
|
|
208
|
+
"localInstanceId", "machineId", "policyDigest", "generation", "canonicalLocalRoot",
|
|
209
|
+
"rootIdentity", "remoteRoot", "bindingCreatedAt", "bindingUpdatedAt",
|
|
210
|
+
"recordCreatedAt", "recordUpdatedAt", "integrityDigest",
|
|
211
|
+
...(executionRecord ? ["executionWorkspaceId"] : []),
|
|
212
|
+
]);
|
|
213
|
+
const rootSource = exactObject(source.rootIdentity, [
|
|
214
|
+
"platform", "device", "inode", "birthtimeNanoseconds",
|
|
215
|
+
]);
|
|
216
|
+
const rootIdentity = Object.freeze({
|
|
217
|
+
platform: oneOf(rootSource.platform, ["windows", "macos", "linux"]),
|
|
218
|
+
device: decimal(rootSource.device),
|
|
219
|
+
inode: positiveDecimal(rootSource.inode),
|
|
220
|
+
birthtimeNanoseconds: decimal(rootSource.birthtimeNanoseconds),
|
|
221
|
+
});
|
|
222
|
+
const withoutDigest = {
|
|
223
|
+
schemaVersion: exactInteger(source.schemaVersion, executionRecord ? 3 : 2, executionRecord ? 3 : 2),
|
|
224
|
+
minimumReaderVersion: exactInteger(source.minimumReaderVersion, executionRecord ? 3 : 1, executionRecord ? 3 : 1),
|
|
225
|
+
minimumWriterVersion: exactInteger(source.minimumWriterVersion, executionRecord ? 3 : 2, executionRecord ? 3 : 2),
|
|
226
|
+
recordType: exactString(source.recordType, executionRecord ? EXECUTION_RECORD_TYPE : RECORD_TYPE),
|
|
227
|
+
recordRevision: integer(source.recordRevision, 1),
|
|
228
|
+
profileId: profile(source.profileId),
|
|
229
|
+
userId: publicId(source.userId, "user ID"),
|
|
230
|
+
workspaceId: publicId(source.workspaceId, "workspace ID"),
|
|
231
|
+
bindingId: publicId(source.bindingId, "binding ID"),
|
|
232
|
+
projectId: publicId(source.projectId, "project ID"),
|
|
233
|
+
...(executionRecord ? { executionWorkspaceId: executionId(source.executionWorkspaceId) } : {}),
|
|
234
|
+
localInstanceId: publicId(source.localInstanceId, "local instance ID"),
|
|
235
|
+
machineId: publicId(source.machineId, "machine ID"),
|
|
236
|
+
policyDigest: digest(source.policyDigest),
|
|
237
|
+
generation: integer(source.generation, 0),
|
|
238
|
+
canonicalLocalRoot: absolutePath(source.canonicalLocalRoot),
|
|
239
|
+
rootIdentity,
|
|
240
|
+
remoteRoot: nonempty(source.remoteRoot),
|
|
241
|
+
bindingCreatedAt: timestamp(source.bindingCreatedAt),
|
|
242
|
+
bindingUpdatedAt: timestamp(source.bindingUpdatedAt),
|
|
243
|
+
recordCreatedAt: timestamp(source.recordCreatedAt),
|
|
244
|
+
recordUpdatedAt: timestamp(source.recordUpdatedAt),
|
|
245
|
+
};
|
|
246
|
+
if (withoutDigest.remoteRoot !== bindingRemoteRoot(withoutDigest)) {
|
|
247
|
+
throw new TypeError("remote root mismatch");
|
|
248
|
+
}
|
|
249
|
+
if (Date.parse(withoutDigest.bindingUpdatedAt) < Date.parse(withoutDigest.bindingCreatedAt) ||
|
|
250
|
+
Date.parse(withoutDigest.recordUpdatedAt) < Date.parse(withoutDigest.recordCreatedAt)) {
|
|
251
|
+
throw new TypeError("timestamp order");
|
|
252
|
+
}
|
|
253
|
+
const integrityDigest = digest(source.integrityDigest);
|
|
254
|
+
if (digestRecord(withoutDigest) !== integrityDigest)
|
|
255
|
+
throw new TypeError("integrity mismatch");
|
|
256
|
+
return freezeRecord({ ...withoutDigest, integrityDigest });
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (isWorkspaceRecordError(error))
|
|
260
|
+
throw error;
|
|
261
|
+
throw corruptRecord("record_shape_or_integrity");
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function validateDraft(draft) {
|
|
265
|
+
try {
|
|
266
|
+
profile(draft.profileId);
|
|
267
|
+
publicId(draft.userId, "user ID");
|
|
268
|
+
publicId(draft.workspaceId, "workspace ID");
|
|
269
|
+
publicId(draft.bindingId, "binding ID");
|
|
270
|
+
const projectId = publicId(draft.projectId, "project ID");
|
|
271
|
+
const localInstanceId = publicId(draft.localInstanceId, "local instance ID");
|
|
272
|
+
if (projectId === localInstanceId)
|
|
273
|
+
throw new TypeError("identity collision");
|
|
274
|
+
publicId(draft.machineId, "machine ID");
|
|
275
|
+
if (draft.executionWorkspaceId !== undefined)
|
|
276
|
+
executionId(draft.executionWorkspaceId);
|
|
277
|
+
if (draft.remoteRoot !== bindingRemoteRoot(draft))
|
|
278
|
+
throw new TypeError("remote root mismatch");
|
|
279
|
+
digest(draft.policyDigest);
|
|
280
|
+
integer(draft.generation, 0);
|
|
281
|
+
const bindingCreatedAt = timestamp(draft.bindingCreatedAt);
|
|
282
|
+
const bindingUpdatedAt = timestamp(draft.bindingUpdatedAt);
|
|
283
|
+
if (Date.parse(bindingUpdatedAt) < Date.parse(bindingCreatedAt))
|
|
284
|
+
throw new TypeError("timestamp order");
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
throw corruptRecord("draft_invalid");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function assertExpectedAuthority(record, expected) {
|
|
291
|
+
let normalizedProfile;
|
|
292
|
+
try {
|
|
293
|
+
normalizedProfile = profile(expected.profileId);
|
|
294
|
+
publicId(expected.userId, "user ID");
|
|
295
|
+
publicId(expected.workspaceId, "workspace ID");
|
|
296
|
+
publicId(expected.machineId, "machine ID");
|
|
297
|
+
nonempty(expected.remoteRoot);
|
|
298
|
+
digest(expected.policyDigest);
|
|
299
|
+
integer(expected.generation, 0);
|
|
300
|
+
timestamp(expected.bindingCreatedAt);
|
|
301
|
+
timestamp(expected.bindingUpdatedAt);
|
|
302
|
+
if (expected.bindingId !== undefined)
|
|
303
|
+
publicId(expected.bindingId, "binding ID");
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
throw ownerMismatch();
|
|
307
|
+
}
|
|
308
|
+
if (record.profileId !== normalizedProfile ||
|
|
309
|
+
record.userId !== expected.userId ||
|
|
310
|
+
record.workspaceId !== expected.workspaceId ||
|
|
311
|
+
record.machineId !== expected.machineId ||
|
|
312
|
+
record.remoteRoot !== expected.remoteRoot ||
|
|
313
|
+
record.policyDigest !== expected.policyDigest ||
|
|
314
|
+
record.generation !== expected.generation ||
|
|
315
|
+
// Instants, not bytes: the left side was copied out of a service response
|
|
316
|
+
// and written to disk, the right side is a fresh service response. They are
|
|
317
|
+
// the same moment rendered twice, and nothing guarantees one renderer.
|
|
318
|
+
!sameInstant(record.bindingCreatedAt, expected.bindingCreatedAt) ||
|
|
319
|
+
!sameInstant(record.bindingUpdatedAt, expected.bindingUpdatedAt) ||
|
|
320
|
+
(expected.bindingId !== undefined && record.bindingId !== expected.bindingId)) {
|
|
321
|
+
throw ownerMismatch();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function assertCompareAndSwap(current, expected) {
|
|
325
|
+
if (expected === null) {
|
|
326
|
+
if (current !== undefined)
|
|
327
|
+
throw staleBinding("record_exists");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (current === undefined ||
|
|
331
|
+
current.recordRevision !== expected.recordRevision ||
|
|
332
|
+
current.generation !== expected.generation ||
|
|
333
|
+
current.integrityDigest !== expected.integrityDigest) {
|
|
334
|
+
throw staleBinding("compare_and_swap_failed");
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function assertStableBindingIdentity(current, next) {
|
|
338
|
+
if (current.profileId !== profile(next.profileId) ||
|
|
339
|
+
current.userId !== next.userId ||
|
|
340
|
+
current.workspaceId !== next.workspaceId ||
|
|
341
|
+
current.bindingId !== next.bindingId ||
|
|
342
|
+
current.executionWorkspaceId !== next.executionWorkspaceId ||
|
|
343
|
+
current.projectId !== next.projectId ||
|
|
344
|
+
current.localInstanceId !== next.localInstanceId ||
|
|
345
|
+
current.machineId !== next.machineId ||
|
|
346
|
+
current.remoteRoot !== next.remoteRoot ||
|
|
347
|
+
!sameInstant(current.bindingCreatedAt, next.bindingCreatedAt) ||
|
|
348
|
+
Date.parse(next.bindingUpdatedAt) < Date.parse(current.bindingUpdatedAt) ||
|
|
349
|
+
next.generation < current.generation) {
|
|
350
|
+
throw ownerMismatch();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* A rebind keeps everything that names the project and changes only what
|
|
355
|
+
* names the Machine and its binding. A "rebind" that lands on the same Machine
|
|
356
|
+
* or the same binding is not a rebind and is refused as an identity error.
|
|
357
|
+
*/
|
|
358
|
+
function assertRebindIdentity(current, next) {
|
|
359
|
+
if (current.profileId !== profile(next.profileId) ||
|
|
360
|
+
current.userId !== next.userId ||
|
|
361
|
+
current.workspaceId !== next.workspaceId ||
|
|
362
|
+
current.projectId !== next.projectId ||
|
|
363
|
+
current.localInstanceId !== next.localInstanceId ||
|
|
364
|
+
(next.executionWorkspaceId === undefined && current.remoteRoot !== next.remoteRoot) ||
|
|
365
|
+
current.machineId === next.machineId ||
|
|
366
|
+
current.bindingId === next.bindingId) {
|
|
367
|
+
throw ownerMismatch();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function createRecordBody(root, draft, current, now) {
|
|
371
|
+
return Object.freeze({
|
|
372
|
+
schemaVersion: draft.executionWorkspaceId === undefined ? 2 : 3,
|
|
373
|
+
minimumReaderVersion: draft.executionWorkspaceId === undefined ? 1 : 3,
|
|
374
|
+
minimumWriterVersion: draft.executionWorkspaceId === undefined ? 2 : 3,
|
|
375
|
+
recordType: draft.executionWorkspaceId === undefined ? RECORD_TYPE : EXECUTION_RECORD_TYPE,
|
|
376
|
+
recordRevision: (current?.recordRevision ?? 0) + 1,
|
|
377
|
+
profileId: profile(draft.profileId),
|
|
378
|
+
userId: draft.userId,
|
|
379
|
+
workspaceId: draft.workspaceId,
|
|
380
|
+
bindingId: draft.bindingId,
|
|
381
|
+
projectId: draft.projectId,
|
|
382
|
+
...(draft.executionWorkspaceId === undefined ? {} : { executionWorkspaceId: draft.executionWorkspaceId }),
|
|
383
|
+
localInstanceId: draft.localInstanceId,
|
|
384
|
+
machineId: draft.machineId,
|
|
385
|
+
policyDigest: draft.policyDigest,
|
|
386
|
+
generation: draft.generation,
|
|
387
|
+
canonicalLocalRoot: root.path,
|
|
388
|
+
rootIdentity: root.identity,
|
|
389
|
+
remoteRoot: draft.remoteRoot,
|
|
390
|
+
bindingCreatedAt: draft.bindingCreatedAt,
|
|
391
|
+
bindingUpdatedAt: draft.bindingUpdatedAt,
|
|
392
|
+
recordCreatedAt: current?.recordCreatedAt ?? now.toISOString(),
|
|
393
|
+
recordUpdatedAt: now.toISOString(),
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function atomicCommitRecord(marker, previous, record) {
|
|
397
|
+
const temporaryPath = join(marker.metadataDirectory, `.workspace.json.${process.pid}.${randomUUID()}.tmp`);
|
|
398
|
+
const bytes = Buffer.from(JSON.stringify(record), "utf8");
|
|
399
|
+
if (bytes.byteLength > MAXIMUM_RECORD_BYTES)
|
|
400
|
+
throw corruptRecord("record_too_large");
|
|
401
|
+
let handle;
|
|
402
|
+
try {
|
|
403
|
+
handle = await open(temporaryPath, fileConstants.O_CREAT | fileConstants.O_EXCL | fileConstants.O_WRONLY | noFollowFlag(), 0o600);
|
|
404
|
+
await handle.writeFile(bytes);
|
|
405
|
+
await handle.sync();
|
|
406
|
+
await assertSecureHandle(handle, temporaryPath, false);
|
|
407
|
+
await handle.close();
|
|
408
|
+
handle = undefined;
|
|
409
|
+
await assertMarkerAuthority(marker);
|
|
410
|
+
const observed = await readOptionalBindingRecord(marker);
|
|
411
|
+
if ((previous === undefined && observed !== undefined) ||
|
|
412
|
+
(previous !== undefined && observed?.integrityDigest !== previous.integrityDigest)) {
|
|
413
|
+
throw staleBinding("record_changed_before_commit");
|
|
414
|
+
}
|
|
415
|
+
await rename(temporaryPath, marker.recordPath);
|
|
416
|
+
await chmod(marker.recordPath, 0o600);
|
|
417
|
+
await syncDirectory(marker.metadataDirectory);
|
|
418
|
+
const committed = await readBindingRecord(marker);
|
|
419
|
+
if (committed.integrityDigest !== record.integrityDigest) {
|
|
420
|
+
throw corruptRecord("commit_verification_failed");
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
if (handle !== undefined)
|
|
425
|
+
await handle.close().catch(() => undefined);
|
|
426
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async function prepareMetadataDirectory(root) {
|
|
431
|
+
await assertCanonicalWorkspaceRootUnchanged(root);
|
|
432
|
+
const path = join(root.path, METADATA_DIRECTORY);
|
|
433
|
+
try {
|
|
434
|
+
await mkdir(path, { mode: 0o700 });
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
if (error.code !== "EEXIST")
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
await assertOwnedPhysicalDirectory(path);
|
|
441
|
+
await chmod(path, 0o700);
|
|
442
|
+
await assertPrivateDirectory(path);
|
|
443
|
+
await assertCanonicalWorkspaceRootUnchanged(root);
|
|
444
|
+
return path;
|
|
445
|
+
}
|
|
446
|
+
async function cleanInterruptedTemporaryRecords(directory) {
|
|
447
|
+
for (const name of await readdir(directory)) {
|
|
448
|
+
if (!TEMPORARY_RECORD.test(name))
|
|
449
|
+
continue;
|
|
450
|
+
const path = join(directory, name);
|
|
451
|
+
await assertPrivateRegularFile(path);
|
|
452
|
+
await unlink(path);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function assertNoInterruptedTemporaryRecords(directory) {
|
|
456
|
+
if ((await readdir(directory)).some((name) => TEMPORARY_RECORD.test(name))) {
|
|
457
|
+
throw workspaceError("binding_recovery_required", "The local workspace binding has an interrupted atomic update.", "conflict", "interrupted_commit");
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async function assertMarkerAuthority(marker) {
|
|
461
|
+
await assertCanonicalWorkspaceRootUnchanged(marker.workspaceRoot);
|
|
462
|
+
await assertPrivateDirectory(marker.metadataDirectory);
|
|
463
|
+
assertPathWithinBoundary(marker.workspaceRoot.path, marker.metadataDirectory);
|
|
464
|
+
}
|
|
465
|
+
async function assertPrivateDirectory(path) {
|
|
466
|
+
const entry = await assertOwnedPhysicalDirectory(path);
|
|
467
|
+
assertPrivateOwnerAndMode(entry.uid, entry.mode, "metadata_directory_permissions");
|
|
468
|
+
}
|
|
469
|
+
async function assertOwnedPhysicalDirectory(path) {
|
|
470
|
+
const entry = await lstat(path);
|
|
471
|
+
if (!entry.isDirectory() || entry.isSymbolicLink())
|
|
472
|
+
throw unsafeStore("metadata_directory_untrusted");
|
|
473
|
+
const canonical = await realpath(path);
|
|
474
|
+
if (!sameCanonicalPath(canonical, path))
|
|
475
|
+
throw unsafeStore("metadata_directory_untrusted");
|
|
476
|
+
if (process.platform !== "win32") {
|
|
477
|
+
const currentUid = process.getuid?.();
|
|
478
|
+
if (currentUid === undefined || entry.uid !== currentUid) {
|
|
479
|
+
throw unsafeStore("metadata_directory_owner");
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return entry;
|
|
483
|
+
}
|
|
484
|
+
async function assertPrivateRegularFile(path) {
|
|
485
|
+
const entry = await lstat(path);
|
|
486
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.nlink !== 1) {
|
|
487
|
+
throw unsafeStore("record_file_untrusted");
|
|
488
|
+
}
|
|
489
|
+
if (entry.size > MAXIMUM_RECORD_BYTES)
|
|
490
|
+
throw corruptRecord("record_too_large");
|
|
491
|
+
assertPrivateOwnerAndMode(entry.uid, entry.mode, "record_file_permissions");
|
|
492
|
+
}
|
|
493
|
+
function assertPrivateOwnerAndMode(uid, mode, reason) {
|
|
494
|
+
if (process.platform === "win32")
|
|
495
|
+
return;
|
|
496
|
+
const currentUid = process.getuid?.();
|
|
497
|
+
if (currentUid === undefined || uid !== currentUid || (mode & 0o077) !== 0) {
|
|
498
|
+
throw unsafeStore(reason);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async function readSecureTextFile(path) {
|
|
502
|
+
await assertPrivateRegularFile(path);
|
|
503
|
+
const handle = await open(path, fileConstants.O_RDONLY | noFollowFlag());
|
|
504
|
+
try {
|
|
505
|
+
await assertSecureHandle(handle, path, true);
|
|
506
|
+
const bytes = await handle.readFile();
|
|
507
|
+
if (bytes.byteLength > MAXIMUM_RECORD_BYTES)
|
|
508
|
+
throw corruptRecord("record_too_large");
|
|
509
|
+
await assertSecureHandle(handle, path, true);
|
|
510
|
+
return bytes.toString("utf8");
|
|
511
|
+
}
|
|
512
|
+
finally {
|
|
513
|
+
await handle.close();
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
async function assertSecureHandle(handle, path, requirePrivate) {
|
|
517
|
+
const opened = await handle.stat();
|
|
518
|
+
const linked = await lstat(path);
|
|
519
|
+
if (!opened.isFile() || opened.nlink !== 1 ||
|
|
520
|
+
!linked.isFile() || linked.isSymbolicLink() || linked.nlink !== 1 ||
|
|
521
|
+
opened.dev !== linked.dev || opened.ino !== linked.ino) {
|
|
522
|
+
throw unsafeStore("record_identity_changed");
|
|
523
|
+
}
|
|
524
|
+
if (requirePrivate)
|
|
525
|
+
assertPrivateOwnerAndMode(linked.uid, linked.mode, "record_file_permissions");
|
|
526
|
+
}
|
|
527
|
+
async function syncDirectory(path) {
|
|
528
|
+
if (process.platform === "win32")
|
|
529
|
+
return;
|
|
530
|
+
const handle = await open(path, fileConstants.O_RDONLY);
|
|
531
|
+
try {
|
|
532
|
+
await handle.sync();
|
|
533
|
+
}
|
|
534
|
+
finally {
|
|
535
|
+
await handle.close();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
async function acquireBindingWriterLock(identity) {
|
|
539
|
+
const endpoint = await bindingLockEndpoint(identity);
|
|
540
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
541
|
+
const server = createServer((socket) => socket.destroy());
|
|
542
|
+
try {
|
|
543
|
+
await listen(server, endpoint);
|
|
544
|
+
return bindingWriterLock(server);
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
await closeUnboundServer(server);
|
|
548
|
+
if (error.code !== "EADDRINUSE")
|
|
549
|
+
throw error;
|
|
550
|
+
if (process.platform === "win32" || await unixSocketIsActive(endpoint)) {
|
|
551
|
+
throw workspaceError("workspace_busy", "Another process owns the workspace binding writer lock.", "conflict", "active_writer");
|
|
552
|
+
}
|
|
553
|
+
await quarantineStaleSocket(endpoint);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
throw workspaceError("workspace_busy", "Another process owns the workspace binding writer lock.", "conflict", "active_writer");
|
|
557
|
+
}
|
|
558
|
+
async function bindingLockEndpoint(identity) {
|
|
559
|
+
const digest = createHash("sha256")
|
|
560
|
+
.update("cuna-workspace-binding-lock-v1\0")
|
|
561
|
+
.update(JSON.stringify(identity))
|
|
562
|
+
.digest("hex");
|
|
563
|
+
if (process.platform === "win32")
|
|
564
|
+
return `\\\\.\\pipe\\cuna-workspace-binding-${digest}`;
|
|
565
|
+
const base = await realpath(tmpdir());
|
|
566
|
+
const uid = process.getuid?.();
|
|
567
|
+
if (uid === undefined)
|
|
568
|
+
throw unsafeStore("lock_identity_unavailable");
|
|
569
|
+
const directory = join(base, `.cuna-${uid}`);
|
|
570
|
+
try {
|
|
571
|
+
await mkdir(directory, { mode: 0o700 });
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
if (error.code !== "EEXIST")
|
|
575
|
+
throw error;
|
|
576
|
+
}
|
|
577
|
+
await assertOwnedPhysicalDirectory(directory);
|
|
578
|
+
await chmod(directory, 0o700);
|
|
579
|
+
await assertPrivateDirectory(directory);
|
|
580
|
+
return join(directory, `binding-${digest.slice(0, 32)}.sock`);
|
|
581
|
+
}
|
|
582
|
+
async function listen(server, endpoint) {
|
|
583
|
+
await new Promise((resolveListen, rejectListen) => {
|
|
584
|
+
const onError = (error) => {
|
|
585
|
+
server.removeListener("listening", onListening);
|
|
586
|
+
rejectListen(error);
|
|
587
|
+
};
|
|
588
|
+
const onListening = () => {
|
|
589
|
+
server.removeListener("error", onError);
|
|
590
|
+
resolveListen();
|
|
591
|
+
};
|
|
592
|
+
server.once("error", onError);
|
|
593
|
+
server.once("listening", onListening);
|
|
594
|
+
server.listen(endpoint);
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
function bindingWriterLock(server) {
|
|
598
|
+
let closed = false;
|
|
599
|
+
return Object.freeze({
|
|
600
|
+
server,
|
|
601
|
+
close: async () => {
|
|
602
|
+
if (closed)
|
|
603
|
+
return;
|
|
604
|
+
await new Promise((resolveClose, rejectClose) => {
|
|
605
|
+
server.close((error) => error === undefined ? resolveClose() : rejectClose(error));
|
|
606
|
+
});
|
|
607
|
+
// Node removes a Unix-domain socket pathname while closing the server.
|
|
608
|
+
// Never unlink after the close callback: another writer may already have
|
|
609
|
+
// rebound that pathname, and deleting it would orphan an active lock.
|
|
610
|
+
closed = true;
|
|
611
|
+
},
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
async function unixSocketIsActive(endpoint) {
|
|
615
|
+
return new Promise((resolveProbe) => {
|
|
616
|
+
const socket = createConnection(endpoint);
|
|
617
|
+
socket.once("connect", () => {
|
|
618
|
+
socket.destroy();
|
|
619
|
+
resolveProbe(true);
|
|
620
|
+
});
|
|
621
|
+
socket.once("error", (error) => {
|
|
622
|
+
socket.destroy();
|
|
623
|
+
resolveProbe(error.code !== "ECONNREFUSED" && error.code !== "ENOENT");
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
async function quarantineStaleSocket(endpoint) {
|
|
628
|
+
const stale = `${endpoint}.stale-${process.pid}-${randomUUID()}`;
|
|
629
|
+
try {
|
|
630
|
+
const entry = await lstat(endpoint);
|
|
631
|
+
if (!entry.isSocket() || entry.isSymbolicLink())
|
|
632
|
+
throw unsafeStore("lock_endpoint_untrusted");
|
|
633
|
+
await rename(endpoint, stale);
|
|
634
|
+
await unlink(stale);
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
if (error.code !== "ENOENT")
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
async function closeUnboundServer(server) {
|
|
642
|
+
if (server.listening) {
|
|
643
|
+
await new Promise((resolveClose) => server.close(() => resolveClose()));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function noFollowFlag() {
|
|
647
|
+
return typeof fileConstants.O_NOFOLLOW === "number" ? fileConstants.O_NOFOLLOW : 0;
|
|
648
|
+
}
|
|
649
|
+
function digestRecord(record) {
|
|
650
|
+
return createHash("sha256")
|
|
651
|
+
.update(record.schemaVersion === 3 ? "cuna-workspace-binding-record-v3\0" : "cuna-workspace-binding-record-v2\0")
|
|
652
|
+
.update(JSON.stringify(record))
|
|
653
|
+
.digest("hex");
|
|
654
|
+
}
|
|
655
|
+
function executionId(value) {
|
|
656
|
+
if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u.test(value))
|
|
657
|
+
throw new TypeError("execution workspace ID");
|
|
658
|
+
return value;
|
|
659
|
+
}
|
|
660
|
+
function bindingRemoteRoot(value) {
|
|
661
|
+
return value.executionWorkspaceId === undefined ? `/workspace/projects/${value.projectId}` : `/workspace/workspaces/${value.executionWorkspaceId}`;
|
|
662
|
+
}
|
|
663
|
+
function freezeRecord(record) {
|
|
664
|
+
return Object.freeze({ ...record, rootIdentity: Object.freeze({ ...record.rootIdentity }) });
|
|
665
|
+
}
|
|
666
|
+
function exactObject(value, keys) {
|
|
667
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
668
|
+
throw new TypeError("object");
|
|
669
|
+
const source = value;
|
|
670
|
+
const actual = Object.keys(source).sort();
|
|
671
|
+
const expected = [...keys].sort();
|
|
672
|
+
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
|
|
673
|
+
throw new TypeError("keys");
|
|
674
|
+
}
|
|
675
|
+
return source;
|
|
676
|
+
}
|
|
677
|
+
function exactString(value, expected) {
|
|
678
|
+
if (value !== expected)
|
|
679
|
+
throw new TypeError("string");
|
|
680
|
+
return expected;
|
|
681
|
+
}
|
|
682
|
+
function nonempty(value) {
|
|
683
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 4_096 || value.includes("\0")) {
|
|
684
|
+
throw new TypeError("string");
|
|
685
|
+
}
|
|
686
|
+
return value;
|
|
687
|
+
}
|
|
688
|
+
function profile(value) {
|
|
689
|
+
const text = nonempty(value);
|
|
690
|
+
if (Buffer.byteLength(text, "utf8") > 256 || PROFILE_CONTROL.test(text) || text !== text.normalize("NFC")) {
|
|
691
|
+
throw new TypeError("profile");
|
|
692
|
+
}
|
|
693
|
+
return text;
|
|
694
|
+
}
|
|
695
|
+
function publicId(value, label) {
|
|
696
|
+
if (typeof value !== "string")
|
|
697
|
+
throw new TypeError(label);
|
|
698
|
+
return assertPublicId(value, label);
|
|
699
|
+
}
|
|
700
|
+
function digest(value) {
|
|
701
|
+
if (typeof value !== "string" || !DIGEST.test(value))
|
|
702
|
+
throw new TypeError("digest");
|
|
703
|
+
return value;
|
|
704
|
+
}
|
|
705
|
+
function decimal(value) {
|
|
706
|
+
if (typeof value !== "string" || !/^(?:0|[1-9][0-9]*)$/u.test(value))
|
|
707
|
+
throw new TypeError("decimal");
|
|
708
|
+
return value;
|
|
709
|
+
}
|
|
710
|
+
function positiveDecimal(value) {
|
|
711
|
+
const text = decimal(value);
|
|
712
|
+
if (text === "0")
|
|
713
|
+
throw new TypeError("positive decimal");
|
|
714
|
+
return text;
|
|
715
|
+
}
|
|
716
|
+
function integer(value, minimum) {
|
|
717
|
+
if (!Number.isSafeInteger(value) || value < minimum)
|
|
718
|
+
throw new TypeError("integer");
|
|
719
|
+
return value;
|
|
720
|
+
}
|
|
721
|
+
function exactInteger(value, minimum, maximum) {
|
|
722
|
+
const result = integer(value, minimum);
|
|
723
|
+
if (result > maximum)
|
|
724
|
+
throw new TypeError("integer");
|
|
725
|
+
return result;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* An instant in any encoding a conforming service may emit.
|
|
729
|
+
*
|
|
730
|
+
* This used to require `new Date(text).toISOString() === text`, which is not a
|
|
731
|
+
* validity check — it is an equality against ONE encoding, the one JavaScript
|
|
732
|
+
* happens to render. `bindingCreatedAt` and `bindingUpdatedAt` are the
|
|
733
|
+
* service's, forwarded out of Postgres verbatim, so they arrive with up to six
|
|
734
|
+
* fractional digits and an explicit `+00:00`. Measured against production
|
|
735
|
+
* 2026-08-18:
|
|
736
|
+
*
|
|
737
|
+
* bindingCreatedAt 2026-08-18T19:55:47.437071+00:00 six digits
|
|
738
|
+
* bindingUpdatedAt 2026-08-18T20:01:57.89766+00:00 five, trailing zero trimmed
|
|
739
|
+
*
|
|
740
|
+
* The check could therefore never pass on a server-minted value, and
|
|
741
|
+
* `cuna claude` failed for every user, every time, with
|
|
742
|
+
* `binding_corrupt / draft_invalid` — a message that accuses the LOCAL record
|
|
743
|
+
* of corruption when the local record was a faithful copy of what the service
|
|
744
|
+
* sent.
|
|
745
|
+
*
|
|
746
|
+
* Still rejected: anything unparseable, and anything with no explicit offset,
|
|
747
|
+
* which `Date.parse` would silently read in the host's local zone.
|
|
748
|
+
*/
|
|
749
|
+
function timestamp(value) {
|
|
750
|
+
const text = nonempty(value);
|
|
751
|
+
if (instantOrNull(text) === null)
|
|
752
|
+
throw new TypeError("timestamp");
|
|
753
|
+
return text;
|
|
754
|
+
}
|
|
755
|
+
function absolutePath(value) {
|
|
756
|
+
const text = nonempty(value);
|
|
757
|
+
if (!isAbsolute(text))
|
|
758
|
+
throw new TypeError("path");
|
|
759
|
+
return text;
|
|
760
|
+
}
|
|
761
|
+
function oneOf(value, choices) {
|
|
762
|
+
if (typeof value !== "string" || !choices.includes(value))
|
|
763
|
+
throw new TypeError("enum");
|
|
764
|
+
return value;
|
|
765
|
+
}
|
|
766
|
+
function isWorkspaceRecordError(error) {
|
|
767
|
+
return error instanceof Error && "code" in error &&
|
|
768
|
+
typeof error.code === "string" &&
|
|
769
|
+
error.code.startsWith("cuna.workspace.");
|
|
770
|
+
}
|
|
771
|
+
function corruptRecord(reason) {
|
|
772
|
+
return workspaceError("binding_corrupt", "The local workspace binding record is malformed or corrupt.", "integrity", reason);
|
|
773
|
+
}
|
|
774
|
+
function ownerMismatch() {
|
|
775
|
+
return workspaceError("identity_unproven", "Workspace binding identity could not be proven.", "policy", "binding_owner_mismatch");
|
|
776
|
+
}
|
|
777
|
+
function staleBinding(reason) {
|
|
778
|
+
return workspaceError("binding_stale", "The workspace binding changed before the local update could commit.", "conflict", reason);
|
|
779
|
+
}
|
|
780
|
+
function unsafeStore(reason) {
|
|
781
|
+
return workspaceError("binding_store_unsafe", "The local workspace binding store is unsafe.", "policy", reason);
|
|
782
|
+
}
|
|
783
|
+
//# sourceMappingURL=binding-store.js.map
|