@intentic/sandbox-contract 1.344.0 → 1.346.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/README.md +27 -9
- package/dist/contracts/accounts.contract.d.ts +24 -80
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +247 -8
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +13 -2
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +1570 -33
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +47 -4
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/device.contract.d.ts +244 -1
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +5 -1
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +2 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +1 -0
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts +0 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.d.ts +11 -0
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +10 -1
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +149 -123
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +169 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +35 -0
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +37 -0
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +235 -31
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +24 -80
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +11 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +11 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +60 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +44 -38
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/agent-transcript.d.ts +727 -0
- package/dist/events/agent-transcript.d.ts.map +1 -0
- package/dist/events/agent-transcript.js +34 -0
- package/dist/events/agent-transcript.js.map +1 -0
- package/dist/events/agent-words.d.ts +5 -0
- package/dist/events/agent-words.d.ts.map +1 -1
- package/dist/events/agent-words.js +9 -0
- package/dist/events/agent-words.js.map +1 -1
- package/dist/events/failure-rows.d.ts +14 -0
- package/dist/events/failure-rows.d.ts.map +1 -0
- package/dist/events/failure-rows.js +109 -0
- package/dist/events/failure-rows.js.map +1 -0
- package/dist/events/requests.d.ts +143 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/requests.js +35 -1
- package/dist/events/requests.js.map +1 -1
- package/dist/events/sandbox-notice.d.ts +23 -0
- package/dist/events/sandbox-notice.d.ts.map +1 -1
- package/dist/events/sandbox-notice.js +2 -0
- package/dist/events/sandbox-notice.js.map +1 -1
- package/dist/events/system-events.d.ts +156 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/system-events.js +7 -1
- package/dist/events/system-events.js.map +1 -1
- package/dist/events/transcript.d.ts +20 -720
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +17 -19
- package/dist/events/transcript.js.map +1 -1
- package/dist/ids/conversation-ids.d.ts +2 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -1
- package/dist/ids/conversation-ids.js +2 -0
- package/dist/ids/conversation-ids.js.map +1 -1
- package/dist/ids/row-ids.d.ts +3 -0
- package/dist/ids/row-ids.d.ts.map +1 -0
- package/dist/ids/row-ids.js +11 -0
- package/dist/ids/row-ids.js.map +1 -0
- package/dist/index.d.ts +2296 -199
- package/dist/index.d.ts.map +1 -1
- package/dist/models/agent-lanes.d.ts.map +1 -1
- package/dist/models/agent-lanes.js +6 -7
- package/dist/models/agent-lanes.js.map +1 -1
- package/dist/models/agent-standing.d.ts +6 -19
- package/dist/models/agent-standing.d.ts.map +1 -1
- package/dist/models/agent-standing.js +14 -38
- package/dist/models/agent-standing.js.map +1 -1
- package/dist/models/model-pins.d.ts +3 -0
- package/dist/models/model-pins.d.ts.map +1 -1
- package/dist/models/model-pins.js +2 -0
- package/dist/models/model-pins.js.map +1 -1
- package/dist/models/plan-pools.d.ts +26 -4
- package/dist/models/plan-pools.d.ts.map +1 -1
- package/dist/models/plan-pools.js +159 -40
- package/dist/models/plan-pools.js.map +1 -1
- package/dist/netd/generated/wire.d.ts +5 -0
- package/dist/netd/generated/wire.d.ts.map +1 -1
- package/dist/policy/command-classes.d.ts +1 -1
- package/dist/policy/command-classes.d.ts.map +1 -1
- package/dist/policy/command-classes.js +2 -2
- package/dist/policy/command-classes.js.map +1 -1
- package/dist/policy/keyring-origins.d.ts +27 -0
- package/dist/policy/keyring-origins.d.ts.map +1 -0
- package/dist/policy/keyring-origins.js +213 -0
- package/dist/policy/keyring-origins.js.map +1 -0
- package/dist/policy/keyring-seal.d.ts +9 -0
- package/dist/policy/keyring-seal.d.ts.map +1 -1
- package/dist/policy/keyring-seal.js +18 -6
- package/dist/policy/keyring-seal.js.map +1 -1
- package/dist/policy/safety-policy.d.ts +1 -1
- package/dist/policy/safety-policy.d.ts.map +1 -1
- package/dist/policy/safety-policy.js +1 -1
- package/dist/policy/safety-policy.js.map +1 -1
- package/dist/policy/turned-away.d.ts +1 -0
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +10 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/doors/host-protocol.d.ts +1 -0
- package/dist/protocol/doors/host-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/host-protocol.js +1 -0
- package/dist/protocol/doors/host-protocol.js.map +1 -1
- package/dist/protocol/doors/runner-protocol.d.ts +1 -0
- package/dist/protocol/doors/runner-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/runner-protocol.js +1 -0
- package/dist/protocol/doors/runner-protocol.js.map +1 -1
- package/dist/protocol/doors/webext-links.d.ts +1 -0
- package/dist/protocol/doors/webext-links.d.ts.map +1 -1
- package/dist/protocol/doors/webext-links.js +1 -0
- package/dist/protocol/doors/webext-links.js.map +1 -1
- package/dist/protocol/peer-dial.d.ts +2 -0
- package/dist/protocol/peer-dial.d.ts.map +1 -1
- package/dist/protocol/peer-dial.js +62 -29
- package/dist/protocol/peer-dial.js.map +1 -1
- package/dist/protocol/raw/raw-json-routes.d.ts +179 -1
- package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-json-routes.js +5 -0
- package/dist/protocol/raw/raw-json-routes.js.map +1 -1
- package/dist/protocol/raw/raw-routes.d.ts +35 -0
- package/dist/protocol/raw/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-routes.js +9 -0
- package/dist/protocol/raw/raw-routes.js.map +1 -1
- package/dist/schemas/agent-next.d.ts +21 -0
- package/dist/schemas/agent-next.d.ts.map +1 -0
- package/dist/schemas/agent-next.js +21 -0
- package/dist/schemas/agent-next.js.map +1 -0
- package/dist/schemas/agent-place.d.ts +10 -0
- package/dist/schemas/agent-place.d.ts.map +1 -0
- package/dist/schemas/agent-place.js +15 -0
- package/dist/schemas/agent-place.js.map +1 -0
- package/dist/schemas/agent-search.d.ts +45 -0
- package/dist/schemas/agent-search.d.ts.map +1 -0
- package/dist/schemas/agent-search.js +28 -0
- package/dist/schemas/agent-search.js.map +1 -0
- package/dist/schemas/agent.d.ts +120 -78
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +40 -49
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +54 -0
- package/dist/schemas/agents-list.d.ts.map +1 -1
- package/dist/schemas/agents.d.ts +165 -59
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +25 -50
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/attach.d.ts +8 -0
- package/dist/schemas/attach.d.ts.map +1 -0
- package/dist/schemas/attach.js +14 -0
- package/dist/schemas/attach.js.map +1 -0
- package/dist/schemas/command-admission.d.ts +71 -0
- package/dist/schemas/command-admission.d.ts.map +1 -0
- package/dist/schemas/command-admission.js +27 -0
- package/dist/schemas/command-admission.js.map +1 -0
- package/dist/schemas/compose-overlay.d.ts +9 -0
- package/dist/schemas/compose-overlay.d.ts.map +1 -0
- package/dist/schemas/compose-overlay.js +11 -0
- package/dist/schemas/compose-overlay.js.map +1 -0
- package/dist/schemas/composer-drafts.d.ts +169 -0
- package/dist/schemas/composer-drafts.d.ts.map +1 -0
- package/dist/schemas/composer-drafts.js +60 -0
- package/dist/schemas/composer-drafts.js.map +1 -0
- package/dist/schemas/conversation-links.d.ts +44 -0
- package/dist/schemas/conversation-links.d.ts.map +1 -0
- package/dist/schemas/conversation-links.js +35 -0
- package/dist/schemas/conversation-links.js.map +1 -0
- package/dist/schemas/data-protection.d.ts +1 -1
- package/dist/schemas/data-protection.d.ts.map +1 -1
- package/dist/schemas/device-commands.d.ts +63 -0
- package/dist/schemas/device-commands.d.ts.map +1 -0
- package/dist/schemas/device-commands.js +42 -0
- package/dist/schemas/device-commands.js.map +1 -0
- package/dist/schemas/device-folder.d.ts +11 -0
- package/dist/schemas/device-folder.d.ts.map +1 -1
- package/dist/schemas/device-folder.js +1 -0
- package/dist/schemas/device-folder.js.map +1 -1
- package/dist/schemas/devices.d.ts +18 -68
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +8 -45
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/hosts.d.ts +29 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +23 -0
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/keyring-native.d.ts +137 -0
- package/dist/schemas/keyring-native.d.ts.map +1 -0
- package/dist/schemas/keyring-native.js +69 -0
- package/dist/schemas/keyring-native.js.map +1 -0
- package/dist/schemas/keyring.d.ts +413 -0
- package/dist/schemas/keyring.d.ts.map +1 -1
- package/dist/schemas/keyring.js +139 -4
- package/dist/schemas/keyring.js.map +1 -1
- package/dist/schemas/phone-passwords.d.ts +186 -0
- package/dist/schemas/phone-passwords.d.ts.map +1 -0
- package/dist/schemas/phone-passwords.js +25 -0
- package/dist/schemas/phone-passwords.js.map +1 -0
- package/dist/schemas/privacy-egress.d.ts +41 -0
- package/dist/schemas/privacy-egress.d.ts.map +1 -0
- package/dist/schemas/privacy-egress.js +30 -0
- package/dist/schemas/privacy-egress.js.map +1 -0
- package/dist/schemas/privacy.d.ts +1 -0
- package/dist/schemas/privacy.d.ts.map +1 -1
- package/dist/schemas/privacy.js +1 -0
- package/dist/schemas/privacy.js.map +1 -1
- package/dist/schemas/providers/plan-limits.d.ts +76 -130
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +36 -23
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/providers/provider-oauth.d.ts +24 -82
- package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/providers/provider-oauth.js +1 -6
- package/dist/schemas/providers/provider-oauth.js.map +1 -1
- package/dist/schemas/providers/refusals.d.ts +64 -0
- package/dist/schemas/providers/refusals.d.ts.map +1 -0
- package/dist/schemas/providers/refusals.js +33 -0
- package/dist/schemas/providers/refusals.js.map +1 -0
- package/dist/schemas/providers/usage.d.ts +1 -0
- package/dist/schemas/providers/usage.d.ts.map +1 -1
- package/dist/schemas/providers/usage.js +1 -0
- package/dist/schemas/providers/usage.js.map +1 -1
- package/dist/schemas/push.d.ts +13 -0
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js +11 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/sandbox-passwords.d.ts +288 -0
- package/dist/schemas/sandbox-passwords.d.ts.map +1 -0
- package/dist/schemas/sandbox-passwords.js +66 -0
- package/dist/schemas/sandbox-passwords.js.map +1 -0
- package/dist/schemas/secrets.d.ts +2 -0
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +4 -0
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/sessions.js +1 -1
- package/dist/schemas/sessions.js.map +1 -1
- package/dist/schemas/settings-savings.d.ts +709 -0
- package/dist/schemas/settings-savings.d.ts.map +1 -0
- package/dist/schemas/settings-savings.js +53 -0
- package/dist/schemas/settings-savings.js.map +1 -0
- package/dist/schemas/settings.d.ts +7 -671
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +5 -50
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/system.d.ts +16 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +11 -0
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/terminal.d.ts +5 -0
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js +4 -0
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/work-assurance.d.ts +24 -0
- package/dist/schemas/work-assurance.d.ts.map +1 -0
- package/dist/schemas/work-assurance.js +23 -0
- package/dist/schemas/work-assurance.js.map +1 -0
- package/dist/schemas/workspace/workspace-tree.d.ts +23 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +20 -0
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/auth-state.d.ts +4 -0
- package/dist/state/auth-state.d.ts.map +1 -0
- package/dist/state/auth-state.js +37 -0
- package/dist/state/auth-state.js.map +1 -0
- package/dist/state/definition.d.ts +12 -0
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/runtime-state.d.ts +3 -0
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js +1 -0
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/state/sandbox-build.d.ts +20 -0
- package/dist/state/sandbox-build.d.ts.map +1 -0
- package/dist/state/sandbox-build.js +43 -0
- package/dist/state/sandbox-build.js.map +1 -0
- package/dist/state/ways-back.d.ts +4 -0
- package/dist/state/ways-back.d.ts.map +1 -0
- package/dist/state/ways-back.js +8 -0
- package/dist/state/ways-back.js.map +1 -0
- package/dist/text/land-rows.d.ts +14 -0
- package/dist/text/land-rows.d.ts.map +1 -0
- package/dist/text/land-rows.js +86 -0
- package/dist/text/land-rows.js.map +1 -0
- package/dist/text/transcript-fold.d.ts +4 -2
- package/dist/text/transcript-fold.d.ts.map +1 -1
- package/dist/text/transcript-fold.js +21 -187
- package/dist/text/transcript-fold.js.map +1 -1
- package/dist/webext/index.d.ts +1 -0
- package/dist/webext/index.d.ts.map +1 -1
- package/dist/webext/index.js +1 -0
- package/dist/webext/index.js.map +1 -1
- package/package.json +7 -6
- package/src/contracts/agent.contract.ts +13 -1
- package/src/contracts/agents.contract.ts +53 -28
- package/src/contracts/device.contract.ts +16 -0
- package/src/contracts/endpoints.contract.ts +3 -0
- package/src/contracts/push.contract.ts +23 -1
- package/src/contracts/secrets.contract.ts +39 -0
- package/src/contracts/workspace.contract.ts +16 -0
- package/src/events/agent-events.ts +99 -79
- package/src/events/agent-transcript.ts +48 -0
- package/src/events/agent-words.ts +13 -0
- package/src/events/failure-rows.ts +148 -0
- package/src/events/requests.ts +41 -3
- package/src/events/sandbox-notice.ts +14 -2
- package/src/events/system-events.ts +14 -4
- package/src/events/transcript.ts +30 -28
- package/src/ids/conversation-ids.ts +7 -0
- package/src/ids/project-dir.test.ts +2 -2
- package/src/ids/project-dir.ts +4 -4
- package/src/ids/row-ids.ts +20 -0
- package/src/models/agent-lanes.ts +16 -24
- package/src/models/agent-runtimes.ts +2 -2
- package/src/models/agent-standing.ts +38 -95
- package/src/models/model-pins.test.ts +31 -1
- package/src/models/model-pins.ts +17 -0
- package/src/models/plan-pools.test.ts +274 -31
- package/src/models/plan-pools.ts +294 -79
- package/src/netd/generated/netd-wire.json +25 -0
- package/src/netd/generated/wire.ts +1 -1
- package/src/policy/command-classes.ts +2 -2
- package/src/policy/keyring-origins.test.ts +132 -0
- package/src/policy/keyring-origins.ts +287 -0
- package/src/policy/keyring-seal.test.ts +37 -2
- package/src/policy/keyring-seal.ts +33 -7
- package/src/policy/safety-policy.ts +1 -1
- package/src/policy/tests/safety-policy.test.ts +1 -1
- package/src/policy/turned-away.ts +15 -0
- package/src/protocol/doors/host-protocol.ts +3 -0
- package/src/protocol/doors/runner-protocol.ts +4 -1
- package/src/protocol/doors/webext-links.ts +3 -0
- package/src/protocol/peer-dial.test.ts +90 -4
- package/src/protocol/peer-dial.ts +83 -39
- package/src/protocol/raw/raw-json-routes.ts +13 -0
- package/src/protocol/raw/raw-routes.ts +13 -1
- package/src/schemas/agent-next.ts +34 -0
- package/src/schemas/agent-place.ts +22 -0
- package/src/schemas/agent-search.ts +51 -0
- package/src/schemas/agent.ts +63 -90
- package/src/schemas/agents.ts +55 -99
- package/src/schemas/attach.ts +23 -0
- package/src/schemas/command-admission.ts +57 -0
- package/src/schemas/compose-overlay.test.ts +35 -0
- package/src/schemas/compose-overlay.ts +19 -0
- package/src/schemas/composer-drafts.ts +86 -0
- package/src/schemas/conversation-links.ts +62 -0
- package/src/schemas/data-protection.ts +1 -1
- package/src/schemas/device-commands.ts +89 -0
- package/src/schemas/device-folder.ts +9 -0
- package/src/schemas/devices.ts +28 -110
- package/src/schemas/environment.ts +8 -9
- package/src/schemas/hosts.ts +60 -0
- package/src/schemas/keyring-native.test.ts +13 -0
- package/src/schemas/keyring-native.ts +101 -0
- package/src/schemas/keyring.ts +202 -4
- package/src/schemas/machine-presence.test.ts +33 -0
- package/src/schemas/phone-passwords.ts +51 -0
- package/src/schemas/privacy-egress.test.ts +83 -0
- package/src/schemas/privacy-egress.ts +86 -0
- package/src/schemas/privacy.ts +4 -0
- package/src/schemas/project-delivery.ts +1 -1
- package/src/schemas/providers/plan-limits.test.ts +16 -0
- package/src/schemas/providers/plan-limits.ts +55 -49
- package/src/schemas/providers/provider-oauth.ts +1 -13
- package/src/schemas/providers/refusals.ts +62 -0
- package/src/schemas/providers/usage.ts +2 -0
- package/src/schemas/push.ts +19 -3
- package/src/schemas/sandbox-passwords.ts +88 -0
- package/src/schemas/secrets.ts +4 -0
- package/src/schemas/sessions.ts +1 -1
- package/src/schemas/settings-savings.ts +125 -0
- package/src/schemas/settings.ts +10 -116
- package/src/schemas/system.ts +15 -0
- package/src/schemas/terminal.ts +8 -0
- package/src/schemas/work-assurance.ts +36 -0
- package/src/schemas/workspace/workspace-tree.ts +32 -0
- package/src/state/auth-state.ts +89 -0
- package/src/state/runtime-state.ts +10 -4
- package/src/state/sandbox-build.test.ts +95 -0
- package/src/state/sandbox-build.ts +96 -0
- package/src/state/ways-back.test.ts +36 -0
- package/src/state/ways-back.ts +19 -0
- package/src/state/workspace-state.ts +1 -1
- package/src/text/land-rows.ts +111 -0
- package/src/text/transcript-fold.test.ts +105 -9
- package/src/text/transcript-fold.ts +30 -232
- package/src/webext/index.ts +2 -0
- package/dist/events/undelivered.d.ts +0 -6
- package/dist/events/undelivered.d.ts.map +0 -1
- package/dist/events/undelivered.js +0 -9
- package/dist/events/undelivered.js.map +0 -1
- package/dist/state/history-state.d.ts +0 -3
- package/dist/state/history-state.d.ts.map +0 -1
- package/dist/state/history-state.js +0 -137
- package/dist/state/history-state.js.map +0 -1
- package/src/events/undelivered.ts +0 -15
- package/src/state/history-state.ts +0 -270
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// WHAT A TARGET IMAGE COMPOSES FOR A SANDBOX, as the host reads it: the one line the image's own composer prints
|
|
4
|
+
// (`node /opt/sandbox/dist/environment/compose-overlay.js --base <image>`, _sandbox/sandbox/src/environment/compose-overlay.ts) over read-only
|
|
5
|
+
// mounts of the sandbox's volumes before a swap onto it, which `ic` builds instead of the overlay the running daemon
|
|
6
|
+
// composed (_sandbox/ic/src/sandbox/composition.rs). golden/compose-overlay.json holds examples the Rust test reads.
|
|
7
|
+
|
|
8
|
+
// The one format `ic` reads; any other, or none, sends it back to the running daemon's overlay.
|
|
9
|
+
export const COMPOSE_OVERLAY_FORMAT = 1;
|
|
10
|
+
|
|
11
|
+
export const ComposedOverlayLineSchema = z.object({
|
|
12
|
+
compose: z.literal(COMPOSE_OVERLAY_FORMAT).describe("The format of this line. A reader takes no other."),
|
|
13
|
+
overlay: z
|
|
14
|
+
.string()
|
|
15
|
+
.nullable()
|
|
16
|
+
.describe("The Dockerfile the image's daemon composes on its first boot, byte for byte; null when the sandbox wants no overlay on it."),
|
|
17
|
+
hash: z.string().optional().describe("sha256 of `overlay`, what the new container is stamped with (SANDBOX_ENVIRONMENT_HASH). Absent with no overlay."),
|
|
18
|
+
});
|
|
19
|
+
export type ComposedOverlayLine = z.infer<typeof ComposedOverlayLineSchema>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ATTACHMENT_LIMIT, ConversationIdSchema, ForkOfSchema, FreshOfSchema, QueuedServingSchema } from "./agent.js";
|
|
3
|
+
|
|
4
|
+
// A PERSON'S UNSENT WORDS FOR ONE CONVERSATION, held by the sandbox. Until 2026-10-20 a composer's words lived only in the
|
|
5
|
+
// browser: in each window's tab snapshot, moved into a per-browser "closed drafts" set when the tab closed and back out
|
|
6
|
+
// when it reopened, and broadcast between windows as previews. Every move was a chance to lose or duplicate them: a
|
|
7
|
+
// popped-out chat and the board each held a copy for a round trip, two windows wrote the same chat's words over each
|
|
8
|
+
// other, and another device never saw them at all. Now the sandbox holds the one record, per person and conversation, and
|
|
9
|
+
// a browser keeps only an optimistic copy of it. A draft never goes by itself (AgentSummary.next never names one), and it
|
|
10
|
+
// is not egress: no model reads it until the person sends it, when it becomes the message the privacy shield judges.
|
|
11
|
+
|
|
12
|
+
// The words as the composer holds them: what the message will say, its files, and who it will go to when it opens a
|
|
13
|
+
// conversation (the pick a draft for a conversation the sandbox has never seen has nowhere else to live).
|
|
14
|
+
const draftWords = {
|
|
15
|
+
text: z.string().max(200_000).describe("The words, exactly as typed."),
|
|
16
|
+
attachments: z
|
|
17
|
+
.array(z.string().min(1))
|
|
18
|
+
.max(ATTACHMENT_LIMIT)
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Files staged with it, as workspace paths already uploaded."),
|
|
21
|
+
serves: QueuedServingSchema.optional().describe(
|
|
22
|
+
"Who the message is to go to: the provider, loop, model, effort and account picked in the composer. Absent when nothing was picked.",
|
|
23
|
+
),
|
|
24
|
+
forkOf: ForkOfSchema.optional().describe("Where the conversation this draft opens is cut from, when it is a fork no turn has started yet."),
|
|
25
|
+
freshOf: FreshOfSchema.optional().describe("The work a fresh session this draft opens starts from, when no turn has started it yet."),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const ComposerDraftSchema = z.object({
|
|
29
|
+
conversationId: ConversationIdSchema.describe("The conversation the words are for. It may not exist yet: a new chat's words are a draft before its first turn."),
|
|
30
|
+
...draftWords,
|
|
31
|
+
since: z.number().describe("When the composer first held these words unsent, in milliseconds."),
|
|
32
|
+
revision: z
|
|
33
|
+
.number()
|
|
34
|
+
.int()
|
|
35
|
+
.positive()
|
|
36
|
+
.describe("Moves with every write of any of your drafts. A write or a clear naming an older one is answered with the newer draft instead."),
|
|
37
|
+
});
|
|
38
|
+
export type ComposerDraft = z.infer<typeof ComposerDraftSchema>;
|
|
39
|
+
|
|
40
|
+
export const ComposerDraftsSchema = z.object({
|
|
41
|
+
drafts: z.array(ComposerDraftSchema).describe("Every draft you hold in this sandbox, newest first. Only your own: another member's unsent words are theirs."),
|
|
42
|
+
revision: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.nonnegative()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
"The newest revision handed out when this list was read. A draft you hold at a revision past it was written after the read, so its absence here says nothing about it.",
|
|
49
|
+
),
|
|
50
|
+
});
|
|
51
|
+
export type ComposerDrafts = z.infer<typeof ComposerDraftsSchema>;
|
|
52
|
+
|
|
53
|
+
export const DraftWriteSchema = z.object({
|
|
54
|
+
id: ConversationIdSchema.describe("The conversation the words are for."),
|
|
55
|
+
...draftWords,
|
|
56
|
+
since: z.number().optional().describe("When the words were first held unsent. Leave it out to keep the draft's own, or to start it now."),
|
|
57
|
+
base: z
|
|
58
|
+
.number()
|
|
59
|
+
.int()
|
|
60
|
+
.positive()
|
|
61
|
+
.optional()
|
|
62
|
+
.describe(
|
|
63
|
+
"The draft's revision these words were edited from. When the draft has been written since (another window, another device), nothing is written and the newer draft comes back with `conflict`, so no one's words are overwritten unseen. Leave it out to write a draft you have never read.",
|
|
64
|
+
),
|
|
65
|
+
});
|
|
66
|
+
export type DraftWrite = z.infer<typeof DraftWriteSchema>;
|
|
67
|
+
|
|
68
|
+
export const DraftWrittenSchema = z.object({
|
|
69
|
+
draft: ComposerDraftSchema.optional().describe("The draft as it now stands. Absent when there is none: it was cleared, or sent, before this write arrived."),
|
|
70
|
+
conflict: z
|
|
71
|
+
.literal(true)
|
|
72
|
+
.optional()
|
|
73
|
+
.describe("Nothing was written: the draft had moved past `base`. Merge your words into this one and write again from its revision."),
|
|
74
|
+
});
|
|
75
|
+
export type DraftWritten = z.infer<typeof DraftWrittenSchema>;
|
|
76
|
+
|
|
77
|
+
export const DraftClearSchema = z.object({
|
|
78
|
+
id: ConversationIdSchema.describe("The conversation whose draft to clear."),
|
|
79
|
+
revision: z
|
|
80
|
+
.number()
|
|
81
|
+
.int()
|
|
82
|
+
.positive()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe("Clear it only while it is still this revision, so words written since in another window survive. Leave it out to clear whatever is there."),
|
|
85
|
+
});
|
|
86
|
+
export type DraftClear = z.infer<typeof DraftClearSchema>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CONVERSATION_ID } from "../ids/conversation-ids.js";
|
|
3
|
+
|
|
4
|
+
// HOW ONE CONVERSATION RELATES TO ANOTHER at its birth, latched on its registry entry and carried on its card: the
|
|
5
|
+
// conversation a fork was cut from, and the work a fresh session was opened on. Re-exported by agent.ts, whose turn
|
|
6
|
+
// names them on a conversation's first turn.
|
|
7
|
+
|
|
8
|
+
// agent.ts's ConversationIdSchema, spelled here rather than imported, since agent.ts re-exports this module.
|
|
9
|
+
const ConversationIdSchema = z.string().regex(CONVERSATION_ID);
|
|
10
|
+
|
|
11
|
+
// Where a conversation was cut from, the durable half of a fork, carried on the registry entry. `index` is the message
|
|
12
|
+
// the cut sat above in the source, so its transcript can put the mark back.
|
|
13
|
+
export const ForkedFromSchema = z.object({
|
|
14
|
+
conversationId: ConversationIdSchema,
|
|
15
|
+
index: z.number().int().nonnegative(),
|
|
16
|
+
// Which files this fork opened on; kept so the fork can still say it later, not only right after the click.
|
|
17
|
+
files: z.enum(["then", "now"]),
|
|
18
|
+
});
|
|
19
|
+
export type ForkedFrom = z.infer<typeof ForkedFromSchema>;
|
|
20
|
+
// A FRESH SESSION on another conversation's work: a code review, a test pass, or a person's own ask, started from that
|
|
21
|
+
// conversation's work as it stands now and with none of its messages. A harness's own reviewer runs this way (Claude
|
|
22
|
+
// Code's /code-review in a forked subagent, Codex's /review in a thread of its own) so it judges the diff rather than
|
|
23
|
+
// the reasoning that produced it. Its first turn names the origin; the daemon then treats it as the origin's child: cut
|
|
24
|
+
// from its current work, its edits going back into it, folded under its card. It is still a person's chat, never woken
|
|
25
|
+
// for nor waking its origin: findings reach the origin only when a person sends them.
|
|
26
|
+
export const FRESH_KINDS = ["review", "test", "ask"] as const;
|
|
27
|
+
export const FreshKindSchema = z.enum(FRESH_KINDS);
|
|
28
|
+
export type FreshKind = z.infer<typeof FreshKindSchema>;
|
|
29
|
+
export const FreshOfSchema = z.object({
|
|
30
|
+
conversationId: ConversationIdSchema.describe("The conversation whose work this one starts from."),
|
|
31
|
+
kind: FreshKindSchema.describe("What it is opened for: a code review, a test pass, or the person's own ask."),
|
|
32
|
+
});
|
|
33
|
+
export type FreshOf = z.infer<typeof FreshOfSchema>;
|
|
34
|
+
// The durable half, latched on the entry by the first turn and never cleared: the relationship, not a pending state.
|
|
35
|
+
export const FreshSessionSchema = z.object({
|
|
36
|
+
of: ConversationIdSchema.describe("The conversation whose work it started from."),
|
|
37
|
+
kind: FreshKindSchema.describe("What it was opened for: a code review, a test pass, or the person's own ask."),
|
|
38
|
+
at: z.number().describe("When it started, in milliseconds. Work its origin changed after this is work it has not seen."),
|
|
39
|
+
});
|
|
40
|
+
export type FreshSession = z.infer<typeof FreshSessionSchema>;
|
|
41
|
+
|
|
42
|
+
export const FRESH_OF_DESCRIPTION =
|
|
43
|
+
"Open this conversation on another conversation's work as it stands now, with none of that conversation's messages: for a review or a test that should judge the work, not the reasoning behind it. Its edits go back into that work. First turn only, and only on a private copy.";
|
|
44
|
+
|
|
45
|
+
// The turn's own rules for `freshOf`: a new private copy of its own, never beside a fork's copy of a chat, never on itself.
|
|
46
|
+
export const freshOfIssues = (
|
|
47
|
+
turn: { readonly freshOf?: FreshOf | undefined; readonly conversationId?: string | undefined; readonly isolated?: boolean | undefined; readonly forkOf?: unknown },
|
|
48
|
+
ctx: z.RefinementCtx,
|
|
49
|
+
): void => {
|
|
50
|
+
if (turn.freshOf === undefined) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (turn.conversationId === undefined || turn.isolated !== true) {
|
|
54
|
+
ctx.addIssue({ code: "custom", message: "freshOf requires an isolated conversationId" });
|
|
55
|
+
}
|
|
56
|
+
if (turn.forkOf !== undefined) {
|
|
57
|
+
ctx.addIssue({ code: "custom", message: "freshOf and forkOf are two different starts: a fork carries the conversation, a fresh session carries none of it" });
|
|
58
|
+
}
|
|
59
|
+
if (turn.freshOf.conversationId === turn.conversationId) {
|
|
60
|
+
ctx.addIssue({ code: "custom", message: "a conversation cannot start fresh on its own work" });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// behaviour except for restore points: that copy grows without bound on disk. Thirty days still covers recovering a
|
|
5
5
|
// deleted file; zero remains available for people who want every snapshot. The public-office preset sets the rest.
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import type { AdmissionRule } from "./
|
|
7
|
+
import type { AdmissionRule } from "./command-admission.js";
|
|
8
8
|
|
|
9
9
|
export const AgentRetentionDaysSchema = z
|
|
10
10
|
.number()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// Closed set of command names; the daemon builds argv from the name alone (hosts/device-commands.ts). Never a free-text
|
|
4
|
+
// command: the same socket carries `run_command`, which would grant a shell on the user's machine.
|
|
5
|
+
// `sync-unpair` runs the machine's own `sync uninstall --sandbox` (terminates both Mutagen sessions, drops the pairing,
|
|
6
|
+
// self-revokes enrollment); revoking from the sandbox side is a different route.
|
|
7
|
+
// `dev-restart`, `dev-rebuild` and `sync-install` are the three whose argv the daemon fills from what only it knows — the
|
|
8
|
+
// dev checkout on that machine, a freshly minted pairing token — which is also why none takes a path or a token from the
|
|
9
|
+
// caller. The two dev commands are also why a machine-side op is the wrong shape for them: this door carries a COMMAND
|
|
10
|
+
// STRING to a tool every released agent already has, so a sandbox can drive a machine whose agent predates the feature.
|
|
11
|
+
// `dev-rebuild-log` is the read side of `dev-rebuild`: the build is detached out there, so its log is the only place its
|
|
12
|
+
// progress exists, and polling this is what turns a fired-and-forgotten command into something with a progress bar.
|
|
13
|
+
// `sync-clean` removes the build output left in directories the sandbox has deleted, which is what stops those
|
|
14
|
+
// deletions from ever landing. It deletes only content the session already ignores, so it is the one command here whose
|
|
15
|
+
// worst outcome is a rebuild — which is why it is a button and not a turn.
|
|
16
|
+
// `mirror-ignore`/`mirror-unignore` are `mirror-off`'s per-port form, and the reason they exist: a port number that is
|
|
17
|
+
// permanently taken on one machine's localhost has no answer in an all-or-nothing switch, so the choice lives where the
|
|
18
|
+
// conflict does — one port, one device, durable — instead of muting every port the pairing serves.
|
|
19
|
+
export const DeviceCommandSchema = z.enum([
|
|
20
|
+
"mirror-off",
|
|
21
|
+
"mirror-on",
|
|
22
|
+
"mirror-ignore",
|
|
23
|
+
"mirror-unignore",
|
|
24
|
+
"sync-pause",
|
|
25
|
+
"sync-resume",
|
|
26
|
+
"sync-unpair",
|
|
27
|
+
"sync-clean",
|
|
28
|
+
"dev-restart",
|
|
29
|
+
"dev-rebuild",
|
|
30
|
+
"dev-rebuild-log",
|
|
31
|
+
"sync-install",
|
|
32
|
+
]);
|
|
33
|
+
export type DeviceCommand = z.infer<typeof DeviceCommandSchema>;
|
|
34
|
+
// The reversible sync switches: the subset a device's own row drives with a pair of buttons, as opposed to the two
|
|
35
|
+
// commands a card elsewhere issues once. Its own type so those button tables stay total without carrying entries for
|
|
36
|
+
// commands they can never send.
|
|
37
|
+
export const DeviceSyncSwitchSchema = DeviceCommandSchema.exclude(["dev-restart", "dev-rebuild", "dev-rebuild-log", "sync-install", "sync-clean"]);
|
|
38
|
+
export type DeviceSyncSwitch = z.infer<typeof DeviceSyncSwitchSchema>;
|
|
39
|
+
|
|
40
|
+
// Where a detached rebuild reports itself, and the reader of that report (dev-rebuild-log.ts).
|
|
41
|
+
export { DEV_REBUILD_EXIT_MARK, DEV_REBUILD_QUIET_MARK, type DevRebuildLog, devRebuildLogPath, readDevRebuildLog } from "./dev-rebuild-log.js";
|
|
42
|
+
|
|
43
|
+
// Machine's sandbox id (absent = every paired sandbox); must start alphanumeric, else it parses as a CLI flag.
|
|
44
|
+
export const DeviceSandboxIdSchema = z
|
|
45
|
+
.string()
|
|
46
|
+
.max(200)
|
|
47
|
+
.regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/);
|
|
48
|
+
// A folder on the DEVICE for `sync-install` to keep in step. The only caller-supplied string that reaches a command
|
|
49
|
+
// line, so its shape is the guard: `~`, an absolute POSIX path or a drive letter, and none of the characters that would
|
|
50
|
+
// end the argument it sits in. `~` is expanded by the daemon, which is why `$` is not allowed to arrive here. The line
|
|
51
|
+
// may be PowerShell, which reads the typographic quotes “ ” „ as double quotes and ‘ ’ ‚ ‛ as single quotes beside the
|
|
52
|
+
// ASCII ones, so those are refused too: the daemon quotes the folder, and this keeps a second guard where one quoter
|
|
53
|
+
// misses a character.
|
|
54
|
+
export const DeviceLocalDirSchema = z
|
|
55
|
+
.string()
|
|
56
|
+
.min(1)
|
|
57
|
+
.max(4096)
|
|
58
|
+
// The curly quotes as escapes: bun's transpiler rewrites a literal one in a regex to its escape and tsgo keeps it,
|
|
59
|
+
// so spelled literally the pattern reads differently from source and from dist, and contract.lock.json can match
|
|
60
|
+
// only one of them.
|
|
61
|
+
.regex(/^(?:~|\/|[A-Za-z]:[\\/])[^"'`$;|&\n\r\u201C\u201D\u201E\u2018\u2019\u201A\u201B]*$/);
|
|
62
|
+
// A TCP port number, the one value a caller supplies that reaches a command line as a number rather than a string.
|
|
63
|
+
export const PortNumberSchema = z.number().int().min(1).max(65535);
|
|
64
|
+
export const DeviceCommandInputSchema = z.object({
|
|
65
|
+
id: z.string().min(1),
|
|
66
|
+
command: DeviceCommandSchema,
|
|
67
|
+
sandboxId: DeviceSandboxIdSchema.optional(),
|
|
68
|
+
// `sync-install` only: which half to enroll (a member's "sync" still comes back mirror, decided daemon-side) and,
|
|
69
|
+
// for file sync, the folder on that device. The pairing token is minted by the daemon; no caller ever carries one.
|
|
70
|
+
mode: z.enum(["sync", "mirror"]).optional(),
|
|
71
|
+
localDir: DeviceLocalDirSchema.optional(),
|
|
72
|
+
// The two per-port mirror switches only. A number rather than a string, so nothing a caller sends can widen the
|
|
73
|
+
// command line it lands in.
|
|
74
|
+
port: PortNumberSchema.optional(),
|
|
75
|
+
});
|
|
76
|
+
export type DeviceCommandInput = z.infer<typeof DeviceCommandInputSchema>;
|
|
77
|
+
// `ok` is the command's own exit status, not this route's: a refusal or non-zero exit is a real answer, not a thrown
|
|
78
|
+
// error. Only an unreachable machine throws. `output` is the command's own printed text.
|
|
79
|
+
export const DeviceCommandResultSchema = z.object({
|
|
80
|
+
ok: z.boolean(),
|
|
81
|
+
message: z.string(),
|
|
82
|
+
output: z.string().optional(),
|
|
83
|
+
// WHICH KIND OF `ok: false` THIS IS, because a caller that repeats itself needs to tell them apart: the device
|
|
84
|
+
// turning the command away (a switch of its own is off, the path is out of its reach) will turn it away again,
|
|
85
|
+
// whereas a command it accepted and then killed at its deadline says nothing except that this attempt was too slow.
|
|
86
|
+
refused: z.boolean(),
|
|
87
|
+
});
|
|
88
|
+
export type DeviceCommandResult = z.infer<typeof DeviceCommandResultSchema>;
|
|
89
|
+
|
|
@@ -33,6 +33,15 @@ export type DeviceConflict = z.infer<typeof DeviceConflictSchema>;
|
|
|
33
33
|
export const clearableOnDevice = (conflict: DeviceConflict): boolean =>
|
|
34
34
|
conflict.nature === "derived-leftover" && conflict.local === "untracked" && conflict.sandbox === "deleted";
|
|
35
35
|
|
|
36
|
+
// WHY A FOLDER'S FILE SYNC IS HELD STILL, AND BY WHOM (2026-10-20). The machine agent reads each off a fact it keeps
|
|
37
|
+
// on the pairing and makes Mutagen agree every pass (its sync/holds.ts), so a pause never outlives its reason and a
|
|
38
|
+
// resume never undoes somebody else's. `owner` is a person's Pause, the only one a person lifts; every other is the
|
|
39
|
+
// agent's own and lifts by itself once its reason ends. `transfer` (2026-10-21) is a bring-back, a restore or a delivery
|
|
40
|
+
// of landed work writing into the folder. Strings on the wire, so a reason a newer agent adds still reads as held to an
|
|
41
|
+
// older page.
|
|
42
|
+
export const DeviceSyncHoldSchema = z.enum(["owner", "gone", "container-missing", "container-trashed", "swap", "unreachable", "low-disk", "transfer"]);
|
|
43
|
+
export type DeviceSyncHold = z.infer<typeof DeviceSyncHoldSchema>;
|
|
44
|
+
|
|
36
45
|
// The drive reading that paused a pairing for want of room: when (epoch ms), and how much was free of how much.
|
|
37
46
|
export const DeviceLowDiskSchema = z.object({
|
|
38
47
|
since: z.number(),
|
package/src/schemas/devices.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// What one of the user's own machines is running.
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { PortNumberSchema } from "./device-commands.js";
|
|
3
4
|
import { DeviceBridgeHoldSchema, DeviceConflictSchema, DeviceLowDiskSchema } from "./device-folder.js";
|
|
4
|
-
import { parseHostConnection, type DeviceFacts, DeviceFactsSchema, MachineIdSchema, userDistrosOf, WslEnvironmentSchema } from "./hosts.js";
|
|
5
|
+
import { parseHostConnection, type DeviceFacts, DeviceFactsSchema, MachineIdentitySchema, MachineIdSchema, userDistrosOf, WslEnvironmentSchema } from "./hosts.js";
|
|
5
6
|
import { RollbackTargetSchema, UpdateOutcomeSchema } from "./updates.js";
|
|
6
7
|
import { DEV_VERSION } from "../state/versions.js";
|
|
7
8
|
// Desktop-sync report shape shared by the agent, daemon and browser, produced only by the agent's own `deviceReport`.
|
|
@@ -117,13 +118,13 @@ export type DeviceSandbox = z.infer<typeof DeviceSandboxSchema>;
|
|
|
117
118
|
// One operation on one sandbox, streamed as lines ending in a `result` or `error` frame. `prepare` builds the pending
|
|
118
119
|
// update without touching the container. `set-shape` sets its resources and privileges, now or for the next restart;
|
|
119
120
|
// `forget-shape` drops a shape saved for the next restart. `start`/`restart` apply a saved shape (all through `ic`).
|
|
120
|
-
// `reshape` is
|
|
121
|
-
//
|
|
122
|
-
// `sandboxes` switch, not removal, since a runner holds no separate workspace to lose.
|
|
121
|
+
// `reshape` is `set-shape`'s older spelling, kept one release. `runner-up`/`runner-remove` act on a runner (this
|
|
122
|
+
// sandbox's own container); gated by the `sandboxes` switch, not removal, as a runner holds no workspace to lose.
|
|
123
123
|
export const DeviceSandboxOpSchema = z.enum([
|
|
124
124
|
"start",
|
|
125
125
|
"stop",
|
|
126
126
|
"restart",
|
|
127
|
+
"sleep",
|
|
127
128
|
"prepare",
|
|
128
129
|
// `prepare` under the unattended rules (`ic sandbox prepare --auto`): nobody pressed anything, so low disk is "not
|
|
129
130
|
// now" and a pinned sandbox or the version it went back from is left alone. What the update card sends by itself
|
|
@@ -203,7 +204,7 @@ export const icShapeArgs = (slug: string, fields: SandboxShapeFields, when: Sand
|
|
|
203
204
|
];
|
|
204
205
|
export const icForgetShapeArgs = (slug: string): string[] => ["sandbox", "shape", slug, "--forget"];
|
|
205
206
|
// Power goes through ic too, so a Start or Restart from any door applies the shape saved for the next restart.
|
|
206
|
-
export const icPowerArgs = (op: "start" | "stop" | "restart", slug: string): string[] => ["sandbox", op, slug];
|
|
207
|
+
export const icPowerArgs = (op: "start" | "stop" | "restart" | "sleep", slug: string): string[] => ["sandbox", op, slug];
|
|
207
208
|
// Adds the device id to the flow input; the daemon looks up machines by id. `resumeTurns` is the owner saying, as they
|
|
208
209
|
// restart the sandbox relaying this, that the turns it cuts should run again once it is back; the daemon keeps it for
|
|
209
210
|
// its next boot and never forwards it to the machine. A sandbox older than it ignores it, and the cut turns wait.
|
|
@@ -230,92 +231,7 @@ export type DeviceAgentFlow = z.infer<typeof DeviceAgentFlowSchema>;
|
|
|
230
231
|
// Adds the device id to the flow input.
|
|
231
232
|
export const DeviceAgentFlowInputSchema = DeviceAgentFlowSchema.extend({ id: z.string().min(1) });
|
|
232
233
|
export type DeviceAgentFlowInput = z.infer<typeof DeviceAgentFlowInputSchema>;
|
|
233
|
-
|
|
234
|
-
// command: the same socket carries `run_command`, which would grant a shell on the user's machine.
|
|
235
|
-
// `sync-unpair` runs the machine's own `sync uninstall --sandbox` (terminates both Mutagen sessions, drops the pairing,
|
|
236
|
-
// self-revokes enrollment); revoking from the sandbox side is a different route.
|
|
237
|
-
// `dev-restart`, `dev-rebuild` and `sync-install` are the three whose argv the daemon fills from what only it knows — the
|
|
238
|
-
// dev checkout on that machine, a freshly minted pairing token — which is also why none takes a path or a token from the
|
|
239
|
-
// caller. The two dev commands are also why a machine-side op is the wrong shape for them: this door carries a COMMAND
|
|
240
|
-
// STRING to a tool every released agent already has, so a sandbox can drive a machine whose agent predates the feature.
|
|
241
|
-
// `dev-rebuild-log` is the read side of `dev-rebuild`: the build is detached out there, so its log is the only place its
|
|
242
|
-
// progress exists, and polling this is what turns a fired-and-forgotten command into something with a progress bar.
|
|
243
|
-
// `sync-clean` removes the build output left in directories the sandbox has deleted, which is what stops those
|
|
244
|
-
// deletions from ever landing. It deletes only content the session already ignores, so it is the one command here whose
|
|
245
|
-
// worst outcome is a rebuild — which is why it is a button and not a turn.
|
|
246
|
-
// `mirror-ignore`/`mirror-unignore` are `mirror-off`'s per-port form, and the reason they exist: a port number that is
|
|
247
|
-
// permanently taken on one machine's localhost has no answer in an all-or-nothing switch, so the choice lives where the
|
|
248
|
-
// conflict does — one port, one device, durable — instead of muting every port the pairing serves.
|
|
249
|
-
export const DeviceCommandSchema = z.enum([
|
|
250
|
-
"mirror-off",
|
|
251
|
-
"mirror-on",
|
|
252
|
-
"mirror-ignore",
|
|
253
|
-
"mirror-unignore",
|
|
254
|
-
"sync-pause",
|
|
255
|
-
"sync-resume",
|
|
256
|
-
"sync-unpair",
|
|
257
|
-
"sync-clean",
|
|
258
|
-
"dev-restart",
|
|
259
|
-
"dev-rebuild",
|
|
260
|
-
"dev-rebuild-log",
|
|
261
|
-
"sync-install",
|
|
262
|
-
]);
|
|
263
|
-
export type DeviceCommand = z.infer<typeof DeviceCommandSchema>;
|
|
264
|
-
// The reversible sync switches: the subset a device's own row drives with a pair of buttons, as opposed to the two
|
|
265
|
-
// commands a card elsewhere issues once. Its own type so those button tables stay total without carrying entries for
|
|
266
|
-
// commands they can never send.
|
|
267
|
-
export const DeviceSyncSwitchSchema = DeviceCommandSchema.exclude(["dev-restart", "dev-rebuild", "dev-rebuild-log", "sync-install", "sync-clean"]);
|
|
268
|
-
export type DeviceSyncSwitch = z.infer<typeof DeviceSyncSwitchSchema>;
|
|
269
|
-
|
|
270
|
-
// Where a detached rebuild reports itself, and the reader of that report (dev-rebuild-log.ts).
|
|
271
|
-
export { DEV_REBUILD_EXIT_MARK, DEV_REBUILD_QUIET_MARK, type DevRebuildLog, devRebuildLogPath, readDevRebuildLog } from "./dev-rebuild-log.js";
|
|
272
|
-
|
|
273
|
-
// Machine's sandbox id (absent = every paired sandbox); must start alphanumeric, else it parses as a CLI flag.
|
|
274
|
-
export const DeviceSandboxIdSchema = z
|
|
275
|
-
.string()
|
|
276
|
-
.max(200)
|
|
277
|
-
.regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/);
|
|
278
|
-
// A folder on the DEVICE for `sync-install` to keep in step. The only caller-supplied string that reaches a command
|
|
279
|
-
// line, so its shape is the guard: `~`, an absolute POSIX path or a drive letter, and none of the characters that would
|
|
280
|
-
// end the argument it sits in. `~` is expanded by the daemon, which is why `$` is not allowed to arrive here. The line
|
|
281
|
-
// may be PowerShell, which reads the typographic quotes “ ” „ as double quotes and ‘ ’ ‚ ‛ as single quotes beside the
|
|
282
|
-
// ASCII ones, so those are refused too: the daemon quotes the folder, and this keeps a second guard where one quoter
|
|
283
|
-
// misses a character.
|
|
284
|
-
export const DeviceLocalDirSchema = z
|
|
285
|
-
.string()
|
|
286
|
-
.min(1)
|
|
287
|
-
.max(4096)
|
|
288
|
-
// The curly quotes as escapes: bun's transpiler rewrites a literal one in a regex to its escape and tsgo keeps it,
|
|
289
|
-
// so spelled literally the pattern reads differently from source and from dist, and contract.lock.json can match
|
|
290
|
-
// only one of them.
|
|
291
|
-
.regex(/^(?:~|\/|[A-Za-z]:[\\/])[^"'`$;|&\n\r\u201C\u201D\u201E\u2018\u2019\u201A\u201B]*$/);
|
|
292
|
-
// A TCP port number, the one value a caller supplies that reaches a command line as a number rather than a string.
|
|
293
|
-
export const PortNumberSchema = z.number().int().min(1).max(65535);
|
|
294
|
-
export const DeviceCommandInputSchema = z.object({
|
|
295
|
-
id: z.string().min(1),
|
|
296
|
-
command: DeviceCommandSchema,
|
|
297
|
-
sandboxId: DeviceSandboxIdSchema.optional(),
|
|
298
|
-
// `sync-install` only: which half to enroll (a member's "sync" still comes back mirror, decided daemon-side) and,
|
|
299
|
-
// for file sync, the folder on that device. The pairing token is minted by the daemon; no caller ever carries one.
|
|
300
|
-
mode: z.enum(["sync", "mirror"]).optional(),
|
|
301
|
-
localDir: DeviceLocalDirSchema.optional(),
|
|
302
|
-
// The two per-port mirror switches only. A number rather than a string, so nothing a caller sends can widen the
|
|
303
|
-
// command line it lands in.
|
|
304
|
-
port: PortNumberSchema.optional(),
|
|
305
|
-
});
|
|
306
|
-
export type DeviceCommandInput = z.infer<typeof DeviceCommandInputSchema>;
|
|
307
|
-
// `ok` is the command's own exit status, not this route's: a refusal or non-zero exit is a real answer, not a thrown
|
|
308
|
-
// error. Only an unreachable machine throws. `output` is the command's own printed text.
|
|
309
|
-
export const DeviceCommandResultSchema = z.object({
|
|
310
|
-
ok: z.boolean(),
|
|
311
|
-
message: z.string(),
|
|
312
|
-
output: z.string().optional(),
|
|
313
|
-
// WHICH KIND OF `ok: false` THIS IS, because a caller that repeats itself needs to tell them apart: the device
|
|
314
|
-
// turning the command away (a switch of its own is off, the path is out of its reach) will turn it away again,
|
|
315
|
-
// whereas a command it accepted and then killed at its deadline says nothing except that this attempt was too slow.
|
|
316
|
-
refused: z.boolean(),
|
|
317
|
-
});
|
|
318
|
-
export type DeviceCommandResult = z.infer<typeof DeviceCommandResultSchema>;
|
|
234
|
+
export * from "./device-commands.js";
|
|
319
235
|
|
|
320
236
|
// What a synced folder reports beyond Mutagen's word, its conflicts and what the device holds back (device-folder.ts).
|
|
321
237
|
export * from "./device-folder.js";
|
|
@@ -323,8 +239,7 @@ export * from "./device-folder.js";
|
|
|
323
239
|
// One paired sandbox as the local agent holds it; `localDir` is which folder on that device holds this sandbox's /work.
|
|
324
240
|
export const DevicePairingSchema = z.object({
|
|
325
241
|
sandboxId: z.string(),
|
|
326
|
-
// The account's name for the sandbox, stamped by the editor that reads the report (withSandboxNames)
|
|
327
|
-
// container's `name` is. A machine never sends one: all it knows is the folder, named once at setup.
|
|
242
|
+
// The account's name for the sandbox, stamped by the editor that reads the report (withSandboxNames); never a machine's.
|
|
328
243
|
name: z.string().optional(),
|
|
329
244
|
mode: z.enum(["sync", "mirror"]),
|
|
330
245
|
// Set only for mode "sync", and only for the sandbox being reported to.
|
|
@@ -332,12 +247,13 @@ export const DevicePairingSchema = z.object({
|
|
|
332
247
|
// Which sandbox folder `localDir` holds when it is not /work itself: a project pairing's `/work/<name>`, the
|
|
333
248
|
// owner's own folder, which carries no state backup and no git bridge. Absent means /work.
|
|
334
249
|
remoteDir: z.string().optional(),
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
projectsHost
|
|
338
|
-
//
|
|
339
|
-
// folder attached to the machine's own sandbox says "auto"; absent means Bring back by hand, as before.
|
|
250
|
+
// Whether landed work in this project folder is delivered to `localDir` by itself (`deliverProject`). A project
|
|
251
|
+
// sandbox's folder says "auto"; absent means Bring back by hand, as before. (2026-10-21) The folderless
|
|
252
|
+
// `projectsHost` pairing of the desktop app's one sandbox per computer went with that sandbox; an older agent's report
|
|
253
|
+
// that still carries it parses, the key dropped.
|
|
340
254
|
deliver: z.enum(["auto", "off"]).optional(),
|
|
255
|
+
// (2026-10-20) The slug this machine's ic knows the sandbox by: how the desktop app starts or forgets a folder's sandbox.
|
|
256
|
+
slug: z.string().optional(),
|
|
341
257
|
// Machine-owned switch (agent's own `sync mirror off`); absent reads as "on", not merely unknown.
|
|
342
258
|
mirroring: z.enum(["on", "off"]).optional(),
|
|
343
259
|
// Mutagen's own status word, kept verbatim rather than reduced to a traffic light.
|
|
@@ -346,7 +262,9 @@ export const DevicePairingSchema = z.object({
|
|
|
346
262
|
conflicts: z.number().int().nonnegative().optional(),
|
|
347
263
|
// Conflicted paths, capped at `CONFLICT_PATHS_MAX`; `conflicts` above is the true, uncapped count.
|
|
348
264
|
conflictedPaths: z.array(DeviceConflictSchema).optional(),
|
|
265
|
+
// Mutagen's word, and why the agent holds it still, owner first (DeviceSyncHoldSchema); agreeing by its next pass.
|
|
349
266
|
paused: z.boolean().optional(),
|
|
267
|
+
heldBy: z.array(z.string()).optional(),
|
|
350
268
|
// Second session's status (the state-dir backup mirror), reported separately: the two fail independently.
|
|
351
269
|
backupStatus: z.string().optional(),
|
|
352
270
|
// (2026-10-18) While the drive holding `localDir` is nearly full, the reading that paused its sync and git bridge; and the
|
|
@@ -488,12 +406,11 @@ export const SshHostKeySchema = z
|
|
|
488
406
|
|
|
489
407
|
// POST /system/authorized-key: a machine's agent enrolling its SSH key for desktop sync, redeeming a pairing token.
|
|
490
408
|
// Every field past `key` is optional: an older agent sends none of them and is still enrolled.
|
|
491
|
-
|
|
409
|
+
// The key, and the computer and environment enrolling it (the same identity a device redeem sends), so the
|
|
410
|
+
// enrollment joins that machine's card.
|
|
411
|
+
export const SyncEnrollmentRequestSchema = MachineIdentitySchema.extend({
|
|
492
412
|
// One authorized_keys line; its comment is the name the enrollment goes by (`DeviceSync.machine`).
|
|
493
413
|
key: z.string(),
|
|
494
|
-
// The computer and the environment on it that are enrolling, so the enrollment joins that machine's card.
|
|
495
|
-
machineId: MachineIdSchema.optional(),
|
|
496
|
-
environment: z.string().min(1).optional(),
|
|
497
414
|
});
|
|
498
415
|
export type SyncEnrollmentRequest = z.infer<typeof SyncEnrollmentRequestSchema>;
|
|
499
416
|
|
|
@@ -546,6 +463,10 @@ export const DeviceSchema = z.object({
|
|
|
546
463
|
// (a switch that is off, an `ic` too old to list). Absent when it listed, or when nothing answered at all. What a
|
|
547
464
|
// card falling back to a command says instead of "connect the computer": that computer IS connected (2026-10-07).
|
|
548
465
|
sandboxesUnread: z.string().optional(),
|
|
466
|
+
// Whether its card's "Manage sandboxes on this device" switch is on (HostSummary.manages). Not the same fact as
|
|
467
|
+
// `sandboxes`: "Run commands" alone lists the containers, and only this switch lets one be made, started or removed,
|
|
468
|
+
// so a screen offering such a press asks here first. Absent on a sync-only row and from a daemon older than it.
|
|
469
|
+
manages: z.boolean().optional(),
|
|
549
470
|
gap: DeviceGapSchema.optional(),
|
|
550
471
|
});
|
|
551
472
|
export type Device = z.infer<typeof DeviceSchema>;
|
|
@@ -659,14 +580,11 @@ const doorsRunningSandbox = (devices: readonly Device[], slug: string | undefine
|
|
|
659
580
|
? []
|
|
660
581
|
: devices.filter((device) => device.hostId !== undefined && device.online === true && (device.sandboxes ?? []).some((box) => box.slug === slug));
|
|
661
582
|
|
|
662
|
-
// The connected, online device whose docker reports a given sandbox slug: the machine that sandbox RUNS ON,
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
// a terminal command for a machine one click could have done it on.
|
|
668
|
-
// Answers with a door, and a container verb may take any door of the machine; a command written for a PATH may not
|
|
669
|
-
// (`hostHoldingPath`).
|
|
583
|
+
// The connected, online device whose docker reports a given sandbox slug: the machine that sandbox RUNS ON, not any
|
|
584
|
+
// machine merely paired with it, and `undefined` for a sync-only agent, which reports no containers. Read off the row's
|
|
585
|
+
// own container list, not the report's: a card granting sandbox management without "Run commands" refuses to describe
|
|
586
|
+
// itself yet runs every swap this answer leads to, so judging it on the report printed a command one click could do.
|
|
587
|
+
// Answers with a door, any of which a container verb may take; a command written for a PATH may not (`hostHoldingPath`).
|
|
670
588
|
export const hostRunningSandbox = (devices: readonly Device[], slug: string | undefined): string | undefined =>
|
|
671
589
|
doorsRunningSandbox(devices, slug)[0]?.hostId;
|
|
672
590
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// environment: the overlay Dockerfile extending the sandbox image
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
// The approved
|
|
4
|
-
// is derived, never stored:
|
|
5
|
-
//
|
|
6
|
-
// pending rebuild: approved present but hashes differ.
|
|
3
|
+
// The approved overlay is daemon-composed (pinned FROM + capability fragments + the owner-approved custom section) from its
|
|
4
|
+
// inputs on every read. Status is derived, never stored:
|
|
5
|
+
// pending rebuild: rebuildPending(approved.hash, appliedHash) (state/sandbox-build.ts); applied otherwise.
|
|
7
6
|
// proposed: proposal present with a hash different from custom's.
|
|
8
7
|
|
|
9
8
|
const environmentFileSchema = z.object({ content: z.string(), hash: z.string() });
|
|
@@ -45,10 +44,10 @@ export type RuntimeInstall = z.infer<typeof RuntimeInstallSchema>;
|
|
|
45
44
|
// (`environment propose`) clears its tool's entries.
|
|
46
45
|
export const SettledDraftSchema = z.object({ tool: z.string(), hash: z.string(), at: z.number() });
|
|
47
46
|
export type SettledDraft = z.infer<typeof SettledDraftSchema>;
|
|
48
|
-
// One overlay the daemon composed, by the hash a rebuild is stamped with, and the
|
|
49
|
-
//
|
|
50
|
-
// running container was actually built from, which is rarely the newest one composed:
|
|
51
|
-
// and daemon update composes again, and a rebuild builds whatever was newest
|
|
47
|
+
// One overlay the daemon composed, by the hash a rebuild is stamped with, and the sections it carried, each by the hash
|
|
48
|
+
// of its trimmed steps: capability fragments unnamed, custom-section blocks by name. Kept so "is this in the image" is
|
|
49
|
+
// answered against the overlay the running container was actually built from, which is rarely the newest one composed:
|
|
50
|
+
// every approval, capability change and daemon update composes again, and a rebuild builds whatever was newest then.
|
|
52
51
|
export const EnvironmentCompositionSchema = z.object({
|
|
53
52
|
hash: z.string(),
|
|
54
53
|
at: z.number(),
|
|
@@ -196,7 +195,7 @@ export type EnvironmentRemove = z.infer<typeof EnvironmentRemoveSchema>;
|
|
|
196
195
|
export const EnvironmentContentsSchema = z.object({ items: z.array(EnvironmentItemSchema) });
|
|
197
196
|
export type EnvironmentContents = z.infer<typeof EnvironmentContentsSchema>;
|
|
198
197
|
// A sandbox is four stores: /work, /history, the container, and the AI-provider credential root. A bundle carries only
|
|
199
|
-
// the first two (WORKSPACE_STATE_FILES
|
|
198
|
+
// the first two (WORKSPACE_STATE_FILES here, the daemon's HISTORY_STATE_FILES); it cannot rebuild the container or credentials, so
|
|
200
199
|
// importing one is a report, not a claim of equivalence. Only the outbound half is here; inbound is one of arrival.ts's
|
|
201
200
|
// four sources.
|
|
202
201
|
|