@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
package/src/schemas/system.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { StatePlanSchema } from "./state-plan.js";
|
|
2
3
|
// version is this build's baked-in version; latest/updateAvailable come from comparing it to the published stable
|
|
3
4
|
// release.
|
|
4
5
|
// Whether a runtime can serve a turn, probed off the turn path. "unknown" reads as available-but-unverified, never as
|
|
@@ -27,6 +28,14 @@ export const StagedUpdateSchema = z.object({
|
|
|
27
28
|
),
|
|
28
29
|
// Epoch ms the download finished; used to check this is still the update being offered.
|
|
29
30
|
at: z.number().describe("When the download finished, in milliseconds, which answers whether this is still the update being offered."),
|
|
31
|
+
// The staged build's state pre-flight (the daemon's state-plan.ts, run by `ic sandbox prepare` over read-only mounts
|
|
32
|
+
// of this sandbox's volumes): what its first boot converts, before anyone accepts the update.
|
|
33
|
+
// Embedded verbatim by the ic that staged it (StatePlanSchema); a marker an older ic wrote held only `ok` with
|
|
34
|
+
// `downgrade` and `steps`, or `failures`, so everything but `ok` stays optional here.
|
|
35
|
+
plan: StatePlanSchema.partial()
|
|
36
|
+
.extend({ ok: StatePlanSchema.shape.ok })
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("What the downloaded build's first boot would convert in this sandbox's stored files. Absent when no plan could be had, which says nothing either way."),
|
|
30
39
|
});
|
|
31
40
|
export type StagedUpdate = z.infer<typeof StagedUpdateSchema>;
|
|
32
41
|
export const InfoSchema = z.object({
|
|
@@ -75,8 +84,9 @@ export const InfoSchema = z.object({
|
|
|
75
84
|
),
|
|
76
85
|
});
|
|
77
86
|
export type Info = z.infer<typeof InfoSchema>;
|
|
78
|
-
// What the daemon could not read in its own `.intentic/` state files
|
|
79
|
-
//
|
|
87
|
+
// What the daemon could not read in its own `.intentic/` state files, and in the files on its volume that
|
|
88
|
+
// REPORTED_VOLUME_FILES names. Reported per file, only for files listed in REPORTED_MANIFEST_PATHS or
|
|
89
|
+
// REPORTED_VOLUME_FILES (workspace-state.ts). `kind`:
|
|
80
90
|
// unreadable: whole file ignored, everything in it at default.
|
|
81
91
|
// unknownKey: only that key ignored; `suggestion` may name what it should be.
|
|
82
92
|
// invalidEntry: one list entry skipped, rest of the file stands.
|
|
@@ -86,6 +96,13 @@ export const ManifestProblemSchema = z.object({
|
|
|
86
96
|
.describe(
|
|
87
97
|
"What to do about it. Unreadable means the whole file is being ignored and everything in it is at its default. An unknown key means only that key is ignored. An invalid entry means one item of a list was skipped and the rest is fine.",
|
|
88
98
|
),
|
|
99
|
+
// Why, as a word a reader matches on; `detail` is prose for a person and never parsed. Absent from an older daemon.
|
|
100
|
+
reason: z
|
|
101
|
+
.enum(["io", "not-json", "conversion-failed", "rejected"])
|
|
102
|
+
.optional()
|
|
103
|
+
.describe(
|
|
104
|
+
"Why it could not be read: the file could not be opened (io), it is not JSON, a conversion to this version's shape failed, or its contents are not what this version expects (rejected). A rejected file after a newer version ran is usually that version's, not a broken one.",
|
|
105
|
+
),
|
|
89
106
|
detail: z.string().describe("What exactly was wrong, as one sentence and nothing else. Never the remedy: that is `fix`."),
|
|
90
107
|
suggestion: z.string().optional().describe("The name it was probably meant to be, when one is close enough to guess honestly."),
|
|
91
108
|
// Set only when the fix isn't "open the file and correct it", e.g. a version skew where editing would be wrong.
|
|
@@ -98,7 +115,11 @@ export type ManifestProblem = z.infer<typeof ManifestProblemSchema>;
|
|
|
98
115
|
// Workspace-relative path and everything currently wrong with that file; a clean file is absent from the list, not
|
|
99
116
|
// present and empty.
|
|
100
117
|
export const ManifestProblemReportSchema = z.object({
|
|
101
|
-
path: z
|
|
118
|
+
path: z
|
|
119
|
+
.string()
|
|
120
|
+
.describe(
|
|
121
|
+
"The file, as a workspace path, or as its absolute path on the daemon's own history volume for one kept there (the conversation registry). The file is the unit somebody fixes, which is why problems are grouped by it.",
|
|
122
|
+
),
|
|
102
123
|
problems: z
|
|
103
124
|
.array(ManifestProblemSchema)
|
|
104
125
|
.describe("Everything currently wrong with it. A file with nothing wrong is absent rather than present and empty."),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { pushFixConversationId } from "../../ids/conversation-ids.js";
|
|
2
|
+
import { pushFixBase, pushRedOf, type Red, RedSchema } from "./mainline.js";
|
|
3
|
+
|
|
4
|
+
// What a push left is a Red like any other (source `push`, scope the project), and the hand-over's id is named by when
|
|
5
|
+
// that red began, so the editor and the daemon find the same attempt whichever of them asks.
|
|
6
|
+
|
|
7
|
+
const red = (over: Partial<Red>): Red => RedSchema.parse({ source: `push`, scope: `app`, since: 100, ...over });
|
|
8
|
+
|
|
9
|
+
describe(`a project's push red`, () => {
|
|
10
|
+
test(`is the push red of that project, never a land check's red of the same folder or another project's`, () => {
|
|
11
|
+
const land = red({ source: `land` });
|
|
12
|
+
const other = red({ scope: `web` });
|
|
13
|
+
const mine = red({});
|
|
14
|
+
expect(pushRedOf([land, other, mine], `app`)).toBe(mine);
|
|
15
|
+
expect(pushRedOf([land, other], `app`)).toBeUndefined();
|
|
16
|
+
expect(pushRedOf(undefined, `app`)).toBeUndefined();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test(`names its hand-over by when it began, with the workspace root spelled as the workspace`, () => {
|
|
20
|
+
expect(pushFixBase(red({}))).toBe(pushFixConversationId(`app`, `red:100`));
|
|
21
|
+
expect(pushFixBase(red({ scope: `` }))).toBe(pushFixConversationId(`workspace`, `red:100`));
|
|
22
|
+
expect(pushFixBase(undefined)).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test(`that began later is a fresh attempt`, () => {
|
|
26
|
+
expect(pushFixBase(red({ since: 200 }))).toBe(pushFixConversationId(`app`, `red:200`));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
// main-line checks: the whole-tree check the daemon runs after work lands, and what became of what it found
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { pushFixConversationId } from "../../ids/conversation-ids.js";
|
|
4
|
+
import { AgentRunPickSchema } from "../agent.js";
|
|
5
|
+
|
|
6
|
+
// Nothing is verified inside a conversation any more: a turn ends when the model says it is done, its work lands, and
|
|
7
|
+
// the main tree's own check runs afterwards, off everyone's clock, one project at a time. This is that check as the
|
|
8
|
+
// editor reads it: what is being measured, what is waiting, what the last run said, and who is working on a red one.
|
|
9
|
+
|
|
10
|
+
export const MainlineLandSchema = z.object({
|
|
11
|
+
conversationId: z.string().describe("The conversation whose work landed."),
|
|
12
|
+
title: z.string().optional().describe("Its title when it landed."),
|
|
13
|
+
at: z.number().describe("When the land asked for the check, in milliseconds."),
|
|
14
|
+
});
|
|
15
|
+
export type MainlineLand = z.infer<typeof MainlineLandSchema>;
|
|
16
|
+
|
|
17
|
+
// A land a red is laid at, as a reader names it.
|
|
18
|
+
export const MainlineLandRefSchema = z.object({
|
|
19
|
+
conversationId: z.string().describe("The conversation whose work landed."),
|
|
20
|
+
title: z.string().optional().describe("Its title when it landed."),
|
|
21
|
+
});
|
|
22
|
+
export type MainlineLandRef = z.infer<typeof MainlineLandRefSchema>;
|
|
23
|
+
|
|
24
|
+
// One failure a run named, split the way a reader scans it.
|
|
25
|
+
export const MainlineFailureSchema = z.object({
|
|
26
|
+
name: z.string().describe("What failed: a test by its own name, anything else (a type error, a whole task) as the check printed it."),
|
|
27
|
+
path: z.string().optional().describe("The repository path it failed in, when it names one."),
|
|
28
|
+
});
|
|
29
|
+
export type MainlineFailure = z.infer<typeof MainlineFailureSchema>;
|
|
30
|
+
|
|
31
|
+
// What happened to a red verdict's failures, decided once the lands behind it had their own check.
|
|
32
|
+
export const MainlineRoutingKindSchema = z.enum([
|
|
33
|
+
// More work landed while this ran; the check that measures it decides, so nobody is sent after a failure it may fix.
|
|
34
|
+
"waiting",
|
|
35
|
+
// A conversation still working touches what failed; nobody else is started until it stops.
|
|
36
|
+
"held",
|
|
37
|
+
// Sent back to the conversation that landed it, which still had the work in mind.
|
|
38
|
+
"original",
|
|
39
|
+
// A fresh conversation was started on it with the failures, the suspects' changes and where to read their sessions.
|
|
40
|
+
"fix-up",
|
|
41
|
+
// Nobody was sent: repairs are switched off, or no conversation could take it. An automation may.
|
|
42
|
+
"reported",
|
|
43
|
+
// Gone at the next check, before anybody was sent.
|
|
44
|
+
"resolved",
|
|
45
|
+
// The sends and fresh attempts a red streak allows are used up; it waits for a person.
|
|
46
|
+
"spent",
|
|
47
|
+
// A person set findings aside as not to be fixed (`findings` names which); what a push left is the owner's to dismiss.
|
|
48
|
+
"dismissed",
|
|
49
|
+
]);
|
|
50
|
+
export type MainlineRoutingKind = z.infer<typeof MainlineRoutingKindSchema>;
|
|
51
|
+
|
|
52
|
+
export const MainlineRoutingSchema = z.object({
|
|
53
|
+
kind: MainlineRoutingKindSchema.describe("What became of the failures."),
|
|
54
|
+
conversationId: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("The conversation working on them (the original or a fresh one), or the one still working that the repair waits for."),
|
|
58
|
+
at: z.number().describe("When that was decided, in milliseconds."),
|
|
59
|
+
detail: z.string().optional().describe("One sentence on why, in the sandbox's words."),
|
|
60
|
+
findings: z
|
|
61
|
+
.array(z.string())
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("The findings it was about, by id, when it was about some of a red's findings rather than the whole red."),
|
|
64
|
+
});
|
|
65
|
+
export type MainlineRouting = z.infer<typeof MainlineRoutingSchema>;
|
|
66
|
+
|
|
67
|
+
// The first failures a run names; the whole list stays in its terminal.
|
|
68
|
+
export const MAINLINE_FAILURES_KEPT = 30;
|
|
69
|
+
|
|
70
|
+
export const MainlineRunSchema = z.object({
|
|
71
|
+
project: z.string().describe("Which project, by folder relative to the workspace. Empty is the workspace root."),
|
|
72
|
+
command: z.string().describe("What ran."),
|
|
73
|
+
status: z.enum(["green", "red"]).describe("How it ended."),
|
|
74
|
+
startedAt: z.number().describe("When it started, in milliseconds."),
|
|
75
|
+
at: z.number().describe("When it ended, in milliseconds."),
|
|
76
|
+
lands: z.array(MainlineLandSchema).describe("The lands it answered for, oldest first. Empty for a run no land asked for."),
|
|
77
|
+
failures: z.array(z.string()).describe(`The first failures it named, at most ${MAINLINE_FAILURES_KEPT}.`),
|
|
78
|
+
failureCount: z.number().describe("How many failures it named in all. Zero on a red run that wrote no list."),
|
|
79
|
+
attempt: z.number().describe("How many red runs in a row this is for the project; zero when green."),
|
|
80
|
+
suspects: z
|
|
81
|
+
.array(z.string())
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("The conversations whose lands these failures were laid at, when any could be named."),
|
|
84
|
+
named: z
|
|
85
|
+
.boolean()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe(
|
|
88
|
+
"Whether the failures were laid at the suspects by the paths they changed. False when nobody could be told apart (every land the run covered is a suspect) or nothing new failed in it (none is). Absent on green, and from a daemon that did not say.",
|
|
89
|
+
),
|
|
90
|
+
units: z
|
|
91
|
+
.array(MainlineFailureSchema)
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("The same first failures, split into a name and the path they failed in. Absent from a daemon that does not split them."),
|
|
94
|
+
routing: MainlineRoutingSchema.optional().describe("What became of a red run's failures. Absent on green, and until it is decided."),
|
|
95
|
+
});
|
|
96
|
+
export type MainlineRun = z.infer<typeof MainlineRunSchema>;
|
|
97
|
+
|
|
98
|
+
export const MainlineProjectSchema = z.object({
|
|
99
|
+
project: z.string().describe("Which project, by folder relative to the workspace. Empty is the workspace root."),
|
|
100
|
+
running: z
|
|
101
|
+
.object({
|
|
102
|
+
command: z.string().describe("What is running."),
|
|
103
|
+
startedAt: z.number().describe("When it started, in milliseconds."),
|
|
104
|
+
lands: z.array(MainlineLandSchema).describe("The lands it answers for."),
|
|
105
|
+
on: z.string().optional().describe("The runner it was sent to, on one of your machines. Absent when it runs in this sandbox."),
|
|
106
|
+
})
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("The check running on it now, if any."),
|
|
109
|
+
session: z
|
|
110
|
+
.string()
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("The terminal session its check runs in, running or last, to attach to for the whole log. Absent from a daemon that does not say."),
|
|
113
|
+
queued: z.array(MainlineLandSchema).describe("Lands waiting for the next check, which will measure them together."),
|
|
114
|
+
last: MainlineRunSchema.optional().describe("Its most recent settled check."),
|
|
115
|
+
redSince: z.number().optional().describe("When its checks went red and stayed so, in milliseconds. Absent while green."),
|
|
116
|
+
red: z
|
|
117
|
+
.object({
|
|
118
|
+
since: z.number().describe("When its checks went red and stayed so, in milliseconds."),
|
|
119
|
+
cause: z
|
|
120
|
+
.array(MainlineLandRefSchema)
|
|
121
|
+
.describe("The work this red is laid at, oldest first: the lands its failures were laid at on the latest run of the streak that could name any. Empty when none could be."),
|
|
122
|
+
named: z.boolean().describe("Whether `cause` was narrowed by the paths the lands changed; false when it is every land the run covered."),
|
|
123
|
+
fixer: MainlineRoutingSchema.optional().describe("The latest decision about who has it. Absent until one is made."),
|
|
124
|
+
})
|
|
125
|
+
.optional()
|
|
126
|
+
.describe("The red streak it is in, as the sandbox laid it. Absent while green, and from a daemon that does not lay it."),
|
|
127
|
+
});
|
|
128
|
+
export type MainlineProject = z.infer<typeof MainlineProjectSchema>;
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
// WHAT A PUSH LEFT BEHIND. The pre-push hook never refuses (verify-push.mjs, `--advisory`): it measures, reports, and the
|
|
132
|
+
// push goes. What it found used to vanish with the terminal it printed to. It now leaves a report in the repository's
|
|
133
|
+
// git dir, the daemon files it once the push has actually reached the remote, and what it found is owed, as the
|
|
134
|
+
// project's push Red, until a later measurement no longer prints it or somebody dismisses it. Nobody is sent after it:
|
|
135
|
+
// acting on it is the owner's call (RED_POLICY).
|
|
136
|
+
|
|
137
|
+
// ONE FINDING, whatever measured it: a check run's line as the repository's own tooling printed it, named by what
|
|
138
|
+
// printed it (`source`, the repository's word: a check's id, `lint`, a hook), with the command that shows it again and
|
|
139
|
+
// whether a later measurement can say it is gone. A push's findings are these; a land check's failures and a CI run's
|
|
140
|
+
// failed jobs become them too.
|
|
141
|
+
export const FindingSchema = z.object({
|
|
142
|
+
id: z.string().describe("Stable across measurements: the same problem found again is the same id."),
|
|
143
|
+
source: z.string().describe("What measured it, in the repository's own words: a check's id, `lint`, a hook."),
|
|
144
|
+
text: z.string().describe("The finding as it was printed."),
|
|
145
|
+
path: z.string().optional().describe("The repository path it is about, when it names one."),
|
|
146
|
+
command: z.string().optional().describe("The command that shows it again."),
|
|
147
|
+
recheckable: z
|
|
148
|
+
.boolean()
|
|
149
|
+
.describe("Whether a later measurement can find it gone. False for one about commits already made, which ends only when dismissed."),
|
|
150
|
+
gate: z
|
|
151
|
+
.enum(["code", "tidy"])
|
|
152
|
+
.optional()
|
|
153
|
+
.describe("For a check's finding: `code` means the tree fails the check whoever caused it; `tidy` means the change measured added this line."),
|
|
154
|
+
commit: z
|
|
155
|
+
.object({ sha: z.string(), subject: z.string() })
|
|
156
|
+
.optional()
|
|
157
|
+
.describe("The newest commit of the change measured that touched the path it names, when it names one."),
|
|
158
|
+
});
|
|
159
|
+
export type Finding = z.infer<typeof FindingSchema>;
|
|
160
|
+
|
|
161
|
+
// ONE RED, whatever went red: a land check's project, what a push left in a project, main's CI on a branch. What it owes
|
|
162
|
+
// (its findings), who it was laid at and whether that was narrowed, and every decision about it, oldest first. Each
|
|
163
|
+
// source answers its own red by its own policy (RED_POLICY); the record is the same.
|
|
164
|
+
export const RedSourceSchema = z.enum(["land", "push", "ci"]);
|
|
165
|
+
export type RedSource = z.infer<typeof RedSourceSchema>;
|
|
166
|
+
|
|
167
|
+
// Who answers a red: `route` sends it itself (the land check's router, conversations/land/land-breakage.ts), `owner`
|
|
168
|
+
// waits for a person's press (what a push left, conversations/fix/push-fix.ts), `fix-agent` starts the source's own fix
|
|
169
|
+
// agent once the red is main's standing word (CI, ci/repair-gate.ts).
|
|
170
|
+
export const RED_POLICY = { land: "route", push: "owner", ci: "fix-agent" } as const satisfies Record<RedSource, "route" | "owner" | "fix-agent">;
|
|
171
|
+
|
|
172
|
+
export const RedSchema = z.object({
|
|
173
|
+
source: RedSourceSchema.describe("What went red."),
|
|
174
|
+
scope: z.string().describe("Where: a project's folder, or a repository and branch."),
|
|
175
|
+
since: z.number().describe("When the red streak began (state/red-streak.ts)."),
|
|
176
|
+
findings: z.array(FindingSchema).default([]).describe("What it owes, as the red's own measurement named it."),
|
|
177
|
+
suspects: z.array(z.string()).default([]).describe("The conversations it was laid at."),
|
|
178
|
+
named: z.boolean().default(false).describe("Whether the paths they changed narrowed it to them."),
|
|
179
|
+
decisions: z.array(MainlineRoutingSchema).default([]).describe("What was decided about it, oldest first."),
|
|
180
|
+
});
|
|
181
|
+
export type Red = z.infer<typeof RedSchema>;
|
|
182
|
+
|
|
183
|
+
// ONE PUSH THE HOOK MEASURED, as the record lists it: where it went and what it found that it brought in. What of that is
|
|
184
|
+
// still owed is the project's push Red's to say (`findings`), never the push's.
|
|
185
|
+
export const MainlinePushSchema = z.object({
|
|
186
|
+
project: z.string().describe("Which project, by folder relative to the workspace. Empty is the workspace root."),
|
|
187
|
+
id: z.string().describe("The report's own id."),
|
|
188
|
+
at: z.number().describe("When the push check ran, in milliseconds."),
|
|
189
|
+
remote: z.string().optional().describe("The remote it was pushed to."),
|
|
190
|
+
branch: z.string().optional().describe("The branch it was pushed to."),
|
|
191
|
+
base: z.string().optional().describe("The commit the pushed range starts from; absent when the remote had nothing to compare with."),
|
|
192
|
+
head: z.string().describe("The commit that was pushed."),
|
|
193
|
+
commits: z.number().describe("How many commits the push carried."),
|
|
194
|
+
findings: z
|
|
195
|
+
.array(FindingSchema)
|
|
196
|
+
.describe("What it found that this push brought in, less what an earlier push had already left open. Empty for a clean push."),
|
|
197
|
+
refused: z
|
|
198
|
+
.boolean()
|
|
199
|
+
.optional()
|
|
200
|
+
.describe("True when the repository's own pre-push hook refused it, so nothing reached the remote and its one finding is what the hook said."),
|
|
201
|
+
});
|
|
202
|
+
export type MainlinePush = z.infer<typeof MainlinePushSchema>;
|
|
203
|
+
|
|
204
|
+
export const MainlineStatusSchema = z.object({
|
|
205
|
+
projects: z.array(MainlineProjectSchema).describe("Every project a land has been checked in, or is waiting to be."),
|
|
206
|
+
recent: z.array(MainlineRunSchema).describe("The latest settled checks across every project, newest first."),
|
|
207
|
+
pushed: z
|
|
208
|
+
.array(MainlinePushSchema)
|
|
209
|
+
.optional()
|
|
210
|
+
.describe("The latest pushes the hook measured across every project, newest first, with what each brought in. Absent from a daemon that records none."),
|
|
211
|
+
reds: z
|
|
212
|
+
.array(RedSchema)
|
|
213
|
+
.optional()
|
|
214
|
+
.describe(
|
|
215
|
+
"Every red the main line holds, one record whatever went red: each red project's land check and what pushes left in each project, with what each owes and every decision about it. Absent from a daemon that keeps none.",
|
|
216
|
+
),
|
|
217
|
+
});
|
|
218
|
+
export type MainlineStatus = z.infer<typeof MainlineStatusSchema>;
|
|
219
|
+
|
|
220
|
+
export const MainlinePushDismissSchema = z.object({
|
|
221
|
+
project: z.string().describe("Which project, by folder relative to the workspace."),
|
|
222
|
+
ids: z.array(z.string()).optional().describe("Which findings. Leave it out for every open one in the project."),
|
|
223
|
+
restore: z.boolean().optional().describe("Undo: open the named dismissed findings again."),
|
|
224
|
+
});
|
|
225
|
+
export type MainlinePushDismiss = z.infer<typeof MainlinePushDismissSchema>;
|
|
226
|
+
|
|
227
|
+
export const MainlinePushDismissResultSchema = z.object({
|
|
228
|
+
changed: z.number().describe("How many findings changed state."),
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
export const MainlinePushRecheckSchema = z.object({
|
|
232
|
+
project: z.string().describe("Which project, by folder relative to the workspace."),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
export const MainlinePushRecheckResultSchema = z.object({
|
|
236
|
+
measured: z.boolean().describe("Whether the project could be measured at all; false leaves every finding as it was."),
|
|
237
|
+
resolved: z.number().describe("How many findings the measurement no longer saw."),
|
|
238
|
+
open: z.number().describe("How many are still open."),
|
|
239
|
+
});
|
|
240
|
+
export type MainlinePushRecheckResult = z.infer<typeof MainlinePushRecheckResultSchema>;
|
|
241
|
+
|
|
242
|
+
export const MainlinePushFixSchema = z.object({
|
|
243
|
+
project: z.string().describe("Which project's open push findings to hand over, by folder relative to the workspace."),
|
|
244
|
+
pick: AgentRunPickSchema.describe(
|
|
245
|
+
"Which model to open the conversation on, when somebody chose one. Leave it out for the sandbox's own choice.",
|
|
246
|
+
),
|
|
247
|
+
mode: z
|
|
248
|
+
.enum(["continue", "start-over"])
|
|
249
|
+
.optional()
|
|
250
|
+
.describe(
|
|
251
|
+
"What to do about an attempt already made at these findings: `continue` carries on in it, `start-over` files it away and opens the next attempt. Leave it out for the plain press.",
|
|
252
|
+
),
|
|
253
|
+
});
|
|
254
|
+
export type MainlinePushFix = z.infer<typeof MainlinePushFixSchema>;
|
|
255
|
+
|
|
256
|
+
export const MainlinePushFixResultSchema = z.object({
|
|
257
|
+
conversationId: z.string().describe("The conversation holding the findings. Open it to watch."),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// What pushes left in `project`, as the reds name it; undefined while nothing is owed.
|
|
261
|
+
export const pushRedOf = (reds: readonly Red[] | undefined, project: string): Red | undefined =>
|
|
262
|
+
reds?.find((red) => red.source === "push" && red.scope === project);
|
|
263
|
+
|
|
264
|
+
// The conversation id a hand-over of a push red wears (attempt 1), derived from when the red began, so the editor and the
|
|
265
|
+
// daemon agree on whether an agent is already on it: pressing again while anything is owed continues the same attempt,
|
|
266
|
+
// and a red that begins after everything was handled starts a fresh one. Undefined when nothing is owed.
|
|
267
|
+
export const pushFixBase = (red: Pick<Red, "scope" | "since"> | undefined): string | undefined =>
|
|
268
|
+
red === undefined ? undefined : pushFixConversationId(red.scope === "" ? "workspace" : red.scope, `red:${red.since}`);
|
|
@@ -72,8 +72,33 @@ export const WorkspaceTreeSchema = z.object({
|
|
|
72
72
|
.describe(
|
|
73
73
|
"Folders whose whole contents are empty folders, and nothing else. Complete for the workspace, however much of the tree above was listed, and ordered like the tree, so a parent comes before the branch below it.",
|
|
74
74
|
),
|
|
75
|
+
generation: z
|
|
76
|
+
.number()
|
|
77
|
+
.int()
|
|
78
|
+
.nonnegative()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe(
|
|
81
|
+
"Which state of the shared tree this is; the changes that follow count from it. Absent for a conversation's own checkout, which is listed when asked and followed by no changes.",
|
|
82
|
+
),
|
|
75
83
|
});
|
|
76
84
|
export type WorkspaceTree = z.infer<typeof WorkspaceTreeSchema>;
|
|
85
|
+
// What moved in the shared tree between two generations: every folder whose own entries changed, parents first.
|
|
86
|
+
export const WorkspaceTreeDeltaSchema = z.object({
|
|
87
|
+
from: z.number().int().nonnegative().describe("The generation this applies on top of. A reader holding any other fetches the tree afresh instead."),
|
|
88
|
+
generation: z.number().int().nonnegative().describe("The generation it leaves the tree at."),
|
|
89
|
+
dirs: z
|
|
90
|
+
.array(
|
|
91
|
+
z.object({
|
|
92
|
+
path: z.string().describe("The folder, as a workspace path; empty for the workspace root."),
|
|
93
|
+
entries: z
|
|
94
|
+
.array(WorkspaceTreeEntrySchema)
|
|
95
|
+
.describe("Its entries now, without their contents: a folder whose own entries also changed comes as an item of its own."),
|
|
96
|
+
}),
|
|
97
|
+
)
|
|
98
|
+
.describe("Each folder that changed, parents before the folders inside them."),
|
|
99
|
+
barren: z.array(z.string()).optional().describe("The barren folders now, present only when that list moved."),
|
|
100
|
+
});
|
|
101
|
+
export type WorkspaceTreeDelta = z.infer<typeof WorkspaceTreeDeltaSchema>;
|
|
77
102
|
// Lazy-loads one directory's children past the tree walk's budget; depth reads several levels into one flat `entries`
|
|
78
103
|
// list instead of one request per directory.
|
|
79
104
|
export const WorkspaceChildrenQuerySchema = WorkspaceScopeSchema.extend({
|
|
@@ -253,6 +278,28 @@ export const WorkspaceExtractSchema = z.object({
|
|
|
253
278
|
),
|
|
254
279
|
});
|
|
255
280
|
export type WorkspaceExtract = z.infer<typeof WorkspaceExtractSchema>;
|
|
281
|
+
// A delete moves the entry into the daemon's trash rather than erasing it, so the gesture can be taken back.
|
|
282
|
+
export const WorkspaceDeletedSchema = z.object({
|
|
283
|
+
ok: z.literal(true).describe("Always true: the entry is gone from where it was, or was never there."),
|
|
284
|
+
trashed: z
|
|
285
|
+
.string()
|
|
286
|
+
.optional()
|
|
287
|
+
.describe(
|
|
288
|
+
"The trash id that brings it back through the restore call, for a day. Absent when there was nothing at that path to delete.",
|
|
289
|
+
),
|
|
290
|
+
});
|
|
291
|
+
export type WorkspaceDeleted = z.infer<typeof WorkspaceDeletedSchema>;
|
|
292
|
+
export const WorkspaceRestoreSchema = z.object({
|
|
293
|
+
trashed: z.string().min(1).describe("The trash id a delete answered with."),
|
|
294
|
+
});
|
|
295
|
+
export const WorkspaceRestoredSchema = z.object({
|
|
296
|
+
path: z
|
|
297
|
+
.string()
|
|
298
|
+
.describe(
|
|
299
|
+
"Where it came back, as a workspace path: where it was deleted from, or beside that under a `(restored)` name when something new has taken the name since.",
|
|
300
|
+
),
|
|
301
|
+
});
|
|
302
|
+
export type WorkspaceRestored = z.infer<typeof WorkspaceRestoredSchema>;
|
|
256
303
|
// Deterministic, no-LLM classification into coarse buckets, read-only, applied via /workspace/move. reason is the
|
|
257
304
|
// winning signal: magic:<mime>, ext:<ext>, repository:<marker>, text-content, or unknown.
|
|
258
305
|
export const WorkspaceBucketSchema = z.enum(["repositories", "documents", "media", "archives", "other"]);
|
|
@@ -1,20 +1,81 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { shrunkSurfaces } from "@intentic/constants/contract-shrink";
|
|
3
4
|
import { packageRoot } from "@intentic/constants/node";
|
|
4
|
-
import {
|
|
5
|
+
import { RAW_ROUTE_LIST } from "../protocol/raw-routes.js";
|
|
6
|
+
import type { RouteMeta } from "../protocol/route-meta.js";
|
|
7
|
+
import { accessChanges, currentLock, serializeLock } from "./contract-lock.js";
|
|
8
|
+
|
|
9
|
+
const committedText = (): string => readFileSync(join(packageRoot(import.meta.url), "contract.lock.json"), "utf8");
|
|
10
|
+
|
|
11
|
+
const ACCESS_MOVED =
|
|
12
|
+
"a route's access moved — run `pnpm --filter @intentic/sandbox-contract lock` and commit contract.lock.json with this change. " +
|
|
13
|
+
"Any change to an existing route's reach (a lower floor, a guest, agent, panel or sync grant, a wider control rung, or a " +
|
|
14
|
+
"tighter one that locks callers out) lands as a `type!:` commit with a `Breaking-Note:` trailer saying who can now reach " +
|
|
15
|
+
"what, or who no longer can.";
|
|
5
16
|
|
|
6
17
|
// contract.lock.json must match the exported schemas; the git-aware half of this check lives in contract-shrink.mjs.
|
|
7
18
|
// Needs 30s: serializing ~500 schemas can run past the unit hang detector under load.
|
|
8
19
|
test(
|
|
9
20
|
"contract.lock.json matches the schemas this package exports",
|
|
10
21
|
() => {
|
|
11
|
-
const committed =
|
|
22
|
+
const committed = committedText();
|
|
23
|
+
const current = currentLock();
|
|
24
|
+
// Named first, so a reach change says which route before the whole-lock diff does.
|
|
25
|
+
expect(accessChanges(committed, serializeLock(current)), ACCESS_MOVED).toEqual([]);
|
|
12
26
|
expect(
|
|
13
|
-
|
|
27
|
+
current,
|
|
14
28
|
"the wire contract moved — run `pnpm --filter @intentic/sandbox-contract lock` and commit contract.lock.json with this change. " +
|
|
15
29
|
"If a schema or field was removed or changed (not added), land it as a `type!:` commit with a `Breaking-Note:` trailer " +
|
|
16
30
|
"saying, in the user's words, what stops working and what to do instead.",
|
|
17
|
-
).toEqual(committed);
|
|
31
|
+
).toEqual(JSON.parse(committed));
|
|
18
32
|
},
|
|
19
33
|
{ timeout: 30_000 },
|
|
20
34
|
);
|
|
35
|
+
|
|
36
|
+
// The wire outside oRPC is pinned the same way: a changed tunnel path, a gone control message or a renamed verdict is a
|
|
37
|
+
// shrink the push gate and the landing draft both flag, where before nothing could see it.
|
|
38
|
+
test("the lock flags a change to the wire no oRPC route carries", () => {
|
|
39
|
+
const base = currentLock() as Record<string, Record<string, unknown>>;
|
|
40
|
+
const moved = structuredClone(base);
|
|
41
|
+
(moved["wire:tunnel"] as { path: string }).path = "/tunnel/v3";
|
|
42
|
+
delete (moved["wire:browser-wire"] as { webTransport?: unknown }).webTransport;
|
|
43
|
+
expect(shrunkSurfaces(base, moved)).toEqual(["wire:browser-wire.webTransport", "wire:tunnel.path"]);
|
|
44
|
+
expect(shrunkSurfaces(moved, base)).toEqual(["wire:tunnel.path"]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// The lock as it would be with one raw route declared otherwise: the declaration is swapped in place, and back.
|
|
48
|
+
const lockWith = (name: string, change: (declared: RouteMeta) => RouteMeta): Record<string, unknown> => {
|
|
49
|
+
const route = RAW_ROUTE_LIST.find((candidate) => candidate.name === name);
|
|
50
|
+
if (route === undefined) {
|
|
51
|
+
throw new Error(`${name} is gone; pick another raw route with a maintainer floor and no grants`);
|
|
52
|
+
}
|
|
53
|
+
const declared = route.meta;
|
|
54
|
+
Reflect.set(route, "meta", change(declared));
|
|
55
|
+
try {
|
|
56
|
+
return currentLock();
|
|
57
|
+
} finally {
|
|
58
|
+
Reflect.set(route, "meta", declared);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const ROUTE = "POST /system/sync/report";
|
|
63
|
+
|
|
64
|
+
// A lowered floor on any route, not only the ones route-reach.test.ts pins: the lock check names it, and the push gate and
|
|
65
|
+
// the landing draft read it as a shrink that needs a declared break.
|
|
66
|
+
test("lowering one route's floor fails the lock check, naming the route", () => {
|
|
67
|
+
const committed = currentLock();
|
|
68
|
+
const lowered = lockWith(ROUTE, (declared) => ({ ...declared, floor: "viewer" }));
|
|
69
|
+
expect(accessChanges(serializeLock(committed), serializeLock(lowered))).toEqual([`${ROUTE}: floor "maintainer" → "viewer"`]);
|
|
70
|
+
expect(shrunkSurfaces(committed, lowered)).toEqual([`access:${ROUTE}.floor`]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// A grant a route never declared still has a value in the lock, so granting it is a changed value, not growth that
|
|
74
|
+
// passes; taking one away reads the same way, since it locks out a caller that relied on it.
|
|
75
|
+
test("granting guest or agent reach reads as a shrink, and so does taking it back", () => {
|
|
76
|
+
const committed = currentLock();
|
|
77
|
+
const granted = lockWith(ROUTE, (declared) => ({ ...declared, guest: true, agent: true }));
|
|
78
|
+
expect(accessChanges(serializeLock(committed), serializeLock(granted))).toEqual([`${ROUTE}: agent false → true, guest false → true`]);
|
|
79
|
+
expect(shrunkSurfaces(committed, granted)).toEqual([`access:${ROUTE}.agent`, `access:${ROUTE}.guest`]);
|
|
80
|
+
expect(shrunkSurfaces(granted, committed)).toEqual([`access:${ROUTE}.agent`, `access:${ROUTE}.guest`]);
|
|
81
|
+
});
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
// contract.lock.json is every exported schema serialized to canonical JSON Schema, so git can flag a wire-contract
|
|
2
2
|
// change. contract-shrink demands a `!` commit with a Breaking-Note when a schema, field or type shrinks; additions
|
|
3
|
-
// pass freely. Derived from the package's exports, not a hand-kept list
|
|
3
|
+
// pass freely. Derived from the package's exports, not a hand-kept list, plus the wire no oRPC route carries: the
|
|
4
|
+
// manifests the Rust crates that define it write beside their TypeScript (the tunnel, what a browser sees of the front
|
|
5
|
+
// and the edge, and the front's control socket with Node), under `wire:` names no export can take.
|
|
6
|
+
//
|
|
7
|
+
// And who reaches each route: every raw route's and every procedure's RouteMeta, each reach field with its default
|
|
8
|
+
// resolved (route-meta.ts `routeAccess`), under `access:METHOD /path`. Resolved, so every field is a value on every
|
|
9
|
+
// route: a lowered floor, a `guest`, `agent` or `panel` granted, a control rung widened are each a changed value, which
|
|
10
|
+
// contract-shrink reads as a shrink, the same `!` and Breaking-Note a removed field needs. A field left absent could
|
|
11
|
+
// instead be added unseen, since growth passes freely. route-reach.test.ts in the daemon proves the gates honour
|
|
12
|
+
// exactly these declarations; this pins the declarations themselves.
|
|
4
13
|
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { packageRoot } from "@intentic/constants/node";
|
|
5
17
|
import { z } from "zod";
|
|
6
18
|
import * as contract from "../index.js";
|
|
7
19
|
|
|
@@ -21,6 +33,57 @@ const sorted = (value: unknown): unknown => {
|
|
|
21
33
|
return value;
|
|
22
34
|
};
|
|
23
35
|
|
|
36
|
+
const ACCESS_PREFIX = "access:";
|
|
37
|
+
|
|
38
|
+
// The access half of the lock, one entry per route with its fields in key order; a procedure also names itself, so a
|
|
39
|
+
// route moving between procedures is seen.
|
|
40
|
+
const accessEntries = (): Record<string, Readonly<Record<string, string | boolean>>> => {
|
|
41
|
+
const entries = new Map<string, Readonly<Record<string, string | boolean>>>();
|
|
42
|
+
for (const route of [...contract.RAW_ROUTE_LIST, ...contract.SANDBOX_ROUTES]) {
|
|
43
|
+
const key = `${ACCESS_PREFIX}${route.method} ${route.path}`;
|
|
44
|
+
if (entries.has(key)) {
|
|
45
|
+
throw new Error(`two routes declare ${route.method} ${route.path}; the lock can record only one reach for it`);
|
|
46
|
+
}
|
|
47
|
+
const access = contract.routeAccess(route.method, route.meta);
|
|
48
|
+
const fields = route.name === `${route.method} ${route.path}` ? access : { ...access, procedure: route.name };
|
|
49
|
+
entries.set(key, Object.fromEntries(Object.entries(fields).toSorted(([a], [b]) => a.localeCompare(b))));
|
|
50
|
+
}
|
|
51
|
+
return Object.fromEntries([...entries].toSorted(([a], [b]) => a.localeCompare(b)));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// A lock text's access half: route key to its fields. Entries under other names are not its business.
|
|
55
|
+
const accessHalf = (text: string): Record<string, Readonly<Record<string, string | boolean>>> => {
|
|
56
|
+
const lock = z.record(z.string(), z.unknown()).parse(JSON.parse(text));
|
|
57
|
+
return z
|
|
58
|
+
.record(z.string(), z.record(z.string(), z.union([z.string(), z.boolean()])))
|
|
59
|
+
.parse(Object.fromEntries(Object.entries(lock).filter(([key]) => key.startsWith(ACCESS_PREFIX))));
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Each route whose recorded reach differs between two locks, one line naming the route and every field that moved, so a
|
|
63
|
+
// failing lock check says which route's access changed rather than leaving it to a diff of hundreds of entries. Takes
|
|
64
|
+
// the two lock texts, as serializeLock writes them.
|
|
65
|
+
export const accessChanges = (baseText: string, headText: string): string[] => {
|
|
66
|
+
const base = accessHalf(baseText);
|
|
67
|
+
const head = accessHalf(headText);
|
|
68
|
+
const keys = new Set([...Object.keys(base), ...Object.keys(head)]);
|
|
69
|
+
return [...keys].toSorted().flatMap((key) => {
|
|
70
|
+
const route = key.slice(ACCESS_PREFIX.length);
|
|
71
|
+
const was = base[key];
|
|
72
|
+
const now = head[key];
|
|
73
|
+
if (was === undefined || now === undefined) {
|
|
74
|
+
return [`${route}: ${was === undefined ? "new route" : "no longer declared"}`];
|
|
75
|
+
}
|
|
76
|
+
const moved = [...new Set([...Object.keys(was), ...Object.keys(now)])]
|
|
77
|
+
.toSorted()
|
|
78
|
+
.filter((field) => was[field] !== now[field])
|
|
79
|
+
.map((field) => `${field} ${JSON.stringify(was[field]) ?? "absent"} → ${JSON.stringify(now[field]) ?? "absent"}`);
|
|
80
|
+
return moved.length === 0 ? [] : [`${route}: ${moved.join(", ")}`];
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Each written by its crate's own test: `tunnel`, `browser-wire` and `front-wire` under _sandbox/front/crates.
|
|
85
|
+
const WIRE_MANIFESTS = ["browser-wire", "front-wire", "tunnel"] as const;
|
|
86
|
+
|
|
24
87
|
export const currentLock = (): Record<string, unknown> => {
|
|
25
88
|
const lock: Record<string, unknown> = {};
|
|
26
89
|
for (const name of Object.keys(contract).sort()) {
|
|
@@ -38,7 +101,12 @@ export const currentLock = (): Record<string, unknown> => {
|
|
|
38
101
|
lock[name] = "<unserializable>";
|
|
39
102
|
}
|
|
40
103
|
}
|
|
41
|
-
|
|
104
|
+
for (const manifest of WIRE_MANIFESTS) {
|
|
105
|
+
// Read from src/ whether this runs from src/ or dist/: the manifests are data `cargo test` writes, never compiled.
|
|
106
|
+
const text = readFileSync(join(packageRoot(import.meta.url), "src", "front", "generated", `${manifest}.json`), "utf8");
|
|
107
|
+
lock[`wire:${manifest}`] = sorted(JSON.parse(text));
|
|
108
|
+
}
|
|
109
|
+
return { ...lock, ...accessEntries() };
|
|
42
110
|
};
|
|
43
111
|
|
|
44
112
|
// One line per schema, not pretty-printed: keeps the lock short enough that a diff shows which surfaces moved.
|
package/src/state/definition.ts
CHANGED
|
@@ -48,9 +48,10 @@ const bareField = (field: z.ZodType): z.ZodType => {
|
|
|
48
48
|
return inner;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
// Typed as the prefault it is, so the static input type says what the runtime does: an absent table is accepted.
|
|
52
|
+
const definitionSettings = (): z.ZodPrefault<z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema>>>> => {
|
|
52
53
|
const shape = Object.fromEntries(Object.entries(SandboxSettingsSchema.shape).map(([key, field]) => [key, bareField(field).optional()]));
|
|
53
|
-
return z.strictObject(shape).prefault({}) as unknown as z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema
|
|
54
|
+
return z.strictObject(shape).prefault({}) as unknown as z.ZodPrefault<z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema>>>>;
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
export const SandboxDefinitionSchema = z.strictObject({
|
|
@@ -59,6 +59,14 @@ test.each([
|
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
// The daemon's own reading decides, whatever the watch list says: a wake waiting in its queue keeps it working with no
|
|
63
|
+
// watch at all, and a daemon that says nothing wakes it is not second-guessed from a list it still shows.
|
|
64
|
+
test("an agent the daemon says awaits a wake is still working, and one it says does not is judged on what it holds", () => {
|
|
65
|
+
expect(fixStance(agent({ status: `idle`, awaitingWake: true })).kind).toBe(`working`);
|
|
66
|
+
const watches = [{ id: `watch-a1b2`, note: `CI on the pushed branch`, intervalSeconds: 60, deadlineAt: 9_000 }];
|
|
67
|
+
expect(fixStance(agent({ status: `idle`, awaitingWake: false, watches, diff: { files: 1, insertions: 1, deletions: 0 } })).kind).toBe(`ready`);
|
|
68
|
+
});
|
|
69
|
+
|
|
62
70
|
// Diff present doesn't change a failed status to ready; it only earns a mention in the hint.
|
|
63
71
|
test("an agent that failed after writing files still reads as failed", () => {
|
|
64
72
|
const stance = fixStance(agent({ status: `error`, diff: { files: 2, insertions: 34, deletions: 6 } }));
|