@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,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
bindingWindow,
|
|
3
|
+
gatesModel,
|
|
4
|
+
gatingWindows,
|
|
5
|
+
headroomState,
|
|
6
|
+
preferredAccount,
|
|
7
|
+
refusalVerdict,
|
|
8
|
+
roomiestAccount,
|
|
9
|
+
scopedWindow,
|
|
10
|
+
serviceState,
|
|
11
|
+
serviceStates,
|
|
12
|
+
windowLive,
|
|
13
|
+
windowPeriod,
|
|
14
|
+
} from "./plan-pools.js";
|
|
15
|
+
import type { AccountState, AccountUsage, ProviderRefusal, UsageWindow } from "../schemas/providers/plan-limits.js";
|
|
3
16
|
|
|
4
17
|
// One rule for which pool blocks a given model, shared by the daemon and the browser: a plan can meter models
|
|
5
18
|
// separately, so the account's fullest pool need not be the model's own.
|
|
@@ -102,3 +115,109 @@ test("a reading is live until its reset, or, with none published, for one window
|
|
|
102
115
|
// And a pool whose length nothing names has only its reset instant; without one it stands.
|
|
103
116
|
expect(windowLive(window({ kind: "claude:tangelo" }), NOW - 400 * HOUR, NOW)).toBe(true);
|
|
104
117
|
});
|
|
118
|
+
|
|
119
|
+
// Serviceability: the one verdict on whether an account can serve a turn.
|
|
120
|
+
|
|
121
|
+
const at = (measuredAt: number, ...windows: UsageWindow[]): AccountUsage => ({ windows, measuredAt });
|
|
122
|
+
const refusal = (over: Partial<ProviderRefusal> & Pick<ProviderRefusal, "kind">): ProviderRefusal => ({ at: 1_000, message: "no.", ...over });
|
|
123
|
+
|
|
124
|
+
test("spent is the contract's one line: 99.5% still has room, 100% is spent until its last full pool reopens", () => {
|
|
125
|
+
expect(headroomState(usage(window({ kind: "five_hour", utilization: 99.5 })))).toEqual({ kind: "ready", room: 0.5 });
|
|
126
|
+
expect(
|
|
127
|
+
headroomState(usage(window({ kind: "five_hour", utilization: 100, resetsAt: 50 }), window({ kind: "seven_day", utilization: 100, resetsAt: 900 }))),
|
|
128
|
+
).toEqual({ kind: "spent", reopensAt: 900 });
|
|
129
|
+
expect(headroomState(usage(window({ kind: "five_hour", utilization: 100 })))).toEqual({ kind: "spent" });
|
|
130
|
+
expect(headroomState(undefined)).toEqual({ kind: "unknown" });
|
|
131
|
+
expect(headroomState(CLAUDE, { id: "claude-haiku-4-5" })).toEqual({ kind: "ready", room: 70 });
|
|
132
|
+
expect(headroomState(CLAUDE, { id: "claude-opus-4-6" })).toEqual({ kind: "spent" });
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("with no model named, an account is spent only when no model can run on it", () => {
|
|
136
|
+
// A full Opus slice leaves every other model the room of the fullest pool still open.
|
|
137
|
+
expect(headroomState(CLAUDE)).toEqual({ kind: "ready", room: 70 });
|
|
138
|
+
expect(headroomState(GOOGLE)).toEqual({ kind: "ready", room: 73 });
|
|
139
|
+
// A pool gating every model, full: nothing runs, and it reopens with that pool.
|
|
140
|
+
expect(headroomState(usage(window({ kind: "seven_day", utilization: 100, resetsAt: 900 }), window({ kind: "model:Opus", utilization: 10, gates: { models: ["Opus"] } })))).toEqual({
|
|
141
|
+
kind: "spent",
|
|
142
|
+
reopensAt: 900,
|
|
143
|
+
});
|
|
144
|
+
// Every slice full: the first to reopen lets some model run again.
|
|
145
|
+
expect(
|
|
146
|
+
headroomState(
|
|
147
|
+
usage(
|
|
148
|
+
window({ kind: "g", utilization: 100, resetsAt: 500, gates: { models: ["gemini"] } }),
|
|
149
|
+
window({ kind: "c", utilization: 100, resetsAt: 800, gates: { models: ["claude"] } }),
|
|
150
|
+
),
|
|
151
|
+
),
|
|
152
|
+
).toEqual({ kind: "spent", reopensAt: 500 });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("a revoked sign-in outranks a lost seat, which outranks a bench, whatever the meters say", () => {
|
|
156
|
+
const facts = { account: "a", usage: usage(window({ kind: "five_hour", utilization: 0 })) };
|
|
157
|
+
expect(serviceState({ ...facts, needsReauth: true, seatRefusal: "no seat" })).toEqual({ kind: "blocked", fix: "reconnect", reason: "sign-in expired" });
|
|
158
|
+
expect(serviceState({ ...facts, seatRefusal: "Your org disabled Claude Code." })).toEqual({
|
|
159
|
+
kind: "blocked",
|
|
160
|
+
fix: "admin",
|
|
161
|
+
reason: "Your org disabled Claude Code.",
|
|
162
|
+
});
|
|
163
|
+
expect(serviceState({ ...facts, cooling: { reason: "no project" } })).toEqual({ kind: "blocked", fix: "reconnect", reason: "no project" });
|
|
164
|
+
expect(serviceState({ ...facts, cooling: { until: 2_000 } }, undefined, undefined, 1_000_000)).toEqual({
|
|
165
|
+
kind: "blocked",
|
|
166
|
+
fix: "wait",
|
|
167
|
+
reason: "cooling down",
|
|
168
|
+
until: 2_000,
|
|
169
|
+
});
|
|
170
|
+
// A bench whose instant has passed is over.
|
|
171
|
+
expect(serviceState({ ...facts, cooling: { until: 999 } }, undefined, undefined, 1_000_000)).toEqual({ kind: "ready", room: 100 });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("a standing refusal blocks by its kind, and a limit refusal pins only the pool its model spends", () => {
|
|
175
|
+
const facts = { account: "a", usage: CLAUDE };
|
|
176
|
+
expect(serviceState(facts, refusal({ kind: "auth" }))).toEqual({ kind: "blocked", fix: "reconnect", reason: "no." });
|
|
177
|
+
expect(serviceState(facts, refusal({ kind: "entitlement" }))).toEqual({ kind: "blocked", fix: "admin", reason: "no." });
|
|
178
|
+
// Refused on Haiku: the 5-hour/weekly binding pool (seven_day, 30%) reads full, so Haiku is spent too.
|
|
179
|
+
expect(serviceState(facts, refusal({ kind: "limit", model: "claude-haiku-4-5" }), { id: "claude-haiku-4-5" })).toEqual({ kind: "spent" });
|
|
180
|
+
// Refused on Opus: its own slice was already full; Haiku keeps the room its pools show.
|
|
181
|
+
expect(serviceState(facts, refusal({ kind: "limit", model: "claude-opus-4-6" }), { id: "claude-haiku-4-5" })).toEqual({ kind: "ready", room: 70 });
|
|
182
|
+
// No reading at all: the refusal is the evidence, unless it was about another model.
|
|
183
|
+
expect(serviceState({ account: "a" }, refusal({ kind: "limit" }))).toEqual({ kind: "spent" });
|
|
184
|
+
expect(serviceState({ account: "a" }, refusal({ kind: "limit", model: "opus" }), { id: "haiku" })).toEqual({ kind: "unknown" });
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("a refusal stands until a later reading contradicts it, and never past its account's disconnection", () => {
|
|
188
|
+
const room = at(2_000, window({ kind: "five_hour", utilization: 40 }));
|
|
189
|
+
const full = at(2_000, window({ kind: "five_hour", utilization: 100 }));
|
|
190
|
+
const before = at(500, window({ kind: "five_hour", utilization: 40 }));
|
|
191
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [{ account: "a", usage: room }])).toBe("answered");
|
|
192
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [{ account: "a", usage: full }])).toBe("standing");
|
|
193
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [{ account: "a", usage: before }])).toBe("standing");
|
|
194
|
+
// Another account's room proves nothing about the one refused.
|
|
195
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [{ account: "a", usage: before }, { account: "b", usage: room }])).toBe("standing");
|
|
196
|
+
// A refusal naming no account is answered by any of them.
|
|
197
|
+
expect(refusalVerdict(refusal({ kind: "limit" }), [{ account: "a", usage: before }, { account: "b", usage: room }])).toBe("answered");
|
|
198
|
+
expect(refusalVerdict(refusal({ kind: "auth", account: "a" }), [{ account: "a", usage: full }])).toBe("answered");
|
|
199
|
+
expect(refusalVerdict(refusal({ kind: "auth", account: "a" }), [{ account: "a", usage: full, needsReauth: true }])).toBe("standing");
|
|
200
|
+
expect(refusalVerdict(refusal({ kind: "entitlement", account: "a" }), [{ account: "a", usage: room }])).toBe("standing");
|
|
201
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "gone" }), [{ account: "a", usage: room }])).toBe("gone");
|
|
202
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [])).toBe("standing");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("a provider's accounts are judged together: a standing refusal lands only on the account it names", () => {
|
|
206
|
+
const room = at(500, window({ kind: "five_hour", utilization: 40 }));
|
|
207
|
+
const states = serviceStates([{ account: "a", usage: room }, { account: "b", usage: room }], refusal({ kind: "entitlement", account: "a" }));
|
|
208
|
+
expect(Object.fromEntries(states)).toEqual({ a: { kind: "blocked", fix: "admin", reason: "no." }, b: { kind: "ready", room: 60 } });
|
|
209
|
+
const answered = serviceStates([{ account: "a", usage: at(2_000, window({ kind: "five_hour", utilization: 40 })) }], refusal({ kind: "limit", account: "a" }));
|
|
210
|
+
expect(answered.get("a")).toEqual({ kind: "ready", room: 60 });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("an unnamed turn takes the most room, then an unmeasured account, then a spent one, and a blocked one only when that is all", () => {
|
|
214
|
+
const entry = (id: string, state: AccountState) => ({ id, state });
|
|
215
|
+
const blocked: AccountState = { kind: "blocked", fix: "admin", reason: "no seat" };
|
|
216
|
+
expect(preferredAccount([entry("seatless", blocked), entry("spent", { kind: "spent" }), entry("low", { kind: "ready", room: 5 }), entry("high", { kind: "ready", room: 60 })])?.id).toBe("high");
|
|
217
|
+
expect(preferredAccount([entry("seatless", blocked), entry("spent", { kind: "spent" }), entry("unread", { kind: "unknown" })])?.id).toBe("unread");
|
|
218
|
+
expect(preferredAccount([entry("seatless", blocked), entry("spent", { kind: "spent" })])?.id).toBe("spent");
|
|
219
|
+
expect(preferredAccount([entry("seatless", blocked), entry("other", blocked)])?.id).toBe("seatless");
|
|
220
|
+
expect(preferredAccount([entry("first", { kind: "ready", room: 60 }), entry("second", { kind: "ready", room: 60 })])?.id).toBe("first");
|
|
221
|
+
expect(roomiestAccount([entry("seatless", blocked), entry("unread", { kind: "unknown" })])).toBeUndefined();
|
|
222
|
+
expect(roomiestAccount([entry("low", { kind: "ready", room: 5 }), entry("high", { kind: "ready", room: 60 })])?.id).toBe("high");
|
|
223
|
+
});
|
package/src/models/plan-pools.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { AccountUsage, UsageWindow, WindowGates } from "../schemas/providers/plan-limits.js";
|
|
1
|
+
import type { AccountState, AccountUsage, ProviderRefusal, UsageWindow, WindowGates } from "../schemas/providers/plan-limits.js";
|
|
2
2
|
|
|
3
3
|
// Single reading of which account pool gates a given model (or, with none named, the account's tightest pool), shared
|
|
4
4
|
// by the daemon's picker/refusal logic and the browser's rings and rail. A pool gated `none` is excluded from the
|
|
5
5
|
// no-model case: visible to the account, never a gate on a turn.
|
|
6
6
|
|
|
7
|
-
// 100 = exhaustion (the call will be refused)
|
|
7
|
+
// 100 = exhaustion (the call will be refused). The one spent line: the daemon's pickers and every surface read it, and
|
|
8
|
+
// anything short of it still has room.
|
|
8
9
|
export const SPENT_UTILIZATION = 100;
|
|
9
10
|
|
|
10
11
|
export interface ModelRef {
|
|
@@ -132,3 +133,152 @@ export const windowLive = (window: UsageWindow, measuredAt: number, now: number)
|
|
|
132
133
|
const period = windowPeriod(window);
|
|
133
134
|
return period === undefined || measuredAt + period.seconds * 1000 > now;
|
|
134
135
|
};
|
|
136
|
+
|
|
137
|
+
// Whether an account can serve a turn: the one rule every picker and surface reads (AccountState). The daemon runs it and
|
|
138
|
+
// publishes the verdict on each account row; the editor runs it only on a row from a daemon older than that field.
|
|
139
|
+
|
|
140
|
+
/** Everything the serviceability rule reads of one account, as the account rows already carry it. */
|
|
141
|
+
export interface ServiceFacts {
|
|
142
|
+
// The daemon's key: a native account's id, a routed credential's auth-file name.
|
|
143
|
+
readonly account: string;
|
|
144
|
+
readonly needsReauth?: boolean | undefined;
|
|
145
|
+
// Why the sign-in needs renewing, where the provider said.
|
|
146
|
+
readonly detail?: string | undefined;
|
|
147
|
+
readonly seatRefusal?: string | undefined;
|
|
148
|
+
readonly cooling?: { readonly until?: number | undefined; readonly reason?: string | undefined } | undefined;
|
|
149
|
+
readonly usage?: AccountUsage | undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// A spent allowance is over once a reading with room lands after it; a refused credential once any reading does (the
|
|
153
|
+
// token worked). Nothing a reading says answers an entitlement refusal: a seatless account authenticates and reads fine.
|
|
154
|
+
const answers = (refusal: ProviderRefusal, facts: ServiceFacts): boolean => {
|
|
155
|
+
const measuredAt = facts.usage?.measuredAt;
|
|
156
|
+
if (refusal.kind === "entitlement" || measuredAt === undefined || measuredAt <= refusal.at) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
if (refusal.kind === "auth") {
|
|
160
|
+
return facts.needsReauth !== true;
|
|
161
|
+
}
|
|
162
|
+
const binding = bindingWindow(facts.usage);
|
|
163
|
+
return binding !== undefined && binding.utilization < SPENT_UTILIZATION;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* How a provider's last refusal stands against everything read since, over every account the provider holds: `gone` once
|
|
168
|
+
* the account it named is disconnected, `answered` once that account (or, for a refusal naming none, any account) has a
|
|
169
|
+
* later reading that contradicts it, else `standing`. An empty list is one not loaded yet, so the refusal stands.
|
|
170
|
+
*/
|
|
171
|
+
export const refusalVerdict = (refusal: ProviderRefusal, accounts: readonly ServiceFacts[]): "standing" | "answered" | "gone" => {
|
|
172
|
+
const named = accounts.filter((facts) => facts.account === refusal.account);
|
|
173
|
+
if (refusal.account !== undefined && named.length === 0) {
|
|
174
|
+
return accounts.length === 0 ? "standing" : "gone";
|
|
175
|
+
}
|
|
176
|
+
return (refusal.account === undefined ? accounts : named).some((facts) => answers(refusal, facts)) ? "answered" : "standing";
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// The account reopens for this question when the pools holding it shut do: all of them for a model's own question (or
|
|
180
|
+
// the pools gating every model), the first to reopen when only per-model slices are full. Unknown if any is unpublished.
|
|
181
|
+
const reopening = (full: readonly UsageWindow[], first: boolean): number | undefined => {
|
|
182
|
+
const resets = full.flatMap((window) => (window.resetsAt === undefined ? [] : [window.resetsAt]));
|
|
183
|
+
return resets.length === full.length && resets.length > 0 ? (first ? Math.min(...resets) : Math.max(...resets)) : undefined;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const spent = (reopensAt: number | undefined): AccountState => (reopensAt === undefined ? { kind: "spent" } : { kind: "spent", reopensAt });
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* The plan-limit half of the verdict, at the contract's one spent line. With a model, the pools that model spends: spent
|
|
190
|
+
* once any is full, else the room the fullest leaves. With none, whether the account can serve SOME turn: spent once a
|
|
191
|
+
* pool gating every model is full, or every per-model slice is; a full slice alone (Opus at 100%) leaves the other
|
|
192
|
+
* models their room, which is then read off the fullest pool still open.
|
|
193
|
+
*/
|
|
194
|
+
export const headroomState = (usage: AccountUsage | undefined, model?: ModelRef): AccountState => {
|
|
195
|
+
const windows = gatingWindows(usage, model);
|
|
196
|
+
if (windows.length === 0) {
|
|
197
|
+
return { kind: "unknown" };
|
|
198
|
+
}
|
|
199
|
+
const full = windows.filter((window) => window.utilization >= SPENT_UTILIZATION);
|
|
200
|
+
const open = windows.filter((window) => window.utilization < SPENT_UTILIZATION);
|
|
201
|
+
if (model !== undefined || full.some((window) => window.gates === "all") || open.length === 0) {
|
|
202
|
+
const holding = model !== undefined ? full : full.some((window) => window.gates === "all") ? full.filter((window) => window.gates === "all") : full;
|
|
203
|
+
if (holding.length > 0) {
|
|
204
|
+
return spent(reopening(holding, model === undefined && !holding.some((window) => window.gates === "all")));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { kind: "ready", room: SPENT_UTILIZATION - Math.max(...open.map((window) => window.utilization)) };
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// A standing limit refusal reads its pool as full, since a polled reading freezes the moment a pool actually empties: the
|
|
211
|
+
// pool the refused turn's model spends, else the one asked about, else the tightest. Never another model's allowance.
|
|
212
|
+
const refusedPool = (usage: AccountUsage | undefined, refusal: ProviderRefusal, model: ModelRef | undefined): AccountState => {
|
|
213
|
+
const refusedModel = refusal.model === undefined ? model : { id: refusal.model };
|
|
214
|
+
const binding = bindingWindow(usage, refusedModel);
|
|
215
|
+
if (usage === undefined || binding === undefined) {
|
|
216
|
+
// No pool to pin: the refusal itself is the evidence, unless it was about a different model than this question.
|
|
217
|
+
const sameModel = refusal.model === undefined || model === undefined || refusal.model === model.id;
|
|
218
|
+
return sameModel ? { kind: "spent" } : headroomState(usage, model);
|
|
219
|
+
}
|
|
220
|
+
const pinned = usage.windows.map((window) => (window === binding ? { ...window, utilization: Math.max(window.utilization, SPENT_UTILIZATION) } : window));
|
|
221
|
+
return headroomState({ ...usage, windows: pinned }, model);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* One account's verdict. `refusal` is the provider's last refusal only when it still stands and covers this account
|
|
226
|
+
* (serviceStates decides that). Precedence: a revoked sign-in outranks a lost seat (reconnecting fixes one, nothing here
|
|
227
|
+
* fixes the other), both outrank a standing refusal, then a translator bench, then the plan limits.
|
|
228
|
+
*/
|
|
229
|
+
export const serviceState = (facts: ServiceFacts, refusal?: ProviderRefusal, model?: ModelRef, now: number = Date.now()): AccountState => {
|
|
230
|
+
if (facts.needsReauth === true) {
|
|
231
|
+
return { kind: "blocked", fix: "reconnect", reason: facts.detail ?? "sign-in expired" };
|
|
232
|
+
}
|
|
233
|
+
if (facts.seatRefusal !== undefined) {
|
|
234
|
+
return { kind: "blocked", fix: "admin", reason: facts.seatRefusal };
|
|
235
|
+
}
|
|
236
|
+
if (refusal?.kind === "auth") {
|
|
237
|
+
return { kind: "blocked", fix: "reconnect", reason: refusal.message };
|
|
238
|
+
}
|
|
239
|
+
if (refusal?.kind === "entitlement") {
|
|
240
|
+
return { kind: "blocked", fix: "admin", reason: refusal.message };
|
|
241
|
+
}
|
|
242
|
+
const cooling = facts.cooling;
|
|
243
|
+
// A bench with no instant is one no wait lifts (a Google account with no project): somebody has to connect again.
|
|
244
|
+
if (cooling !== undefined && cooling.until === undefined) {
|
|
245
|
+
return { kind: "blocked", fix: "reconnect", reason: cooling.reason ?? "benched by the translator" };
|
|
246
|
+
}
|
|
247
|
+
if (cooling?.until !== undefined && cooling.until * 1000 > now) {
|
|
248
|
+
return { kind: "blocked", fix: "wait", reason: cooling.reason ?? "cooling down", until: cooling.until };
|
|
249
|
+
}
|
|
250
|
+
return refusal?.kind === "limit" ? refusedPool(facts.usage, refusal, model) : headroomState(facts.usage, model);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/** Every account of one provider, judged together, since a refusal naming no account is answered by any of them. */
|
|
254
|
+
export const serviceStates = (
|
|
255
|
+
accounts: readonly ServiceFacts[],
|
|
256
|
+
refusal: ProviderRefusal | undefined,
|
|
257
|
+
model?: ModelRef,
|
|
258
|
+
now: number = Date.now(),
|
|
259
|
+
): ReadonlyMap<string, AccountState> => {
|
|
260
|
+
const standing = refusal !== undefined && refusalVerdict(refusal, accounts) === "standing" ? refusal : undefined;
|
|
261
|
+
return new Map(
|
|
262
|
+
accounts.map((facts) => [
|
|
263
|
+
facts.account,
|
|
264
|
+
serviceState(facts, standing !== undefined && (standing.account ?? facts.account) === facts.account ? standing : undefined, model, now),
|
|
265
|
+
]),
|
|
266
|
+
);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Worst last: proven room, no reading either way, known spent, and nothing a turn can run on.
|
|
270
|
+
const PREFERENCE: Record<AccountState["kind"], number> = { ready: 0, unknown: 1, spent: 2, blocked: 3 };
|
|
271
|
+
|
|
272
|
+
/** The account an unnamed turn runs on: ready by most room, then unmeasured, then spent, blocked only when that is all there is. Ties keep the caller's order. */
|
|
273
|
+
export const preferredAccount = <T extends { readonly state: AccountState }>(entries: readonly T[]): T | undefined =>
|
|
274
|
+
entries.reduce<T | undefined>((best, next) => {
|
|
275
|
+
if (best === undefined) {
|
|
276
|
+
return next;
|
|
277
|
+
}
|
|
278
|
+
const tier = PREFERENCE[next.state.kind] - PREFERENCE[best.state.kind];
|
|
279
|
+
return tier < 0 || (tier === 0 && next.state.kind === "ready" && best.state.kind === "ready" && next.state.room > best.state.room) ? next : best;
|
|
280
|
+
}, undefined);
|
|
281
|
+
|
|
282
|
+
/** The roomiest account with proven room, or none: what a move off a refused account may land on. Ties keep the caller's order. */
|
|
283
|
+
export const roomiestAccount = <T extends { readonly state: AccountState }>(entries: readonly T[]): T | undefined =>
|
|
284
|
+
preferredAccount(entries.filter((entry) => entry.state.kind === "ready"));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { REQUEST_FIELDS, type RequestField, type TranscriptRequests, type TranscriptRow } from "../events/transcript.js";
|
|
2
2
|
import type { AgentReply } from "../schemas/providers/plan-limits.js";
|
|
3
|
+
import { startedChildCard } from "../events/child-run.js";
|
|
3
4
|
|
|
4
5
|
// How a reply settles the card it answers: one rule used both by the fold and by a chat freezing its own card
|
|
5
6
|
// optimistically before the frame returns. No reply (turn stopped or died) reads as cancelled for every card; a reply
|
|
@@ -22,7 +23,7 @@ export const settledRequests = (cards: TranscriptRequests, reply: AgentReply | u
|
|
|
22
23
|
}
|
|
23
24
|
if (permission !== undefined) {
|
|
24
25
|
out.permission = {
|
|
25
|
-
...permission,
|
|
26
|
+
...startedChildCard(permission, reply),
|
|
26
27
|
status:
|
|
27
28
|
reply?.kind !== "permission"
|
|
28
29
|
? "cancelled"
|
|
@@ -65,16 +66,7 @@ export const settledRequests = (cards: TranscriptRequests, reply: AgentReply | u
|
|
|
65
66
|
export const cancelledRequests = (cards: TranscriptRequests): TranscriptRequests => {
|
|
66
67
|
const out: Cards = {};
|
|
67
68
|
let changed = false;
|
|
68
|
-
for (const field of
|
|
69
|
-
"plan",
|
|
70
|
-
"question",
|
|
71
|
-
"permission",
|
|
72
|
-
"browserHelp",
|
|
73
|
-
"terminalHelp",
|
|
74
|
-
"capabilityOffer",
|
|
75
|
-
"paymentOffer",
|
|
76
|
-
"credentialOffer",
|
|
77
|
-
] as const) {
|
|
69
|
+
for (const field of REQUEST_FIELDS) {
|
|
78
70
|
const card = cards[field];
|
|
79
71
|
if (card === undefined) {
|
|
80
72
|
continue;
|
|
@@ -24,6 +24,12 @@ describe("reserved MCP server names", () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
describe("collidesWithReservedServer", () => {
|
|
27
|
+
// Derived from the manifest schema's meanings: a cli card mints a server when it serves tools, a device and a
|
|
28
|
+
// connected browser always do, and `mcp` is the core kind that is its own endpoint.
|
|
29
|
+
test("the minting kinds are exactly the ones whose id becomes a server name", () => {
|
|
30
|
+
expect([...MCP_SERVER_MINTING_KINDS].toSorted()).toEqual(["cli", "device", "mcp", "webext"]);
|
|
31
|
+
});
|
|
32
|
+
|
|
27
33
|
test("a kind whose id becomes a server name may not reuse a reserved one", () => {
|
|
28
34
|
for (const kind of MCP_SERVER_MINTING_KINDS) {
|
|
29
35
|
for (const name of RESERVED_MCP_SERVER_NAMES) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { contributedServerMintingKinds } from "@intentic/extension-manifest";
|
|
2
|
+
// The MCP servers the daemon mounts under its own names, and whether each carries content from outside this container.
|
|
2
3
|
// One source of truth: the outside-content guard's exemption list is the `control` subset of this, and a capability
|
|
3
4
|
// whose id would become `mcp__<id>__…` is refused when the id is one of these, so nothing the owner configures can
|
|
4
5
|
// shadow a daemon server. A daemon server's name is what reaches the model as the `mcp__<name>__` prefix.
|
|
@@ -8,9 +9,9 @@
|
|
|
8
9
|
// - outside: the server carries content from beyond the container (a web page, a provider's verbatim sentence)
|
|
9
10
|
export type ServerProvenance = "control" | "outside";
|
|
10
11
|
|
|
11
|
-
// Every server agent/run/agent.ts and agent/run/harness/harness-servers.ts mount themselves
|
|
12
|
-
// names (web, browser)
|
|
13
|
-
// text scan. A server added anywhere else without a row here fails the conformance test in the sandbox guard package.
|
|
12
|
+
// Every server agent/run/agent.ts and agent/run/harness/harness-servers.ts mount themselves, plus the browser router's two
|
|
13
|
+
// names (web, browser), which every turn mounts on its lease at the daemon's MCP door (browser-tools.ts) and which the
|
|
14
|
+
// text scan reads from their constants. A server added anywhere else without a row here fails the conformance test in the sandbox guard package.
|
|
14
15
|
export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
|
|
15
16
|
ui: "control", // agent.ts: AskUserQuestion
|
|
16
17
|
accounts: "control", // agent.ts: the account roster and the credential typists
|
|
@@ -22,8 +23,8 @@ export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
|
|
|
22
23
|
watch: "control", // harness: condition watches
|
|
23
24
|
deps: "control", // harness: dependency readiness
|
|
24
25
|
diagnostics: "outside", // harness: two tools relay a provider's own sentence verbatim
|
|
25
|
-
web: "outside", //
|
|
26
|
-
browser: "outside", //
|
|
26
|
+
web: "outside", // the turn's mounts: the anonymous browser router; the page is the internet
|
|
27
|
+
browser: "outside", // the turn's mounts: the signed-in browser router; the page is the internet
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
// Every daemon-mounted server name, the set a capability id may not collide with.
|
|
@@ -37,10 +38,12 @@ export const CONTROL_MCP_SERVERS: ReadonlySet<string> = new Set(
|
|
|
37
38
|
.map(([name]) => name),
|
|
38
39
|
);
|
|
39
40
|
|
|
40
|
-
// Capability kinds whose id becomes an MCP server name for the turn
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
41
|
+
// Capability kinds whose id becomes an MCP server name for the turn, and so whose id must not collide with a daemon
|
|
42
|
+
// server: `mcp`, a core kind that is its own endpoint, and every contributable kind the manifest schema says mints one
|
|
43
|
+
// (a device's and a connected browser's peer bridge, a cli card that serves tools), read off the schema's own meaning
|
|
44
|
+
// (`contributedServerMintingKinds`), so a kind that starts minting is refused here without a second list. Other kinds
|
|
45
|
+
// mint accounts, providers or infrastructure, never a `mcp__<id>__` server keyed by the id.
|
|
46
|
+
export const MCP_SERVER_MINTING_KINDS: ReadonlySet<string> = new Set(["mcp", ...contributedServerMintingKinds()]);
|
|
44
47
|
|
|
45
48
|
// Whether adding or renaming a capability of this kind to this id would shadow a daemon server. The one predicate the
|
|
46
49
|
// capability routes consult, so the refusal and this list can't drift.
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
// A set rather than a run of case labels: what they share is a fact about the turn, not a shape.
|
|
6
6
|
const TURNED_AWAY: ReadonlySet<string> = new Set([
|
|
7
7
|
"claude-reauth",
|
|
8
|
+
// An organisation turned the account's Claude Code access off, or no account of the provider can serve: the next
|
|
9
|
+
// turn is routed off it (the daemon's blocked-account route), so the words wait for it rather than being spent.
|
|
10
|
+
"claude-not-entitled",
|
|
8
11
|
"unknown-command",
|
|
9
12
|
"context-window-too-small",
|
|
10
13
|
"sandbox-memory-low",
|
|
@@ -38,9 +38,8 @@ describe(`containerDrift`, () => {
|
|
|
38
38
|
expect(containerDrift({ SANDBOX_PUBLIC_URL: `` })).toEqual([]);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
expect(containerDrift({ SANDBOX_PUBLIC_URL: CURRENT.SANDBOX_PUBLIC_URL, SANDBOX_VM: `1` })).toEqual([]);
|
|
41
|
+
it(`holds a hosted machine to the same grant, since it dials the edge like any sandbox`, () => {
|
|
42
|
+
expect(containerDrift({ SANDBOX_PUBLIC_URL: CURRENT.SANDBOX_PUBLIC_URL, SANDBOX_VM: `1` }).map((gap) => gap.key)).toEqual([`reachability`]);
|
|
44
43
|
});
|
|
45
44
|
});
|
|
46
45
|
|
|
@@ -7,8 +7,6 @@ export interface ContainerRequirement {
|
|
|
7
7
|
readonly requires: readonly string[];
|
|
8
8
|
// Absent `given` evidence means this sandbox never had the capability: not a fault, just unconfigured.
|
|
9
9
|
readonly given: readonly string[];
|
|
10
|
-
// Row stays silent if any `unless` key is present: an alternate mechanism already satisfies the evidence.
|
|
11
|
-
readonly unless?: readonly string[];
|
|
12
10
|
readonly enables: string;
|
|
13
11
|
readonly lost: string;
|
|
14
12
|
readonly repair: string;
|
|
@@ -25,8 +23,6 @@ export const CONTAINER_REQUIREMENTS: readonly ContainerRequirement[] = [
|
|
|
25
23
|
key: "reachability",
|
|
26
24
|
requires: ["SANDBOX_GRANT", "INGRESS_URL"],
|
|
27
25
|
given: ["SANDBOX_PUBLIC_URL"],
|
|
28
|
-
// A Fly microVM's edge replays directly to it, so it holds no grant by design.
|
|
29
|
-
unless: ["SANDBOX_VM"],
|
|
30
26
|
enables: "reaching this sandbox at its public address, from anywhere",
|
|
31
27
|
lost:
|
|
32
28
|
"Its public address answers 502 to everyone, including this browser when it is not on the same machine as the sandbox. " +
|
|
@@ -45,9 +41,7 @@ export interface ContainerGap {
|
|
|
45
41
|
|
|
46
42
|
/** Empty means every requirement is met or not applicable; non-empty always means a setup rerun is needed. */
|
|
47
43
|
export const containerDrift = (env: ContainerEnv): readonly ContainerGap[] =>
|
|
48
|
-
CONTAINER_REQUIREMENTS.filter(
|
|
49
|
-
(requirement) => requirement.given.every((name) => present(env, name)) && !(requirement.unless ?? []).some((name) => present(env, name)),
|
|
50
|
-
)
|
|
44
|
+
CONTAINER_REQUIREMENTS.filter((requirement) => requirement.given.every((name) => present(env, name)))
|
|
51
45
|
.map((requirement) => ({
|
|
52
46
|
key: requirement.key,
|
|
53
47
|
missing: requirement.requires.filter((name) => !present(env, name)),
|
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
// JavaScript unless the responder allows it — so the verdict rides an exposed header and the edge CORS-allows its own
|
|
4
4
|
// errors. Ingress writes it, the editor's connection machine reads it; both sides import this file so they cannot drift.
|
|
5
5
|
|
|
6
|
+
import type { EdgeVerdict } from "../front/generated/browser-wire.js";
|
|
7
|
+
|
|
6
8
|
export const EDGE_VERDICT_HEADER = "x-intentic-edge";
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
// The verdicts themselves are the edge's (browser-wire's `EdgeVerdict`), each documented there:
|
|
11
|
+
// - no-tunnel: no tunnel is registered for this sandbox, and retrying is right, since a container that comes back redials
|
|
12
|
+
// within seconds;
|
|
13
|
+
// - unknown-sandbox: the platform has no such sandbox, and nothing the reader waits for can change that;
|
|
14
|
+
// - dropped: a tunnel was held and the forward failed mid-flight.
|
|
15
|
+
export type { EdgeVerdict };
|
|
16
|
+
|
|
17
|
+
// Every verdict, so a new one in the Rust enum fails this file's typecheck until it is read here too.
|
|
18
|
+
const VERDICTS: ReadonlySet<string> = new Set(
|
|
19
|
+
Object.keys({ "no-tunnel": true, "unknown-sandbox": true, dropped: true } satisfies Record<EdgeVerdict, true>),
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
// A header value only counts when it is one of ours: a 502 from anything else on the path (a corporate proxy, a CDN)
|
|
21
23
|
// carries no verdict and must not be read as one.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"publicKey": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAfiMlxPB/8tnjh6TYS3rVde63OXB/wY77KWWtJ39XjBg=\n-----END PUBLIC KEY-----\n",
|
|
3
|
+
"grants": [
|
|
4
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": {"sandboxId": "abcdef012345", "issuedAt": 1700000000} },
|
|
5
|
+
{ "token": "ig1.eyJzdWIiOiIwMTIzNDU2Nzg5YWIiLCJpYXQiOjE3NTcwMDAwMDAsImV4dHJhIjoiaWdub3JlZCJ9.NK2BR2L_ycCACdmnbZgkg7sovw-Nhlt5vIL6ldArAx_jN9XOh-k1wisviROAgU40YGBgUASIgA6Wdn5SyYHHCA", "claim": {"sandboxId": "0123456789ab", "issuedAt": 1757000000} },
|
|
6
|
+
{ "token": "ig1.eyJpYXQiOjE3MDAwMDAwMDAsInN1YiI6ImFiY2RlZjAxMjM0NSJ9.AenzYQn3Opfc-Sg_vkBrMEIOnCFZ3a46oSzjABAWyoVe3GP0vXlIM8MFgddHDQc7yow4kdfn1kHcUcsOoKkLCg", "claim": {"sandboxId": "abcdef012345", "issuedAt": 1700000000} },
|
|
7
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wNpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": null },
|
|
8
|
+
{ "token": "ig1.eiJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": null },
|
|
9
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.Ac2ofn7IxD3M51pchXEycOPg4TP_kiTzu-aTVowDLTirjVzYrvfJ-ntrzPbQg-3RpBhmc53yP7s7iWyOgGWuAw", "claim": null },
|
|
10
|
+
{ "token": "ig2.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": null },
|
|
11
|
+
{ "token": "eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": null },
|
|
12
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA.wdpBpqmMl21mqAZvRSYi4WfDejreTKDxHfOQp_sBKOTQB0_N2trL6iFcRxFUDrGBnGHmYnv-x66FgU_j57ZECA", "claim": null },
|
|
13
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.", "claim": null },
|
|
14
|
+
{ "token": "", "claim": null },
|
|
15
|
+
{ "token": "ig1", "claim": null },
|
|
16
|
+
{ "token": "ig1..", "claim": null },
|
|
17
|
+
{ "token": "ig1.%%%.%%%", "claim": null },
|
|
18
|
+
{ "token": "ig1.eyJzdWIiOiJBQkNERUYwMTIzNDUiLCJpYXQiOjE3MDAwMDAwMDB9.CbPEciFki-GXJnUcS5F9_9uXUOw5tWhv3iS69BjuQpSmsA72_xnvYUIjhAMiBPI98XBQ9-zKc9GSPJIFGQqaDA", "claim": null },
|
|
19
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNCIsImlhdCI6MTcwMDAwMDAwMH0.qfJbxpVtbcymaweaCu9fUounkldkMy4HSdllEDlHs5Yq8b11XxiHLguDyvqubXcMGCuVVygCeg2MjU3i0vEuDA", "claim": null },
|
|
20
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUiLCJpYXQiOiIxNzAwMDAwMDAwIn0.BI6UT1aTaN01bGZyI9SHc_qIf9S-JlpmNtiBd8by_giZCq8pQIJCBKIutYZW0mmqCF0YHf0NHc9icq1h9Wr7BA", "claim": null },
|
|
21
|
+
{ "token": "ig1.eyJzdWIiOiJhYmNkZWYwMTIzNDUifQ.Aa5FeLKazhsr2IvYZ2p5BJmLL1qvQWReXeCKt5gxCq9PqSaAnn8Pa6PJp0jiaXY5FIbc_S9MFrUCeEfQ6vnkBQ", "claim": null },
|
|
22
|
+
{ "token": "ig1.eyJzdWIiOjEyMzQ1Njc4OTAxMiwiaWF0IjoxNzAwMDAwMDAwfQ.kb_lMTBvFS4nzTmqLf-T7l9IF8PHaPPkP5HB1T0yd0IRWqYJnIZH2eoKexv7e6aA2PkqCpe-B1FL8Nbu4qPvDg", "claim": null },
|
|
23
|
+
{ "token": "ig1.bm90IGpzb24.Ffec27cYSbvKvjlxtSUIFFX7sGo3Zp4BxotW02rFwcJHfJikM51Zfzn3_0Rg8coR4y43iOUA2u-ZOcBJg4mmDA", "claim": null },
|
|
24
|
+
{ "token": "ig1.bnVsbA.lFa3FNSkMcf3WCyjdb87YRVdt8h3aSzt4cignx9Rkwq6drwl12m0rlrmzdPkLjsdrQdL1oWZ2E2MGuo2CMeSBw", "claim": null },
|
|
25
|
+
{ "token": "ig1.WyJhYmNkZWYwMTIzNDUiLDE3MDAwMDAwMDBd.BWFTD0bHKDBAEWwhYq6F-cWo_HXEC8UvDWkrTmafOycvTZUHvVOjWy_97OYl_pF-svCO1vbeumhF89ybhqv4Dw", "claim": null }
|
|
26
|
+
],
|
|
27
|
+
"owners": [
|
|
28
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "owner": "abcdef012345" },
|
|
29
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test:443", "owner": "abcdef012345" },
|
|
30
|
+
{ "host": "preview-web-app-abcdef012345.sbx.example.test:443", "owner": "abcdef012345" },
|
|
31
|
+
{ "host": "port-0f0f0f0f0f0f-abcdef012345.sbx.example.dev", "owner": "abcdef012345" },
|
|
32
|
+
{ "host": "public-1a2b3c4d5e6f-abcdef012345.sbx.example.dev", "owner": "abcdef012345" },
|
|
33
|
+
{ "host": "SANDBOX-abcdef012345.sbx.example.test", "owner": "abcdef012345" },
|
|
34
|
+
{ "host": "-abcdef012345.example.com", "owner": "abcdef012345" },
|
|
35
|
+
{ "host": "sandbox-abcdef012345", "owner": "abcdef012345" },
|
|
36
|
+
{ "host": "ingress.sbx.example.test", "owner": null },
|
|
37
|
+
{ "host": "sbx.example.test", "owner": null },
|
|
38
|
+
{ "host": "abcdef012345.local.sbx.example.dev", "owner": null },
|
|
39
|
+
{ "host": "sandbox-ABCDEF012345.sbx.example.test", "owner": null },
|
|
40
|
+
{ "host": "sandbox-abcdef01234.sbx.example.test", "owner": null },
|
|
41
|
+
{ "host": "sandbox-abcdef012345x.sbx.example.test", "owner": null },
|
|
42
|
+
{ "host": "sandbox-abcdef012345-.sbx.example.test", "owner": null },
|
|
43
|
+
{ "host": "[::1]:8788", "owner": null },
|
|
44
|
+
{ "host": "127.0.0.1:8788", "owner": null },
|
|
45
|
+
{ "host": "", "owner": null }
|
|
46
|
+
],
|
|
47
|
+
"bulk": [
|
|
48
|
+
"GET /diff/raw",
|
|
49
|
+
"GET /workspace/raw",
|
|
50
|
+
"GET /workspace/media",
|
|
51
|
+
"POST /workspace/upload",
|
|
52
|
+
"POST /workspace/upload-archive",
|
|
53
|
+
"GET /system/sync/ssh",
|
|
54
|
+
"GET /bundles/download",
|
|
55
|
+
"GET /extensions/{id}/bundle",
|
|
56
|
+
"GET /system/runners/git/{repo}/info/refs",
|
|
57
|
+
"POST /system/runners/git/{repo}/git-upload-pack",
|
|
58
|
+
"POST /system/runners/git/{repo}/git-receive-pack"
|
|
59
|
+
],
|
|
60
|
+
"lanes": [
|
|
61
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/workspace/media?path=a.mp4", "lane": "bulk" },
|
|
62
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "POST", "path": "/workspace/upload?path=a", "lane": "bulk" },
|
|
63
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test:443", "method": "GET", "path": "/system/runners/git/app/info/refs?service=git-upload-pack", "lane": "bulk" },
|
|
64
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "POST", "path": "/system/runners/git/app/git-receive-pack", "lane": "bulk" },
|
|
65
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/system/sync/ssh", "lane": "bulk" },
|
|
66
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/extensions/abc/bundle", "lane": "bulk" },
|
|
67
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/diff/raw?a=1?b=2", "lane": "bulk" },
|
|
68
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/bundles/download?ticket=x", "lane": "bulk" },
|
|
69
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "POST", "path": "/workspace/upload-archive", "lane": "bulk" },
|
|
70
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "HEAD", "path": "/workspace/raw?path=a", "lane": "bulk" },
|
|
71
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "OPTIONS", "path": "/workspace/raw", "lane": "bulk" },
|
|
72
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "OPTIONS", "path": "/system/runners/git/app/git-upload-pack", "lane": "bulk" },
|
|
73
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "get", "path": "/workspace/raw?path=a", "lane": "bulk" },
|
|
74
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/workspace/thumb?path=a.png", "lane": "interactive" },
|
|
75
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "POST", "path": "/workspace/upload-diff", "lane": "interactive" },
|
|
76
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/agents", "lane": "interactive" },
|
|
77
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/system/terminal?ticket=t", "lane": "interactive" },
|
|
78
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "POST", "path": "/workspace/raw", "lane": "interactive" },
|
|
79
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/workspace/raw/", "lane": "interactive" },
|
|
80
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/system/runners/git//info/refs", "lane": "interactive" },
|
|
81
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/x/anything/at/all", "lane": "interactive" },
|
|
82
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/", "lane": "interactive" },
|
|
83
|
+
{ "host": "sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "", "lane": "interactive" },
|
|
84
|
+
{ "host": "preview-web-abcdef012345.sbx.example.test", "method": "GET", "path": "/agents", "lane": "bulk" },
|
|
85
|
+
{ "host": "port-1a2b3c4d5e6f-abcdef012345.sbx.example.test", "method": "GET", "path": "/", "lane": "bulk" },
|
|
86
|
+
{ "host": "Sandbox-abcdef012345.sbx.example.test", "method": "GET", "path": "/agents", "lane": "bulk" },
|
|
87
|
+
{ "host": "sbx.example.test", "method": "GET", "path": "/agents", "lane": "bulk" },
|
|
88
|
+
{ "host": "", "method": "GET", "path": "/agents", "lane": "bulk" }
|
|
89
|
+
]
|
|
90
|
+
}
|