@intentic/sandbox-contract 1.311.0 → 1.313.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 +32 -4
- package/dist/chores/chores.js +6 -6
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/index.d.ts +0 -1
- package/dist/chores/index.d.ts.map +1 -1
- package/dist/chores/index.js +0 -1
- package/dist/chores/index.js.map +1 -1
- package/dist/chores/prompt.d.ts.map +1 -1
- package/dist/chores/prompt.js +3 -2
- package/dist/chores/prompt.js.map +1 -1
- package/dist/contracts/accounts.contract.d.ts +69 -0
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +436 -0
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +11 -1
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +718 -90
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +30 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.js +1 -1
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/device.contract.d.ts +20 -4
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +1 -1
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +13 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.d.ts +2 -0
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/offload.contract.d.ts +107 -0
- package/dist/contracts/offload.contract.d.ts.map +1 -0
- package/dist/contracts/offload.contract.js +53 -0
- package/dist/contracts/offload.contract.js.map +1 -0
- package/dist/contracts/personas.contract.d.ts +2 -0
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/ports.contract.d.ts +5 -0
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.d.ts +204 -0
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +3 -1
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +1 -0
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +59 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +20 -8
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +2 -2
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +230 -15
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +88 -0
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +217 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +40 -3
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/documents/conversions.d.ts +81 -0
- package/dist/documents/conversions.d.ts.map +1 -0
- package/dist/documents/conversions.js +213 -0
- package/dist/documents/conversions.js.map +1 -0
- package/dist/documents/index.d.ts +4 -0
- package/dist/documents/index.d.ts.map +1 -0
- package/dist/documents/index.js +4 -0
- package/dist/documents/index.js.map +1 -0
- package/dist/documents/passthrough.d.ts +13 -0
- package/dist/documents/passthrough.d.ts.map +1 -0
- package/dist/documents/passthrough.js +101 -0
- package/dist/documents/passthrough.js.map +1 -0
- package/dist/documents/read.d.ts +24 -0
- package/dist/documents/read.d.ts.map +1 -0
- package/dist/documents/read.js +81 -0
- package/dist/documents/read.js.map +1 -0
- package/dist/events/agent-events.d.ts +235 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +3 -0
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/child-run.d.ts +9 -0
- package/dist/events/child-run.d.ts.map +1 -0
- package/dist/events/child-run.js +41 -0
- package/dist/events/child-run.js.map +1 -0
- package/dist/events/errands.d.ts +5 -0
- package/dist/events/errands.d.ts.map +1 -0
- package/dist/events/errands.js +19 -0
- package/dist/events/errands.js.map +1 -0
- package/dist/events/land-breakage.d.ts +3 -0
- package/dist/events/land-breakage.d.ts.map +1 -1
- package/dist/events/land-breakage.js +3 -0
- package/dist/events/land-breakage.js.map +1 -1
- package/dist/events/land-conflict.d.ts +3 -0
- package/dist/events/land-conflict.d.ts.map +1 -0
- package/dist/events/land-conflict.js +4 -0
- package/dist/events/land-conflict.js.map +1 -0
- package/dist/events/requests.d.ts +152 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/requests.js +26 -1
- package/dist/events/requests.js.map +1 -1
- package/dist/events/system-events.d.ts +74 -12
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/system-events.js +3 -1
- package/dist/events/system-events.js.map +1 -1
- package/dist/events/transcript.d.ts +387 -0
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +3 -0
- package/dist/events/transcript.js.map +1 -1
- package/dist/events/verify-nudge.d.ts.map +1 -1
- package/dist/events/verify-nudge.js.map +1 -1
- package/dist/front/browser-wire.d.ts +6 -0
- package/dist/front/browser-wire.d.ts.map +1 -0
- package/dist/front/browser-wire.js +4 -0
- package/dist/front/browser-wire.js.map +1 -0
- package/dist/front/front-wire.d.ts +6 -0
- package/dist/front/front-wire.d.ts.map +1 -0
- package/dist/front/front-wire.js +5 -0
- package/dist/front/front-wire.js.map +1 -0
- package/dist/front/generated/browser-wire.d.ts +19 -0
- package/dist/front/generated/browser-wire.d.ts.map +1 -0
- package/dist/front/generated/browser-wire.js +2 -0
- package/dist/front/generated/browser-wire.js.map +1 -0
- package/dist/front/generated/wire.d.ts +70 -1
- package/dist/front/generated/wire.d.ts.map +1 -1
- package/dist/ids/conversation-ids.d.ts +3 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -1
- package/dist/ids/conversation-ids.js +4 -2
- package/dist/ids/conversation-ids.js.map +1 -1
- package/dist/ids/session-names.d.ts +3 -0
- package/dist/ids/session-names.d.ts.map +1 -1
- package/dist/ids/session-names.js +3 -0
- package/dist/ids/session-names.js.map +1 -1
- package/dist/index.d.ts +2052 -190
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/models/agent-catalog.d.ts.map +1 -1
- package/dist/models/agent-catalog.js +4 -6
- package/dist/models/agent-catalog.js.map +1 -1
- package/dist/models/agent-runtimes.d.ts +2 -1
- package/dist/models/agent-runtimes.d.ts.map +1 -1
- package/dist/models/agent-runtimes.js +7 -1
- package/dist/models/agent-runtimes.js.map +1 -1
- package/dist/models/plan-pools.d.ts +22 -1
- package/dist/models/plan-pools.d.ts.map +1 -1
- package/dist/models/plan-pools.js +86 -0
- package/dist/models/plan-pools.js.map +1 -1
- package/dist/policy/request-status.d.ts +1 -1
- package/dist/policy/request-status.d.ts.map +1 -1
- package/dist/policy/request-status.js +4 -11
- package/dist/policy/request-status.js.map +1 -1
- package/dist/policy/reserved-servers.d.ts.map +1 -1
- package/dist/policy/reserved-servers.js +2 -1
- package/dist/policy/reserved-servers.js.map +1 -1
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +1 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/container-requirements.d.ts +0 -1
- package/dist/protocol/container-requirements.d.ts.map +1 -1
- package/dist/protocol/container-requirements.js +1 -2
- package/dist/protocol/container-requirements.js.map +1 -1
- package/dist/protocol/edge-verdict.d.ts +2 -1
- package/dist/protocol/edge-verdict.d.ts.map +1 -1
- package/dist/protocol/edge-verdict.js +1 -1
- package/dist/protocol/edge-verdict.js.map +1 -1
- package/dist/protocol/ingress-contract.d.ts +1 -12
- package/dist/protocol/ingress-contract.d.ts.map +1 -1
- package/dist/protocol/ingress-contract.js +1 -1
- package/dist/protocol/ingress-contract.js.map +1 -1
- package/dist/protocol/raw-routes.d.ts +36 -26
- package/dist/protocol/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw-routes.js +17 -23
- package/dist/protocol/raw-routes.js.map +1 -1
- package/dist/protocol/route-meta.d.ts +22 -0
- package/dist/protocol/route-meta.d.ts.map +1 -1
- package/dist/protocol/route-meta.js +16 -0
- package/dist/protocol/route-meta.js.map +1 -1
- package/dist/protocol/runner-protocol.d.ts +34 -0
- package/dist/protocol/runner-protocol.d.ts.map +1 -1
- package/dist/protocol/runner-protocol.js +33 -0
- package/dist/protocol/runner-protocol.js.map +1 -1
- package/dist/protocol/tunnel-bulk.d.ts +2 -0
- package/dist/protocol/tunnel-bulk.d.ts.map +1 -0
- package/dist/protocol/tunnel-bulk.js +3 -0
- package/dist/protocol/tunnel-bulk.js.map +1 -0
- package/dist/protocol/x402.d.ts +17 -0
- package/dist/protocol/x402.d.ts.map +1 -0
- package/dist/protocol/x402.js +37 -0
- package/dist/protocol/x402.js.map +1 -0
- package/dist/schemas/activity.d.ts.map +1 -1
- package/dist/schemas/activity.js.map +1 -1
- package/dist/schemas/agent.d.ts +25 -0
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +14 -2
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +90 -18
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +49 -5
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automations.d.ts +23 -6
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/devices.d.ts +134 -7
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +43 -18
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +26 -0
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/extension-updates.js +4 -0
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/git/git.d.ts +19 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/git/git.js +1 -0
- package/dist/schemas/git/git.js.map +1 -1
- package/dist/schemas/hosts.d.ts +35 -3
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +22 -6
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/keep-warm.d.ts +2 -12
- package/dist/schemas/keep-warm.d.ts.map +1 -1
- package/dist/schemas/keep-warm.js +8 -10
- package/dist/schemas/keep-warm.js.map +1 -1
- package/dist/schemas/metrics.d.ts +29 -0
- package/dist/schemas/metrics.d.ts.map +1 -1
- package/dist/schemas/metrics.js +19 -3
- package/dist/schemas/metrics.js.map +1 -1
- package/dist/schemas/offload.d.ts +62 -0
- package/dist/schemas/offload.d.ts.map +1 -0
- package/dist/schemas/offload.js +23 -0
- package/dist/schemas/offload.js.map +1 -0
- package/dist/schemas/personas.d.ts +3 -0
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +12 -3
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/ports.d.ts +10 -0
- package/dist/schemas/ports.d.ts.map +1 -1
- package/dist/schemas/ports.js +8 -0
- package/dist/schemas/ports.js.map +1 -1
- package/dist/schemas/providers/plan-limits.d.ts +169 -0
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +54 -1
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/providers/provider-oauth.d.ts +69 -0
- package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/providers/provider-oauth.js +6 -1
- package/dist/schemas/providers/provider-oauth.js.map +1 -1
- package/dist/schemas/settings-history.d.ts +55 -0
- package/dist/schemas/settings-history.d.ts.map +1 -0
- package/dist/schemas/settings-history.js +73 -0
- package/dist/schemas/settings-history.js.map +1 -0
- package/dist/schemas/settings.d.ts +188 -4
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +41 -26
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/speaker.d.ts +36 -0
- package/dist/schemas/speaker.d.ts.map +1 -0
- package/dist/schemas/speaker.js +62 -0
- package/dist/schemas/speaker.js.map +1 -0
- package/dist/schemas/state-plan.d.ts +46 -0
- package/dist/schemas/state-plan.d.ts.map +1 -0
- package/dist/schemas/state-plan.js +31 -0
- package/dist/schemas/state-plan.js.map +1 -0
- package/dist/schemas/system.d.ts +64 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +12 -1
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/workspace/mainline.d.ts +513 -0
- package/dist/schemas/workspace/mainline.d.ts.map +1 -0
- package/dist/schemas/workspace/mainline.js +182 -0
- package/dist/schemas/workspace/mainline.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 +34 -0
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/contract-lock.d.ts +1 -0
- package/dist/state/contract-lock.d.ts.map +1 -1
- package/dist/state/contract-lock.js +47 -1
- package/dist/state/contract-lock.js.map +1 -1
- package/dist/state/definition.d.ts +44 -20
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/definition.js.map +1 -1
- package/dist/state/fix-stance.d.ts +1 -1
- package/dist/state/fix-stance.d.ts.map +1 -1
- package/dist/state/fix-stance.js +2 -1
- package/dist/state/fix-stance.js.map +1 -1
- package/dist/state/history-state.d.ts.map +1 -1
- package/dist/state/history-state.js +7 -0
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/landed-commit.d.ts +1 -0
- package/dist/state/landed-commit.d.ts.map +1 -1
- package/dist/state/landed-commit.js +2 -0
- package/dist/state/landed-commit.js.map +1 -1
- package/dist/state/red-streak.d.ts +7 -0
- package/dist/state/red-streak.d.ts.map +1 -0
- package/dist/state/red-streak.js +11 -0
- package/dist/state/red-streak.js.map +1 -0
- 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/workspace-state.d.ts +23 -1
- package/dist/state/workspace-state.d.ts.map +1 -1
- package/dist/state/workspace-state.js +33 -3
- package/dist/state/workspace-state.js.map +1 -1
- package/dist/text/shell-regions.d.ts +1 -0
- package/dist/text/shell-regions.d.ts.map +1 -1
- package/dist/text/shell-regions.js +1 -1
- package/dist/text/shell-regions.js.map +1 -1
- package/dist/text/transcript-fold.d.ts +1 -0
- package/dist/text/transcript-fold.d.ts.map +1 -1
- package/dist/text/transcript-fold.js +24 -8
- package/dist/text/transcript-fold.js.map +1 -1
- package/package.json +42 -42
- package/src/chores/chores.ts +6 -6
- package/src/chores/index.ts +0 -1
- package/src/chores/prompt.ts +3 -2
- package/src/contracts/agent.contract.ts +14 -0
- package/src/contracts/agents.contract.ts +36 -1
- package/src/contracts/capabilities.contract.ts +2 -2
- package/src/contracts/device.contract.ts +5 -3
- package/src/contracts/offload.contract.ts +60 -0
- package/src/contracts/runner.contract.ts +7 -1
- package/src/contracts/secrets.contract.ts +2 -0
- package/src/contracts/settings.contract.ts +2 -1
- package/src/contracts/workspace.contract.ts +54 -2
- package/src/documents/conversions.ts +402 -0
- package/src/documents/index.ts +7 -0
- package/src/documents/passthrough.ts +139 -0
- package/src/documents/read.ts +114 -0
- package/src/events/agent-events.ts +5 -0
- package/src/events/child-run.test.ts +81 -0
- package/src/events/child-run.ts +73 -0
- package/src/events/errands.test.ts +22 -0
- package/src/events/errands.ts +27 -0
- package/src/events/land-breakage.ts +12 -0
- package/src/events/land-conflict.ts +12 -0
- package/src/events/requests.ts +40 -1
- package/src/events/system-events.ts +9 -3
- package/src/events/transcript.ts +8 -0
- package/src/events/verify-nudge.ts +4 -3
- package/src/front/browser-wire.ts +20 -0
- package/src/front/front-wire.ts +15 -0
- package/src/front/generated/browser-wire.json +138 -0
- package/src/front/generated/browser-wire.ts +16 -0
- package/src/front/generated/front-wire.json +793 -0
- package/src/front/generated/tunnel.json +38 -0
- package/src/front/generated/wire.ts +37 -9
- package/src/front/wire-manifests.test.ts +61 -0
- package/src/ids/conversation-ids.ts +13 -5
- package/src/ids/session-names.ts +7 -0
- package/src/index.ts +15 -2
- package/src/models/agent-catalog.test.ts +6 -4
- package/src/models/agent-catalog.ts +4 -6
- package/src/models/agent-runtimes.ts +22 -7
- package/src/models/capability-ledger.test.ts +2 -0
- package/src/models/plan-pools.test.ts +121 -2
- package/src/models/plan-pools.ts +152 -2
- package/src/policy/request-status.ts +4 -12
- package/src/policy/reserved-servers.test.ts +6 -0
- package/src/policy/reserved-servers.ts +13 -10
- package/src/policy/turned-away.ts +3 -0
- package/src/protocol/container-requirements.test.ts +2 -3
- package/src/protocol/container-requirements.ts +1 -7
- package/src/protocol/edge-verdict.ts +13 -11
- package/src/protocol/ingress-contract.fixture.json +90 -0
- package/src/protocol/ingress-contract.test.ts +18 -26
- package/src/protocol/ingress-contract.ts +10 -25
- package/src/protocol/raw-routes.ts +22 -26
- package/src/protocol/route-meta.ts +39 -0
- package/src/protocol/runner-protocol.ts +53 -0
- package/src/protocol/tunnel-bulk.test.ts +37 -0
- package/src/protocol/tunnel-bulk.ts +7 -0
- package/src/protocol/x402.test.ts +29 -0
- package/src/protocol/x402.ts +61 -0
- package/src/schemas/activity.ts +3 -1
- package/src/schemas/agent.ts +28 -3
- package/src/schemas/agents.ts +83 -8
- package/src/schemas/automations.ts +4 -2
- package/src/schemas/devices.ts +106 -39
- package/src/schemas/extension-updates.ts +6 -0
- package/src/schemas/git/git.ts +5 -0
- package/src/schemas/hosts.ts +64 -13
- package/src/schemas/ic-shape-args.test.ts +64 -0
- package/src/schemas/keep-warm.test.ts +6 -13
- package/src/schemas/keep-warm.ts +15 -20
- package/src/schemas/metrics.ts +28 -3
- package/src/schemas/offload.ts +44 -0
- package/src/schemas/personas.ts +18 -3
- package/src/schemas/ports.ts +10 -0
- package/src/schemas/providers/plan-limits.ts +84 -1
- package/src/schemas/providers/provider-oauth.ts +10 -1
- package/src/schemas/settings-history.ts +108 -0
- package/src/schemas/settings.test.ts +54 -1
- package/src/schemas/settings.ts +88 -49
- package/src/schemas/speaker.ts +89 -0
- package/src/schemas/state-plan.test.ts +69 -0
- package/src/schemas/state-plan.ts +47 -0
- package/src/schemas/system.ts +24 -3
- package/src/schemas/workspace/mainline.test.ts +28 -0
- package/src/schemas/workspace/mainline.ts +268 -0
- package/src/schemas/workspace/workspace-tree.ts +47 -0
- package/src/state/contract-lock.test.ts +65 -4
- package/src/state/contract-lock.ts +70 -2
- package/src/state/definition.ts +3 -2
- package/src/state/fix-stance.test.ts +8 -0
- package/src/state/fix-stance.ts +3 -3
- package/src/state/history-state.ts +19 -0
- package/src/state/landed-commit.test.ts +12 -1
- package/src/state/landed-commit.ts +5 -0
- package/src/state/red-streak.test.ts +28 -0
- package/src/state/red-streak.ts +28 -0
- package/src/state/runtime-state.ts +4 -0
- package/src/state/workspace-state.test.ts +7 -1
- package/src/state/workspace-state.ts +45 -3
- package/src/text/shell-regions.test.ts +38 -0
- package/src/text/shell-regions.ts +3 -3
- package/src/text/transcript-fold.test.ts +46 -0
- package/src/text/transcript-fold.ts +31 -9
- package/dist/chores/fix-deps.d.ts +0 -10
- package/dist/chores/fix-deps.d.ts.map +0 -1
- package/dist/chores/fix-deps.js +0 -18
- package/dist/chores/fix-deps.js.map +0 -1
- package/dist/protocol/ingress-protocol.d.ts +0 -30
- package/dist/protocol/ingress-protocol.d.ts.map +0 -1
- package/dist/protocol/ingress-protocol.js +0 -300
- package/dist/protocol/ingress-protocol.js.map +0 -1
- package/dist/protocol/terminal-protocol.d.ts +0 -18
- package/dist/protocol/terminal-protocol.d.ts.map +0 -1
- package/dist/protocol/terminal-protocol.js +0 -2
- package/dist/protocol/terminal-protocol.js.map +0 -1
- package/dist/protocol/tunnel-heartbeat.d.ts +0 -19
- package/dist/protocol/tunnel-heartbeat.d.ts.map +0 -1
- package/dist/protocol/tunnel-heartbeat.js +0 -41
- package/dist/protocol/tunnel-heartbeat.js.map +0 -1
- package/dist/protocol/upgrade-relay.d.ts +0 -4
- package/dist/protocol/upgrade-relay.d.ts.map +0 -1
- package/dist/protocol/upgrade-relay.js +0 -25
- package/dist/protocol/upgrade-relay.js.map +0 -1
- package/src/chores/fix-deps.ts +0 -22
- package/src/protocol/ingress-protocol.test.ts +0 -579
- package/src/protocol/ingress-protocol.ts +0 -469
- package/src/protocol/terminal-protocol.ts +0 -13
- package/src/protocol/tunnel-heartbeat.test.ts +0 -75
- package/src/protocol/tunnel-heartbeat.ts +0 -67
- package/src/protocol/upgrade-relay.ts +0 -28
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { AccountUsageSchema } from "./plan-limits.js";
|
|
2
|
+
import { AccountStateSchema, AccountUsageSchema } from "./plan-limits.js";
|
|
3
3
|
import { KeyedProviderSchema } from "./provider-subscriptions.js";
|
|
4
4
|
// Claude uses PKCE paste-back (start → exchange); Codex uses OpenAI's device-code flow (start → poll). A sandbox can
|
|
5
5
|
// hold several accounts per provider; `id` is the store key, `label` the display name. Tokens never ride this shape —
|
|
@@ -15,6 +15,12 @@ export const OauthAccountSchema = z.object({
|
|
|
15
15
|
"Who it signs in as, in the provider's own words. Kept beside the label rather than folded into it, so a renamed account can still say whose it is. Absent when the provider says nothing, which is exactly when renaming is the only answer.",
|
|
16
16
|
),
|
|
17
17
|
organization: z.string().optional().describe("Which organisation it belongs to, where the provider says."),
|
|
18
|
+
variant: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(
|
|
22
|
+
"Which of the provider's estates it signs in to, for a provider selling more than one (Z.ai's international or mainland plan). With the email and organisation, it is who the account is: a sign-in matching all three lands on this account again, same id.",
|
|
23
|
+
),
|
|
18
24
|
scope: z.string().optional().describe("What the credential is permitted to do, in the provider's terms."),
|
|
19
25
|
connectedAt: z.number().describe("When it was connected, in milliseconds."),
|
|
20
26
|
needsReauth: z
|
|
@@ -31,6 +37,9 @@ export const OauthAccountSchema = z.object({
|
|
|
31
37
|
usage: AccountUsageSchema.optional().describe(
|
|
32
38
|
"How full its plan limits were when last measured, so a picker can show what is left before committing work to it. Absent until a reading exists, which reads as unknown rather than as nothing left.",
|
|
33
39
|
),
|
|
40
|
+
state: AccountStateSchema.optional().describe(
|
|
41
|
+
"Whether it can serve a turn now, judged once from the sign-in, the seat, the provider's last refusal and the plan limits: the verdict every picker in the sandbox uses. Read this rather than the fields it was judged from. Absent from a daemon older than this field.",
|
|
42
|
+
),
|
|
34
43
|
});
|
|
35
44
|
export type OauthAccount = z.infer<typeof OauthAccountSchema>;
|
|
36
45
|
export const OauthAccountListSchema = z.object({
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { dropAll, fold, isJsonObject, mapValue, retype } from "../documents/conversions.js";
|
|
3
|
+
import type { KeepWarmSettings, RuleSchema } from "./settings.js";
|
|
4
|
+
|
|
5
|
+
// The conversions the settings shape has had, oldest first: what brings any earlier release's settings to
|
|
6
|
+
// SandboxSettingsSchema. Two documents carry this shape, the daemon's settings.json and a sandbox.toml's [settings]
|
|
7
|
+
// table, and both read through this one list; it sits beside the schema so that neither reader has to reach into the
|
|
8
|
+
// other for it. A name retired here stays retired: no later setting may take it to mean something else.
|
|
9
|
+
|
|
10
|
+
// Rules at a moment or with an action a later version withdrew (the `push.starting` moment, `instruct` actions, three
|
|
11
|
+
// built-in checks) can never run, and one of them made the whole file unreadable, every setting in it with it.
|
|
12
|
+
const RETIRED_MOMENTS: ReadonlySet<unknown> = new Set(["push.starting"]);
|
|
13
|
+
const RETIRED_ACTIONS: ReadonlySet<unknown> = new Set(["instruct"]);
|
|
14
|
+
const RETIRED_BUILTINS: ReadonlySet<unknown> = new Set(["verify-edits", "verify-removals", "verify-tests"]);
|
|
15
|
+
|
|
16
|
+
const isRetiredRule = (rule: unknown): boolean => {
|
|
17
|
+
if (!isJsonObject(rule)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const action = isJsonObject(rule["action"]) ? rule["action"] : {};
|
|
21
|
+
return RETIRED_MOMENTS.has(rule["moment"]) || RETIRED_ACTIONS.has(action["kind"]) || (action["kind"] === "builtin" && RETIRED_BUILTINS.has(action["name"]));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const holdsRetiredRule = (value: unknown): value is readonly unknown[] => Array.isArray(value) && value.some(isRetiredRule);
|
|
25
|
+
|
|
26
|
+
// A rule at the `turn.ending` moment reads and runs nothing since nothing checks inside a turn (its moment and the
|
|
27
|
+
// `verify-ui-edits` built-in stay in the read schema so a file written before reads); dropped, so it stops showing as a
|
|
28
|
+
// rule the owner has and stops travelling with the settings.
|
|
29
|
+
const isInertRule = (rule: unknown): boolean =>
|
|
30
|
+
isJsonObject(rule) &&
|
|
31
|
+
(rule["moment"] === "turn.ending" || (isJsonObject(rule["action"]) && rule["action"]["kind"] === "builtin" && rule["action"]["name"] === "verify-ui-edits"));
|
|
32
|
+
|
|
33
|
+
const holdsInertRule = (value: unknown): value is readonly unknown[] => Array.isArray(value) && value.some(isInertRule);
|
|
34
|
+
|
|
35
|
+
// keep-warm's four top-level settings (2026-09-26), folded into the one `keepWarm` object; a value of the wrong type is
|
|
36
|
+
// left out, for the schema's own default to fill.
|
|
37
|
+
const KEEP_WARM_FLAT = ["keepWarm", "keepWarmHours", "keepWarmMinTokens", "keepWarmReserve"] as const;
|
|
38
|
+
const FlatSwitch = z.boolean();
|
|
39
|
+
const FlatNumber = z.number();
|
|
40
|
+
const keepWarmObject = fold("folds keepWarm, keepWarmHours, keepWarmMinTokens and keepWarmReserve into one keepWarm object", {
|
|
41
|
+
from: KEEP_WARM_FLAT,
|
|
42
|
+
into: "keepWarm",
|
|
43
|
+
applies: (settings) => FlatSwitch.safeParse(settings["keepWarm"]).success || KEEP_WARM_FLAT.slice(1).some((key) => Object.hasOwn(settings, key)),
|
|
44
|
+
convert: ({ keepWarm, keepWarmHours, keepWarmMinTokens, keepWarmReserve }): Partial<KeepWarmSettings> => {
|
|
45
|
+
const folded: Partial<KeepWarmSettings> = {};
|
|
46
|
+
const auto = FlatSwitch.safeParse(keepWarm);
|
|
47
|
+
const hours = FlatNumber.safeParse(keepWarmHours);
|
|
48
|
+
const minTokens = FlatNumber.safeParse(keepWarmMinTokens);
|
|
49
|
+
const reserve = FlatNumber.safeParse(keepWarmReserve);
|
|
50
|
+
if (auto.success) {
|
|
51
|
+
folded.auto = auto.data;
|
|
52
|
+
}
|
|
53
|
+
if (hours.success) {
|
|
54
|
+
folded.hours = hours.data;
|
|
55
|
+
}
|
|
56
|
+
if (minTokens.success) {
|
|
57
|
+
folded.minTokens = minTokens.data;
|
|
58
|
+
}
|
|
59
|
+
if (reserve.success) {
|
|
60
|
+
folded.reserve = reserve.data;
|
|
61
|
+
}
|
|
62
|
+
return folded;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const SETTINGS_HISTORY = [
|
|
67
|
+
// Every setting a release since 2026-08-10 had and this one does not (read off the contract lock's history):
|
|
68
|
+
// retired, so passthrough stops carrying them, a definition naming one still applies, and no later setting may
|
|
69
|
+
// take one of these names to mean something else.
|
|
70
|
+
...dropAll([
|
|
71
|
+
"agentRunEffort",
|
|
72
|
+
"agentRunModel",
|
|
73
|
+
"agentRunModels",
|
|
74
|
+
"autoFastModels",
|
|
75
|
+
"autoTier",
|
|
76
|
+
"autoTierEagerness",
|
|
77
|
+
"commandJudgeModels",
|
|
78
|
+
"commandRules",
|
|
79
|
+
"contextShelf",
|
|
80
|
+
"dependencyFreshness",
|
|
81
|
+
"explainCommands",
|
|
82
|
+
"iqContext",
|
|
83
|
+
"iqContextHoldout",
|
|
84
|
+
"moveAfterLimit",
|
|
85
|
+
"quickModel",
|
|
86
|
+
"resumeAfterLimit",
|
|
87
|
+
"resumeAfterOutage",
|
|
88
|
+
"terseHoldout",
|
|
89
|
+
"terseOutput",
|
|
90
|
+
"testFaultDetection",
|
|
91
|
+
]),
|
|
92
|
+
retype(
|
|
93
|
+
"rules",
|
|
94
|
+
holdsRetiredRule,
|
|
95
|
+
// What survives the filter is every rule this version can read; the parse after the chain says so.
|
|
96
|
+
(rules) => rules.filter((rule) => !isRetiredRule(rule)) as z.input<typeof RuleSchema>[],
|
|
97
|
+
"drops rules at a withdrawn moment or with a withdrawn action (push.starting, instruct, three built-in checks)",
|
|
98
|
+
),
|
|
99
|
+
// suggest, the old default, becomes the new default: routing on.
|
|
100
|
+
mapValue("personaRouting", { off: false, suggest: true, auto: true }),
|
|
101
|
+
retype(
|
|
102
|
+
"rules",
|
|
103
|
+
holdsInertRule,
|
|
104
|
+
(rules) => rules.filter((rule) => !isInertRule(rule)) as z.input<typeof RuleSchema>[],
|
|
105
|
+
"drops rules at the retired turn.ending moment (and the verify-ui-edits built-in), which run nothing",
|
|
106
|
+
),
|
|
107
|
+
keepWarmObject,
|
|
108
|
+
] as const;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { convertDocument } from "../documents/conversions.js";
|
|
2
|
+
import { SETTINGS_HISTORY } from "./settings-history.js";
|
|
3
|
+
import { RepoChecksFileSchema, RuleSchema, SandboxSettingsSchema, SandboxSettingsWriteSchema } from "./settings.js";
|
|
2
4
|
|
|
3
5
|
// A rule that saves cleanly and silently does nothing is the failure this schema exists to refuse: an action, and a
|
|
4
6
|
// built-in's name, are checked against the moment they are written at.
|
|
@@ -57,3 +59,54 @@ describe(`where a command lives`, () => {
|
|
|
57
59
|
expect(file([{ when: `land`, run: `pnpm verify`, paths: [`src/**`] }])).toBe(false);
|
|
58
60
|
});
|
|
59
61
|
});
|
|
62
|
+
|
|
63
|
+
// Nothing runs when a turn ends any more. A file written before still reads, its conversion drops the inert rule, and no
|
|
64
|
+
// save may stand a new one there.
|
|
65
|
+
describe(`the retired turn.ending moment`, () => {
|
|
66
|
+
const look = { id: `verify-ui-edits`, label: `Look at what changed`, moment: `turn.ending`, action: { kind: `builtin`, name: `verify-ui-edits` } };
|
|
67
|
+
const land = { id: `auto-land`, label: `land`, moment: `agent.finished`, action: { kind: `verdict`, verdict: `allow` } };
|
|
68
|
+
|
|
69
|
+
test(`still reads, so an older file parses`, () => {
|
|
70
|
+
expect(SandboxSettingsSchema.safeParse({ rules: [look, land] }).success).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test(`is refused on a save`, () => {
|
|
74
|
+
const saved = SandboxSettingsWriteSchema.safeParse(SandboxSettingsSchema.parse({ rules: [look, land] }));
|
|
75
|
+
expect(saved.error?.issues.map(({ message, path }) => ({ message, path }))).toEqual([
|
|
76
|
+
{ message: `turn.ending is retired: nothing runs when a turn ends any more, so a rule cannot stand there`, path: [`rules`] },
|
|
77
|
+
]);
|
|
78
|
+
expect(SandboxSettingsWriteSchema.safeParse(SandboxSettingsSchema.parse({ rules: [land] })).success).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test(`is dropped from a stored file by its conversion, which leaves every other rule and settles`, () => {
|
|
82
|
+
const converted = convertDocument(SETTINGS_HISTORY, `object`, { rules: [look, land] }, true);
|
|
83
|
+
expect(converted.value).toEqual({ rules: [land] });
|
|
84
|
+
expect(converted.changes.map(({ conversion }) => conversion)).toEqual([
|
|
85
|
+
`drops rules at the retired turn.ending moment (and the verify-ui-edits built-in), which run nothing`,
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// keep-warm's four top-level settings became one object on 2026-09-26; a stored file keeps what its owner picked.
|
|
91
|
+
describe(`the folded keep-warm settings`, () => {
|
|
92
|
+
test(`fold into one object, keeping each value and the key's place`, () => {
|
|
93
|
+
const stored = { timezone: `Europe/Warsaw`, keepWarm: true, keepWarmHours: 6, keepWarmMinTokens: 50_000, keepWarmReserve: 20, iqSearch: true };
|
|
94
|
+
const converted = convertDocument(SETTINGS_HISTORY, `object`, stored, true);
|
|
95
|
+
expect(converted.value).toEqual({ timezone: `Europe/Warsaw`, keepWarm: { auto: true, hours: 6, minTokens: 50_000, reserve: 20 }, iqSearch: true });
|
|
96
|
+
expect(JSON.stringify(converted.value)).toBe(
|
|
97
|
+
`{"timezone":"Europe/Warsaw","keepWarm":{"auto":true,"hours":6,"minTokens":50000,"reserve":20},"iqSearch":true}`,
|
|
98
|
+
);
|
|
99
|
+
expect(SandboxSettingsSchema.parse(converted.value).keepWarm).toEqual({ auto: true, hours: 6, minTokens: 50_000, reserve: 20 });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test(`fold a file that set only some, leaving the rest to the defaults`, () => {
|
|
103
|
+
const converted = convertDocument(SETTINGS_HISTORY, `object`, { keepWarmReserve: 30 }, true);
|
|
104
|
+
expect(converted.value).toEqual({ keepWarm: { reserve: 30 } });
|
|
105
|
+
expect(SandboxSettingsSchema.parse(converted.value).keepWarm).toEqual({ auto: false, hours: 4, minTokens: 100_000, reserve: 30 });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test(`leave a file already in the new shape alone`, () => {
|
|
109
|
+
const current = { keepWarm: { auto: true, hours: 2 } };
|
|
110
|
+
expect(convertDocument(SETTINGS_HISTORY, `object`, current, true).changes).toEqual([]);
|
|
111
|
+
});
|
|
112
|
+
});
|
package/src/schemas/settings.ts
CHANGED
|
@@ -13,13 +13,15 @@ export const SystemPromptModeSchema = z.enum(["intentic", "claude", "custom"]);
|
|
|
13
13
|
export type SystemPromptMode = z.infer<typeof SystemPromptModeSchema>;
|
|
14
14
|
// Excludes "custom": there is nothing to fetch, it's whatever the owner already typed into the settings field.
|
|
15
15
|
export const BuiltinPromptSchema = z.object({ base: z.enum(["intentic", "claude"]) });
|
|
16
|
-
// Rules: "at this moment, if this is true, do this". The owner's rules decide (land, hold, version)
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// Rules: "at this moment, if this is true, do this". The owner's rules decide (land, hold, version); every command a
|
|
17
|
+
// moment runs is a repository's own check (`<repo>/.intentic/checks.json`), compiled into this same table by the daemon,
|
|
18
|
+
// so no command lives in settings. Nothing verifies inside a turn: the whole-tree check runs after work lands and never
|
|
19
|
+
// holds anything (schemas/workspace/mainline.ts).
|
|
19
20
|
export const RuleMomentSchema = z.enum([
|
|
20
21
|
// A command here runs on the just-written file (`{file}` is its path); the cheapest moment to catch a defect.
|
|
21
22
|
"file.edited",
|
|
22
|
-
//
|
|
23
|
+
// Retired: the assistant stopping. Nothing runs here any more and nothing sends a turn back to work; the value stays
|
|
24
|
+
// so settings written before it went still read, and a rule standing here is inert.
|
|
23
25
|
"turn.ending",
|
|
24
26
|
// An agent's turn is over and its delta is sitting on its branch. A rule here decides whether it lands.
|
|
25
27
|
"agent.finished",
|
|
@@ -30,7 +32,8 @@ export type RuleMoment = z.infer<typeof RuleMomentSchema>;
|
|
|
30
32
|
// command: a repository's check; its exit code is the verdict.
|
|
31
33
|
// verdict: allows or holds what is about to happen.
|
|
32
34
|
// builtin: a daemon behaviour that reads a record only the daemon keeps.
|
|
33
|
-
// verify-ui-edits:
|
|
35
|
+
// verify-ui-edits: retired with `turn.ending`, read only so older settings parse; whether a turn looked at the surfaces it
|
|
36
|
+
// changed is recorded on its card instead (AgentSummary.proof), never asked of the model.
|
|
34
37
|
// version-landed: commits what a land brought, in the main tree, under the subject drafted for it, and the tree's own
|
|
35
38
|
// remainder before the next isolated turn starts; the only way a person who never commits keeps every agent seeing
|
|
36
39
|
// the latest tree, since worktrees are cut from HEAD.
|
|
@@ -47,8 +50,8 @@ export const RuleActionSchema = z.discriminatedUnion("kind", [
|
|
|
47
50
|
z.object({ kind: z.literal("builtin"), name: RuleBuiltinSchema }),
|
|
48
51
|
]);
|
|
49
52
|
export type RuleAction = z.infer<typeof RuleActionSchema>;
|
|
50
|
-
// `checks-failed`
|
|
51
|
-
//
|
|
53
|
+
// `checks-failed` was a clean turn whose `turn.ending` check went red. Nothing produces it now that no check runs inside a
|
|
54
|
+
// turn, and a check never holds work; it stays so older rules naming it still read.
|
|
52
55
|
export const RuleOutcomeSchema = z.enum(["clean", "error", "conflict", "checks-failed"]);
|
|
53
56
|
export type RuleOutcome = z.infer<typeof RuleOutcomeSchema>;
|
|
54
57
|
// Every key absent means the rule always matches.
|
|
@@ -57,9 +60,10 @@ export const RuleConditionSchema = z.object({
|
|
|
57
60
|
repo: z.string().min(1).optional(),
|
|
58
61
|
// Globs the change has to touch for the rule to fire. Absent/empty ⇒ any.
|
|
59
62
|
paths: z.array(z.string().min(1)).max(20).optional(),
|
|
60
|
-
// How the turn ended. Absent/empty ⇒ any
|
|
63
|
+
// How the turn ended. Absent/empty ⇒ any.
|
|
61
64
|
outcome: z.array(RuleOutcomeSchema).optional(),
|
|
62
|
-
// The fraction of occasions a rule fires on, at
|
|
65
|
+
// The fraction of occasions a rule fires on, at a moment that draws one; absent ⇒ every occasion. No moment draws
|
|
66
|
+
// now that `turn.ending` is retired, so a sampled rule fires every time.
|
|
63
67
|
sample: z.number().gt(0).lt(1).optional(),
|
|
64
68
|
});
|
|
65
69
|
export type RuleCondition = z.infer<typeof RuleConditionSchema>;
|
|
@@ -94,6 +98,9 @@ export const RuleSchema = z
|
|
|
94
98
|
path: ["action"],
|
|
95
99
|
});
|
|
96
100
|
export type Rule = z.infer<typeof RuleSchema>;
|
|
101
|
+
// A rule at a retired moment or with a retired built-in: read, so an older file parses, but never written again.
|
|
102
|
+
export const isRetiredMomentRule = (rule: Pick<Rule, "moment" | "action">): boolean =>
|
|
103
|
+
rule.moment === "turn.ending" || (rule.action.kind === "builtin" && rule.action.name === "verify-ui-edits");
|
|
97
104
|
// Kept out of the settings object on purpose: a firing is not an edit, and writing config on every push would make
|
|
98
105
|
// every run a settings save.
|
|
99
106
|
export const RuleFiringsSchema = z.record(z.string(), z.number());
|
|
@@ -182,7 +189,42 @@ export type SkillSwitch = z.infer<typeof SkillSwitchSchema>;
|
|
|
182
189
|
// Opt-in settings the /settings routes edit and streamAgent reads, defaulting off so each can be A/B tested (`skills`
|
|
183
190
|
// defaults on for the baked tools worth having, since a skill file is the only thing that tells the agent a baked
|
|
184
191
|
// binary exists). Every default lives in the schema, so an older settings file still parses and keeps the owner's other
|
|
185
|
-
// picks rather than failing whole.
|
|
192
|
+
// picks rather than failing whole. A setting removed or reshaped here gets its conversion in settings-history.ts, which
|
|
193
|
+
// also names every retired setting, none of whose names may come back.
|
|
194
|
+
|
|
195
|
+
// keep-warm's knobs, one object since each only means anything beside the others (cache-keepwarm.ts).
|
|
196
|
+
export const KeepWarmSettingsSchema = z.object({
|
|
197
|
+
auto: z
|
|
198
|
+
.boolean()
|
|
199
|
+
.default(false)
|
|
200
|
+
.describe(
|
|
201
|
+
"Keep a Claude conversation's prompt cache warm after each turn a person asked for. Each refresh re-reads the cached context at the cache price and adds nothing to the conversation.",
|
|
202
|
+
),
|
|
203
|
+
hours: z
|
|
204
|
+
.number()
|
|
205
|
+
.min(1)
|
|
206
|
+
.max(8)
|
|
207
|
+
.default(4)
|
|
208
|
+
.describe(
|
|
209
|
+
"How long an idle conversation is kept warm after its last turn, in hours, and what a press on one offers first. Shortened where refreshing would cost more than the cold resume it saves, and at midnight where the agent runs, when the date in its prompt changes.",
|
|
210
|
+
),
|
|
211
|
+
minTokens: z
|
|
212
|
+
.number()
|
|
213
|
+
.int()
|
|
214
|
+
.min(0)
|
|
215
|
+
.default(100_000)
|
|
216
|
+
.describe("Only conversations at least this large, in tokens, are kept warm by `auto`: a small one is cheap to re-read anyway."),
|
|
217
|
+
reserve: z
|
|
218
|
+
.number()
|
|
219
|
+
.int()
|
|
220
|
+
.min(0)
|
|
221
|
+
.max(90)
|
|
222
|
+
.default(15)
|
|
223
|
+
.describe(
|
|
224
|
+
"How much of an account's usage limit, in percent, keeping conversations warm must leave untouched for real work. Refreshing stops once any limit that account's model spends is fuller than that.",
|
|
225
|
+
),
|
|
226
|
+
});
|
|
227
|
+
export type KeepWarmSettings = z.infer<typeof KeepWarmSettingsSchema>;
|
|
186
228
|
|
|
187
229
|
export const SandboxSettingsSchema = z.object({
|
|
188
230
|
// The zone every WALL-CLOCK RULE in this sandbox is meant in — an automation's cron, and anything else that says
|
|
@@ -387,46 +429,37 @@ export const SandboxSettingsSchema = z.object({
|
|
|
387
429
|
.describe(
|
|
388
430
|
"When a spent usage limit moves a turn to another account, carry the provider session (the model keeps everything, and re-reads all of it once on the other account) while the conversation's context is under this many tokens; at or above it, start a fresh session with the sandbox's measured brief instead. Zero always starts fresh.",
|
|
389
431
|
),
|
|
390
|
-
// Off by default: every refresh spends the account's own allowance on a conversation nobody is using yet.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
.
|
|
394
|
-
|
|
395
|
-
"Keep a Claude conversation's prompt cache warm after each turn a person asked for, so coming back to it hours later costs a cache read instead of re-sending everything. Each refresh re-reads the cached context at the cache price and adds nothing to the conversation. Any one conversation can be kept warm or let cool by hand either way.",
|
|
396
|
-
),
|
|
397
|
-
keepWarmHours: z
|
|
398
|
-
.number()
|
|
399
|
-
.min(1)
|
|
400
|
-
.max(8)
|
|
401
|
-
.default(4)
|
|
402
|
-
.describe(
|
|
403
|
-
"How long an idle conversation is kept warm after its last turn, in hours. Shortened where refreshing would cost more than the cold resume it saves, and at midnight where the agent runs, when the date in its prompt changes.",
|
|
404
|
-
),
|
|
405
|
-
keepWarmMinTokens: z
|
|
406
|
-
.number()
|
|
407
|
-
.int()
|
|
408
|
-
.min(0)
|
|
409
|
-
.default(100_000)
|
|
410
|
-
.describe("Only conversations at least this large, in tokens, are kept warm by themselves: a small one is cheap to re-read anyway."),
|
|
411
|
-
keepWarmReserve: z
|
|
412
|
-
.number()
|
|
413
|
-
.int()
|
|
414
|
-
.min(0)
|
|
415
|
-
.max(90)
|
|
416
|
-
.default(15)
|
|
417
|
-
.describe(
|
|
418
|
-
"How much of an account's usage limit, in percent, keeping conversations warm must leave untouched for real work. Refreshing stops once any limit that account's model spends is fuller than that.",
|
|
419
|
-
),
|
|
432
|
+
// Off by default: every refresh spends the account's own allowance on a conversation nobody is using yet. Before
|
|
433
|
+
// 2026-09-26 these were four top-level settings (settings-history.ts folds them).
|
|
434
|
+
keepWarm: KeepWarmSettingsSchema.prefault({}).describe(
|
|
435
|
+
"Keeping an idle conversation's prompt cache warm, so coming back to it hours later costs a cache read instead of re-sending everything. Any one conversation can be kept warm or let cool by hand whatever `auto` says.",
|
|
436
|
+
),
|
|
420
437
|
// Worth it since the container is recreated on every update or environment approval — otherwise approving a
|
|
421
438
|
// Dockerfile change costs the run that asked for it.
|
|
422
|
-
// What happens to breakage found after the work that caused it has left the turn
|
|
423
|
-
// check red
|
|
424
|
-
//
|
|
439
|
+
// What happens to breakage found after the work that caused it has left the turn. A land that turns the main tree's own
|
|
440
|
+
// check red waits for the lands queued behind it to be checked too, then goes back to the conversation that landed it
|
|
441
|
+
// while that one still has it in mind, or to a fresh conversation when nobody can be named or the one named has gone
|
|
442
|
+
// cold; main's CI staying red on one failure gets a fix agent once pushes go quiet, with a fleet failure re-run instead.
|
|
443
|
+
// Off, all of it is only reported.
|
|
425
444
|
autoRepair: z
|
|
426
445
|
.boolean()
|
|
427
446
|
.default(true)
|
|
428
447
|
.describe(
|
|
429
|
-
"Whether breakage found after the work left its turn is repaired without asking
|
|
448
|
+
"Whether breakage found after the work left its turn is repaired without asking. A land that turns the main tree's check red is repaired once the work queued behind it has been checked too: by the conversation that landed it while it still has the work in mind, otherwise by a fresh conversation handed the failures and the suspects' changes. Main's CI staying red on the same failure gets a fix agent once pushes go quiet, and a failure on the CI fleet itself is re-run once instead. Off, all of it is only reported.",
|
|
449
|
+
),
|
|
450
|
+
// Where heavy work runs: a runner (the same image, on one of the owner's machines) instead of this sandbox. Keyed by
|
|
451
|
+
// the heavy-command rule an agent's command matched (system/resources/heavy-commands.ts), and one entry for the
|
|
452
|
+
// check after landing, each naming a runner id. A runner that is offline, outdated or full hands the work back here,
|
|
453
|
+
// which the command's output says. Never pushed to a runner itself (portability/definition.ts), which must not pass
|
|
454
|
+
// work on again.
|
|
455
|
+
offload: z
|
|
456
|
+
.object({
|
|
457
|
+
commands: z.record(z.string().min(1), z.string().min(1)).default({}),
|
|
458
|
+
landCheck: z.string().min(1).optional(),
|
|
459
|
+
})
|
|
460
|
+
.default({ commands: {} })
|
|
461
|
+
.describe(
|
|
462
|
+
"Which heavy work runs on a runner on one of your machines instead of this sandbox: agents' commands by the kind the heavy-command rules sort them into (tests, typechecks, verify…), and the check after landing. The code travels as it stands, uncommitted work included; the output streams back, and any file the command changed comes back with it. A machine that is offline, outdated or busy hands the work back to this sandbox, and the output says so.",
|
|
430
463
|
),
|
|
431
464
|
autoResumeOnRestart: z
|
|
432
465
|
.boolean()
|
|
@@ -454,7 +487,7 @@ export const SandboxSettingsSchema = z.object({
|
|
|
454
487
|
message: "a command belongs in the repository's own .intentic/checks.json, not in settings",
|
|
455
488
|
})
|
|
456
489
|
.describe(
|
|
457
|
-
"Standing decisions about the sandbox's own work: land or hold finished work, save a version of what landed
|
|
490
|
+
"Standing decisions about the sandbox's own work: land or hold finished work, save a version of what landed. Empty is the default and is exactly the behaviour of a fresh sandbox, because each of those defaults is what no rule matched means at its own moment. A command to run is a repository's own check, declared in its .intentic/checks.json.",
|
|
458
491
|
),
|
|
459
492
|
automationFailureLimit: z
|
|
460
493
|
.number()
|
|
@@ -496,6 +529,12 @@ export const SandboxSettingsSchema = z.object({
|
|
|
496
529
|
.describe("How many levels deep the delegation may go, since a subagent can start subagents of its own."),
|
|
497
530
|
});
|
|
498
531
|
export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
|
|
532
|
+
// What a save takes: the settings as read, less what is only read. `turn.ending` (and its `verify-ui-edits` built-in) is
|
|
533
|
+
// retired; a file written before still parses (and its conversion drops such rules), but no save may stand a new one.
|
|
534
|
+
export const SandboxSettingsWriteSchema = SandboxSettingsSchema.refine((settings) => !settings.rules.some(isRetiredMomentRule), {
|
|
535
|
+
message: "turn.ending is retired: nothing runs when a turn ends any more, so a rule cannot stand there",
|
|
536
|
+
path: ["rules"],
|
|
537
|
+
});
|
|
499
538
|
|
|
500
539
|
// A browser telling the sandbox which clock IT is on. An offer, not an instruction: see `adoptTimezone`.
|
|
501
540
|
export const TimezoneOfferSchema = z.object({
|
|
@@ -626,9 +665,9 @@ export type SavingsReport = z.infer<typeof SavingsReportSchema>;
|
|
|
626
665
|
// spelling for the daemon that reads it, the screen that names it and the demo that mimics it.
|
|
627
666
|
export const REPO_CHECKS_FILE = `${STATE_DIR}/checks.json`;
|
|
628
667
|
|
|
629
|
-
// Named for the occasion as a repository would say it: `edit` is `file.edited`, `
|
|
630
|
-
//
|
|
631
|
-
//
|
|
668
|
+
// Named for the occasion as a repository would say it: `edit` is `file.edited`, and `land` is the daemon's run over the
|
|
669
|
+
// main tree after every land (rules/repo-checks.ts maps them). `turn` is retired: nothing runs when a turn ends any more,
|
|
670
|
+
// and a declaration naming it still reads but runs nothing. No check refuses a land, a commit or a push.
|
|
632
671
|
// `edit` runs on one file (`{file}`) and its output rides back in the edit's own response, so a command declared there is
|
|
633
672
|
// paid per edit and has to take the file.
|
|
634
673
|
export const RepoCheckMomentSchema = z.enum(["edit", "turn", "land"]);
|
|
@@ -636,7 +675,7 @@ export type RepoCheckMoment = z.infer<typeof RepoCheckMomentSchema>;
|
|
|
636
675
|
|
|
637
676
|
export const RepoCheckSchema = z.object({
|
|
638
677
|
when: RepoCheckMomentSchema.describe(
|
|
639
|
-
"When to run it: `edit` on each file as it is written (`{file}` is its path), `
|
|
678
|
+
"When to run it: `edit` on each file as it is written (`{file}` is its path), `land` on the main tree after finished work lands (absent, the package's own verify or test script runs there). `turn` is retired and runs nothing: checks no longer run while a conversation works.",
|
|
640
679
|
),
|
|
641
680
|
run: z.string().min(1).max(500).describe("The command, run in this repository's own directory, so it reads as it would in a terminal there."),
|
|
642
681
|
label: z.string().min(1).max(80).optional().describe("What to call it on screen. Absent names it after the command."),
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { MessageVoice } from "./agent.js";
|
|
3
|
+
import type { SessionOwner } from "./agents.js";
|
|
4
|
+
|
|
5
|
+
// WHO IS SPEAKING, as the sandbox verified it: one typed value every door builds once, from which the older one-line
|
|
6
|
+
// facts are derived (the message's `voice`, the turn's `actor` string, the conversation's `owner`), so no reader parses a
|
|
7
|
+
// prefix to learn whether a person is at the keyboard. Shared with transcript rows that want to say who spoke. Named apart
|
|
8
|
+
// from `Speaker` (agents.ts), which is only which side of a transcript a search snippet came from.
|
|
9
|
+
|
|
10
|
+
export const TurnSpeakerSchema = z.discriminatedUnion("kind", [
|
|
11
|
+
z.object({
|
|
12
|
+
kind: z.literal("person"),
|
|
13
|
+
email: z.string().describe("The signed-in member, as the sandbox verified them."),
|
|
14
|
+
name: z.string().optional().describe("Their display name, where the sign-in carries one."),
|
|
15
|
+
}),
|
|
16
|
+
z.object({
|
|
17
|
+
kind: z.literal("program"),
|
|
18
|
+
token: z.string().describe("The label of the control token a person minted and handed to this program."),
|
|
19
|
+
}),
|
|
20
|
+
z.object({
|
|
21
|
+
kind: z.literal("agent"),
|
|
22
|
+
conversationId: z.string().describe("The conversation whose agent is speaking: a child reporting back, a peer's message."),
|
|
23
|
+
}),
|
|
24
|
+
z.object({
|
|
25
|
+
kind: z.literal("sandbox"),
|
|
26
|
+
source: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("What in the sandbox spoke: an automation, a watch that fired, a job that ended, a repair. Absent when it does not say."),
|
|
30
|
+
}),
|
|
31
|
+
]);
|
|
32
|
+
export type TurnSpeaker = z.infer<typeof TurnSpeakerSchema>;
|
|
33
|
+
|
|
34
|
+
// Prefixed so a token labelled like an email, or a conversation id, can never read as a person.
|
|
35
|
+
const TOKEN_PREFIX = "token:";
|
|
36
|
+
const AGENT_PREFIX = "agent:";
|
|
37
|
+
|
|
38
|
+
/** The one-line attribution a turn and a queued message carry: a person's email, else the prefixed program or agent. */
|
|
39
|
+
export const speakerActor = (speaker: TurnSpeaker): string | undefined => {
|
|
40
|
+
switch (speaker.kind) {
|
|
41
|
+
case "person":
|
|
42
|
+
return speaker.email;
|
|
43
|
+
case "program":
|
|
44
|
+
return `${TOKEN_PREFIX}${speaker.token}`;
|
|
45
|
+
case "agent":
|
|
46
|
+
return `${AGENT_PREFIX}${speaker.conversationId}`;
|
|
47
|
+
case "sandbox":
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Whose words a message is: a program writes through a person's door, so it speaks with a person's voice. */
|
|
53
|
+
export const speakerVoice = (speaker: TurnSpeaker): MessageVoice =>
|
|
54
|
+
speaker.kind === "program" ? "person" : speaker.kind === "agent" ? "agent" : speaker.kind === "sandbox" ? "sandbox" : "person";
|
|
55
|
+
|
|
56
|
+
/** The member who owns what this speaker opens; a program, an agent and the sandbox own nothing, so theirs stay claimable. */
|
|
57
|
+
export const speakerOwner = (speaker: TurnSpeaker): Pick<SessionOwner, "email" | "name"> | undefined => {
|
|
58
|
+
if (speaker.kind !== "person") {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const owner: Pick<SessionOwner, "email" | "name"> = { email: speaker.email };
|
|
62
|
+
if (speaker.name !== undefined) {
|
|
63
|
+
owner.name = speaker.name;
|
|
64
|
+
}
|
|
65
|
+
return owner;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** A person, verified, at the keyboard: never a program holding a token a person minted. */
|
|
69
|
+
export const spokenByPerson = (speaker: TurnSpeaker | undefined): boolean => speaker?.kind === "person";
|
|
70
|
+
|
|
71
|
+
// WHAT A COMPOSED PROMPT IS FOR, when the sandbox or the app wrote it rather than whoever is named as speaking: a land's
|
|
72
|
+
// breakage sent back to it, a fresh fix-up on a red main line and its later nudges, a note to a conversation still
|
|
73
|
+
// working on what failed, the brief a person's press hands an agent (what a push left, main's red CI), a land conflict to
|
|
74
|
+
// resolve. Carried on the turn and the row it opens, so a reader shows it as the sandbox's words, not the owner's, and
|
|
75
|
+
// never has to recognise the prompt by its opening; the four openings older rows are recognised by stay what they are
|
|
76
|
+
// (events/errands.ts, errandOfPrompt).
|
|
77
|
+
export const TurnErrandSchema = z.enum([
|
|
78
|
+
"land-conflict",
|
|
79
|
+
"verify-nudge",
|
|
80
|
+
"land-breakage",
|
|
81
|
+
"land-fix",
|
|
82
|
+
"land-fix-nudge",
|
|
83
|
+
"land-held",
|
|
84
|
+
"push-fix",
|
|
85
|
+
"push-fix-nudge",
|
|
86
|
+
"ci-fix",
|
|
87
|
+
"ci-fix-nudge",
|
|
88
|
+
]);
|
|
89
|
+
export type TurnErrand = z.infer<typeof TurnErrandSchema>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { STATE_DIR } from "@intentic/constants";
|
|
4
|
+
import { packageRoot } from "@intentic/constants/node";
|
|
5
|
+
import { STATE_PLAN_FORMAT, type StatePlan, StatePlanSchema, type StateStatus, StateStatusSchema } from "./state-plan.js";
|
|
6
|
+
|
|
7
|
+
// The documents `ic` reads by field name, spelled once here: each golden file under golden/ is one of these examples
|
|
8
|
+
// as JSON, and the Rust tests (_sandbox/ic/src/sandbox/preflight.rs, health.rs) parse the same files. A change here
|
|
9
|
+
// that the committed file does not carry fails, naming the file; `INTENTIC_WRITE_GOLDEN=1` rewrites them, and the Rust
|
|
10
|
+
// tests then say whether ic still reads them.
|
|
11
|
+
|
|
12
|
+
const GOLDEN = join(packageRoot(import.meta.url), "golden");
|
|
13
|
+
|
|
14
|
+
const clear: StatePlan = {
|
|
15
|
+
plan: STATE_PLAN_FORMAT,
|
|
16
|
+
version: "1.400.0",
|
|
17
|
+
engine: 84,
|
|
18
|
+
digest: "c8cff51cab20a2b5",
|
|
19
|
+
ok: true,
|
|
20
|
+
downgrade: false,
|
|
21
|
+
failures: [],
|
|
22
|
+
steps: [
|
|
23
|
+
{ document: "conversations-db-schema", change: "upgrades the conversations database schema" },
|
|
24
|
+
{ document: `${STATE_DIR}/config/personas.json`, change: `moves it from ${STATE_DIR}/identities.json` },
|
|
25
|
+
],
|
|
26
|
+
converts: [
|
|
27
|
+
{ document: `${STATE_DIR}/config/settings.json`, change: "converts personaRouting from its old values", detail: '"suggest" became true' },
|
|
28
|
+
],
|
|
29
|
+
files: [`${STATE_DIR}/config/personas.json`],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const refused: StatePlan = {
|
|
33
|
+
plan: STATE_PLAN_FORMAT,
|
|
34
|
+
version: "1.400.0",
|
|
35
|
+
engine: 84,
|
|
36
|
+
digest: "c8cff51cab20a2b5",
|
|
37
|
+
ok: false,
|
|
38
|
+
downgrade: true,
|
|
39
|
+
failures: [{ document: `${STATE_DIR}/config/automations.json`, detail: 'conversion "converts numbered kinds" failed: no such kind' }],
|
|
40
|
+
steps: [],
|
|
41
|
+
converts: [],
|
|
42
|
+
files: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// The whole `/health` answer is the daemon's; ic reads only `state` out of it, so the golden carries just enough around it.
|
|
46
|
+
const health: { readonly ok: true; readonly state: StateStatus } = { ok: true, state: { journal: "open", engine: 84 } };
|
|
47
|
+
|
|
48
|
+
const goldens = [
|
|
49
|
+
{ file: "state-plan-clear.json", value: StatePlanSchema.parse(clear) },
|
|
50
|
+
{ file: "state-plan-refused.json", value: StatePlanSchema.parse(refused) },
|
|
51
|
+
{ file: "health-state.json", value: { ...health, state: StateStatusSchema.parse(health.state) } },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
test.each(goldens)("golden/$file is the contract's example, as the host reads it", ({ file, value }) => {
|
|
55
|
+
const path = join(GOLDEN, file);
|
|
56
|
+
const expected = `${JSON.stringify(value, undefined, 2)}\n`;
|
|
57
|
+
if (process.env["INTENTIC_WRITE_GOLDEN"] === "1") {
|
|
58
|
+
writeFileSync(path, expected);
|
|
59
|
+
}
|
|
60
|
+
expect(readFileSync(path, "utf8")).toBe(expected);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("a marker plan an older ic wrote, with only what it kept, still reads", () => {
|
|
64
|
+
expect(StatePlanSchema.partial().extend({ ok: StatePlanSchema.shape.ok }).parse({ ok: true, downgrade: false, steps: [{ document: "a.json", change: "renames a to b" }] })).toEqual({
|
|
65
|
+
ok: true,
|
|
66
|
+
downgrade: false,
|
|
67
|
+
steps: [{ document: "a.json", change: "renames a to b" }],
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// The daemon's state engine as the host reads it, in two documents a Rust binary (`ic`) parses by these field names:
|
|
4
|
+
// the update pre-flight's one line (the target image's state-plan.ts, read by _sandbox/ic/src/sandbox/preflight.rs and
|
|
5
|
+
// embedded verbatim in the staged-update marker), and the `state` of `/health` (read by _sandbox/ic/src/health.rs). The
|
|
6
|
+
// golden files beside the contract (golden/) are this schema's examples, and the Rust tests assert against them.
|
|
7
|
+
|
|
8
|
+
export const PlanStepSchema = z.object({
|
|
9
|
+
document: z.string().describe("The stored file, workspace-relative, or `<volume>:<path>` for one on another volume; a structural step's id."),
|
|
10
|
+
change: z.string().describe("What is done to it, in one line."),
|
|
11
|
+
detail: z.string().optional().describe("What was particular about this one: a conflict's losing value, a retired entry, a mapped value."),
|
|
12
|
+
});
|
|
13
|
+
export type PlanStep = z.infer<typeof PlanStepSchema>;
|
|
14
|
+
|
|
15
|
+
export const PlanFailureSchema = z.object({
|
|
16
|
+
document: z.string().describe("The stored file whose conversion would fail, or the structural step that would."),
|
|
17
|
+
detail: z.string().describe("Why, in the conversion's own words."),
|
|
18
|
+
});
|
|
19
|
+
export type PlanFailure = z.infer<typeof PlanFailureSchema>;
|
|
20
|
+
|
|
21
|
+
// The one format `ic` reads; any other is "no plan", never a guess at what its fields mean.
|
|
22
|
+
export const STATE_PLAN_FORMAT = 1;
|
|
23
|
+
|
|
24
|
+
export const StatePlanSchema = z.object({
|
|
25
|
+
plan: z.literal(STATE_PLAN_FORMAT).describe("The format of this line. A reader refuses any other rather than guessing at its fields."),
|
|
26
|
+
version: z.string().describe("The release of the image that planned it; 0.0.0 for a development build."),
|
|
27
|
+
engine: z.number().describe("The conversion count builds before the digest compared. Reported, never decided by."),
|
|
28
|
+
digest: z.string().describe("What identifies the planning build's conversion set: its episodes resume only under the same one."),
|
|
29
|
+
ok: z.boolean().describe("False when a conversion would fail on this sandbox's files, which refuses the update before anything is touched."),
|
|
30
|
+
downgrade: z.boolean().describe("A newer release than the planning build ran here: it opens what it cannot read read-only."),
|
|
31
|
+
failures: z.array(PlanFailureSchema).describe("Each conversion or step that would fail, and why."),
|
|
32
|
+
steps: z.array(PlanStepSchema).describe("What the first boot changes on disk: documents moved, structural steps run."),
|
|
33
|
+
converts: z
|
|
34
|
+
.array(PlanStepSchema)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("What the build's conversions change as its stores read these files, written by each store's next save. Absent from a build before it."),
|
|
37
|
+
files: z.array(z.string()).describe("Every file the first boot writes, workspace-relative where it can be."),
|
|
38
|
+
});
|
|
39
|
+
export type StatePlan = z.infer<typeof StatePlanSchema>;
|
|
40
|
+
|
|
41
|
+
// The `state` of `/health`: whether an update's state changes are still uncommitted. The host rolls an update back when
|
|
42
|
+
// the journal stays open, so this rides the same probe as the boot's progress.
|
|
43
|
+
export const StateStatusSchema = z.object({
|
|
44
|
+
journal: z.enum(["open", "none"]).describe("Open from the start of a boot that changed stored files until that boot has converged."),
|
|
45
|
+
engine: z.number().describe("The running build's conversion count."),
|
|
46
|
+
});
|
|
47
|
+
export type StateStatus = z.infer<typeof StateStatusSchema>;
|