@intentic/sandbox-contract 1.247.0 → 1.249.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 +18 -15
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/digest.d.ts.map +1 -1
- package/dist/chores/digest.js.map +1 -1
- package/dist/chores/extension-update.d.ts.map +1 -1
- package/dist/chores/extension-update.js.map +1 -1
- package/dist/chores/fix-deps.d.ts.map +1 -1
- package/dist/chores/fix-deps.js.map +1 -1
- package/dist/chores/index.d.ts +2 -2
- package/dist/chores/index.d.ts.map +1 -1
- package/dist/chores/index.js +1 -1
- package/dist/chores/index.js.map +1 -1
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/prompt.d.ts.map +1 -1
- package/dist/chores/prompt.js.map +1 -1
- package/dist/chores/stack.d.ts.map +1 -1
- package/dist/chores/stack.js.map +1 -1
- package/dist/chores/verdict.d.ts +7 -1
- package/dist/chores/verdict.d.ts.map +1 -1
- package/dist/chores/verdict.js +8 -0
- package/dist/chores/verdict.js.map +1 -1
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/accounts.contract.js.map +1 -1
- package/dist/contracts/activity.contract.d.ts +1 -0
- package/dist/contracts/activity.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +13 -205
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +2 -1
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +228 -54
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +11 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts +35 -17
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +10 -1
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +0 -12
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +1 -1
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/chores.contract.js.map +1 -1
- package/dist/contracts/ci.contract.d.ts +9 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/exit.contract.d.ts.map +1 -1
- package/dist/contracts/exit.contract.js +1 -1
- package/dist/contracts/exit.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts +45 -6
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +9 -9
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/host.contract.d.ts +2 -0
- package/dist/contracts/host.contract.d.ts.map +1 -1
- package/dist/contracts/host.contract.js.map +1 -1
- package/dist/contracts/intentic.contract.js +1 -1
- package/dist/contracts/intentic.contract.js.map +1 -1
- package/dist/contracts/logs.contract.d.ts.map +1 -1
- package/dist/contracts/logs.contract.js.map +1 -1
- package/dist/contracts/loops.contract.d.ts.map +1 -1
- package/dist/contracts/loops.contract.js.map +1 -1
- package/dist/contracts/personas.contract.d.ts +39 -4
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.js +10 -1
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +6 -80
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +2 -2
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/safety.contract.d.ts.map +1 -1
- package/dist/contracts/safety.contract.js +1 -1
- package/dist/contracts/safety.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -41
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.js +1 -1
- package/dist/contracts/sessions.contract.js.map +1 -1
- package/dist/contracts/settings.contract.d.ts +10 -10
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/share.contract.d.ts.map +1 -1
- package/dist/contracts/share.contract.js.map +1 -1
- package/dist/contracts/skills.contract.d.ts.map +1 -1
- package/dist/contracts/skills.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +49 -73
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +12 -2
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/usage.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/vpn.contract.d.ts.map +1 -1
- package/dist/contracts/vpn.contract.js +1 -1
- package/dist/contracts/vpn.contract.js.map +1 -1
- package/dist/contracts/webext.contract.d.ts.map +1 -1
- package/dist/contracts/webext.contract.js.map +1 -1
- package/dist/contracts/workflows.contract.d.ts +7 -6
- package/dist/contracts/workflows.contract.d.ts.map +1 -1
- package/dist/contracts/workflows.contract.js +12 -3
- package/dist/contracts/workflows.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +1237 -0
- package/dist/events/agent-events.d.ts.map +1 -0
- package/dist/events/agent-events.js +226 -0
- package/dist/events/agent-events.js.map +1 -0
- package/dist/events/cards.d.ts +404 -0
- package/dist/events/cards.d.ts.map +1 -0
- package/dist/events/cards.js +179 -0
- package/dist/events/cards.js.map +1 -0
- package/dist/events/resume.d.ts +23 -0
- package/dist/events/resume.d.ts.map +1 -0
- package/dist/events/resume.js +31 -0
- package/dist/events/resume.js.map +1 -0
- package/dist/events/system-events.d.ts +615 -0
- package/dist/events/system-events.d.ts.map +1 -0
- package/dist/events/system-events.js +64 -0
- package/dist/events/system-events.js.map +1 -0
- package/dist/events/transcript.d.ts +1755 -0
- package/dist/events/transcript.d.ts.map +1 -0
- package/dist/events/transcript.js +205 -0
- package/dist/events/transcript.js.map +1 -0
- package/dist/ids/conversation-ids.d.ts +8 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -0
- package/dist/{conversation-ids.js → ids/conversation-ids.js} +13 -0
- package/dist/ids/conversation-ids.js.map +1 -0
- package/dist/ids/hostnames.d.ts.map +1 -0
- package/dist/ids/hostnames.js.map +1 -0
- package/dist/ids/session-names.d.ts.map +1 -0
- package/dist/ids/session-names.js.map +1 -0
- package/dist/ids/share-paths.d.ts.map +1 -0
- package/dist/ids/share-paths.js.map +1 -0
- package/dist/{tunnel-ids.d.ts → ids/tunnel-ids.d.ts} +1 -0
- package/dist/ids/tunnel-ids.d.ts.map +1 -0
- package/dist/{tunnel-ids.js → ids/tunnel-ids.js} +1 -0
- package/dist/ids/tunnel-ids.js.map +1 -0
- package/dist/index.d.ts +464 -447
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -47
- package/dist/index.js.map +1 -1
- package/dist/{agent-catalog.d.ts → models/agent-catalog.d.ts} +2 -2
- package/dist/models/agent-catalog.d.ts.map +1 -0
- package/dist/models/agent-catalog.js.map +1 -0
- package/dist/models/agent-runtimes.d.ts.map +1 -0
- package/dist/models/agent-runtimes.js.map +1 -0
- package/dist/{fast-tier.d.ts → models/fast-tier.d.ts} +1 -1
- package/dist/models/fast-tier.d.ts.map +1 -0
- package/dist/models/fast-tier.js.map +1 -0
- package/dist/models/model-order.d.ts.map +1 -0
- package/dist/models/model-order.js.map +1 -0
- package/dist/{model-pins.d.ts → models/model-pins.d.ts} +2 -4
- package/dist/models/model-pins.d.ts.map +1 -0
- package/dist/models/model-pins.js +22 -0
- package/dist/models/model-pins.js.map +1 -0
- package/dist/{model-roles.d.ts → models/model-roles.d.ts} +25 -30
- package/dist/models/model-roles.d.ts.map +1 -0
- package/dist/{model-roles.js → models/model-roles.js} +30 -27
- package/dist/models/model-roles.js.map +1 -0
- package/dist/{plan-pools.d.ts → models/plan-pools.d.ts} +1 -1
- package/dist/models/plan-pools.d.ts.map +1 -0
- package/dist/models/plan-pools.js.map +1 -0
- package/dist/models/prompt-complexity.d.ts.map +1 -0
- package/dist/models/prompt-complexity.js.map +1 -0
- package/dist/models/provider-specs.d.ts.map +1 -0
- package/dist/models/provider-specs.js.map +1 -0
- package/dist/policy/approvals-execution.d.ts.map +1 -0
- package/dist/policy/approvals-execution.js.map +1 -0
- package/dist/{batch-runs.d.ts → policy/batch-runs.d.ts} +5 -1
- package/dist/policy/batch-runs.d.ts.map +1 -0
- package/dist/{batch-runs.js → policy/batch-runs.js} +10 -7
- package/dist/policy/batch-runs.js.map +1 -0
- package/dist/policy/capability-env.d.ts.map +1 -0
- package/dist/policy/capability-env.js.map +1 -0
- package/dist/policy/capability-secrets.d.ts.map +1 -0
- package/dist/policy/capability-secrets.js.map +1 -0
- package/dist/{card-status.d.ts → policy/card-status.d.ts} +2 -2
- package/dist/policy/card-status.d.ts.map +1 -0
- package/dist/{card-status.js → policy/card-status.js} +1 -5
- package/dist/policy/card-status.js.map +1 -0
- package/dist/{command-classes.d.ts → policy/command-classes.d.ts} +6 -2
- package/dist/policy/command-classes.d.ts.map +1 -0
- package/dist/{command-classes.js → policy/command-classes.js} +48 -11
- package/dist/policy/command-classes.js.map +1 -0
- package/dist/{command-run.d.ts → policy/command-run.d.ts} +1 -1
- package/dist/policy/command-run.d.ts.map +1 -0
- package/dist/policy/command-run.js.map +1 -0
- package/dist/policy/control-scopes.d.ts +16 -0
- package/dist/policy/control-scopes.d.ts.map +1 -0
- package/dist/policy/control-scopes.js +26 -0
- package/dist/policy/control-scopes.js.map +1 -0
- package/dist/policy/credential-material.d.ts.map +1 -0
- package/dist/policy/credential-material.js.map +1 -0
- package/dist/policy/needs-action.d.ts.map +1 -0
- package/dist/policy/needs-action.js.map +1 -0
- package/dist/policy/output-fields.d.ts.map +1 -0
- package/dist/policy/output-fields.js.map +1 -0
- package/dist/policy/overlay-lint.d.ts.map +1 -0
- package/dist/policy/overlay-lint.js.map +1 -0
- package/dist/policy/owner-ticket.d.ts.map +1 -0
- package/dist/{owner-ticket.js → policy/owner-ticket.js} +1 -1
- package/dist/policy/owner-ticket.js.map +1 -0
- package/dist/{safety-policy.d.ts → policy/safety-policy.d.ts} +6 -5
- package/dist/policy/safety-policy.d.ts.map +1 -0
- package/dist/{safety-policy.js → policy/safety-policy.js} +12 -12
- package/dist/policy/safety-policy.js.map +1 -0
- package/dist/policy/search-globs.d.ts.map +1 -0
- package/dist/policy/search-globs.js.map +1 -0
- package/dist/protocol/container-requirements.d.ts +20 -0
- package/dist/protocol/container-requirements.d.ts.map +1 -0
- package/dist/protocol/container-requirements.js +23 -0
- package/dist/protocol/container-requirements.js.map +1 -0
- package/dist/{host-protocol.d.ts → protocol/host-protocol.d.ts} +1 -0
- package/dist/protocol/host-protocol.d.ts.map +1 -0
- package/dist/{host-protocol.js → protocol/host-protocol.js} +1 -0
- package/dist/protocol/host-protocol.js.map +1 -0
- package/dist/protocol/ingress-contract.d.ts.map +1 -0
- package/dist/{ingress-contract.js → protocol/ingress-contract.js} +1 -1
- package/dist/protocol/ingress-contract.js.map +1 -0
- package/dist/protocol/ingress-protocol.d.ts.map +1 -0
- package/dist/protocol/ingress-protocol.js.map +1 -0
- package/dist/protocol/listener-protocol.d.ts.map +1 -0
- package/dist/{listener-protocol.js → protocol/listener-protocol.js} +1 -1
- package/dist/protocol/listener-protocol.js.map +1 -0
- package/dist/{peer-dial.d.ts → protocol/peer-dial.d.ts} +4 -1
- package/dist/protocol/peer-dial.d.ts.map +1 -0
- package/dist/{peer-dial.js → protocol/peer-dial.js} +51 -10
- package/dist/protocol/peer-dial.js.map +1 -0
- package/dist/protocol/peer-mcp-server.d.ts.map +1 -0
- package/dist/protocol/peer-mcp-server.js.map +1 -0
- package/dist/protocol/request-id.d.ts.map +1 -0
- package/dist/protocol/request-id.js.map +1 -0
- package/dist/protocol/routes.d.ts.map +1 -0
- package/dist/protocol/routes.js.map +1 -0
- package/dist/{runner-protocol.d.ts → protocol/runner-protocol.d.ts} +1 -0
- package/dist/protocol/runner-protocol.d.ts.map +1 -0
- package/dist/{runner-protocol.js → protocol/runner-protocol.js} +2 -1
- package/dist/protocol/runner-protocol.js.map +1 -0
- package/dist/protocol/sse.d.ts.map +1 -0
- package/dist/protocol/sse.js.map +1 -0
- package/dist/{terminal-protocol.d.ts → protocol/terminal-protocol.d.ts} +1 -3
- package/dist/protocol/terminal-protocol.d.ts.map +1 -0
- package/dist/protocol/terminal-protocol.js.map +1 -0
- package/dist/protocol/webext-links.d.ts.map +1 -0
- package/dist/protocol/webext-links.js.map +1 -0
- package/dist/{webext-protocol.d.ts → protocol/webext-protocol.d.ts} +1 -0
- package/dist/protocol/webext-protocol.d.ts.map +1 -0
- package/dist/{webext-protocol.js → protocol/webext-protocol.js} +1 -0
- package/dist/protocol/webext-protocol.js.map +1 -0
- package/dist/schemas/activity.d.ts +2 -0
- package/dist/schemas/activity.d.ts.map +1 -1
- package/dist/schemas/activity.js +4 -0
- package/dist/schemas/activity.js.map +1 -1
- package/dist/schemas/agent.d.ts +17 -4
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +21 -4
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +17 -4
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +15 -4
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/approvals.d.ts.map +1 -1
- package/dist/schemas/approvals.js.map +1 -1
- package/dist/schemas/automations.d.ts +54 -28
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js +26 -8
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/capabilities.d.ts +0 -8
- package/dist/schemas/capabilities.d.ts.map +1 -1
- package/dist/schemas/capabilities.js +0 -4
- package/dist/schemas/capabilities.js.map +1 -1
- package/dist/schemas/ci.d.ts +10 -0
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +9 -1
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/codebase-health.d.ts.map +1 -1
- package/dist/schemas/codebase-health.js.map +1 -1
- package/dist/schemas/devices.d.ts +90 -0
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +10 -1
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/engines.d.ts.map +1 -1
- package/dist/schemas/engines.js.map +1 -1
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/exit.d.ts.map +1 -1
- package/dist/schemas/exit.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/git-history.d.ts.map +1 -1
- package/dist/schemas/git-history.js.map +1 -1
- package/dist/schemas/git.d.ts +80 -16
- package/dist/schemas/git.d.ts.map +1 -1
- package/dist/schemas/git.js +37 -25
- package/dist/schemas/git.js.map +1 -1
- package/dist/schemas/history.d.ts.map +1 -1
- package/dist/schemas/history.js.map +1 -1
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/inventory.d.ts.map +1 -1
- package/dist/schemas/inventory.js.map +1 -1
- package/dist/schemas/issues.d.ts +0 -1
- package/dist/schemas/issues.d.ts.map +1 -1
- package/dist/schemas/issues.js +0 -1
- package/dist/schemas/issues.js.map +1 -1
- package/dist/schemas/logs.d.ts.map +1 -1
- package/dist/schemas/logs.js.map +1 -1
- package/dist/schemas/loops.d.ts.map +1 -1
- package/dist/schemas/loops.js +1 -1
- package/dist/schemas/loops.js.map +1 -1
- package/dist/schemas/maintenance.d.ts.map +1 -1
- package/dist/schemas/maintenance.js.map +1 -1
- package/dist/schemas/marketplace.d.ts +0 -4
- package/dist/schemas/marketplace.d.ts.map +1 -1
- package/dist/schemas/panels.d.ts.map +1 -1
- package/dist/schemas/panels.js.map +1 -1
- package/dist/schemas/personas.d.ts +49 -4
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +32 -5
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/plan-limits.d.ts +2 -4
- package/dist/schemas/plan-limits.d.ts.map +1 -1
- package/dist/schemas/plan-limits.js +5 -8
- package/dist/schemas/plan-limits.js.map +1 -1
- package/dist/schemas/ports.d.ts.map +1 -1
- package/dist/schemas/ports.js.map +1 -1
- package/dist/schemas/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/provider-oauth.js.map +1 -1
- package/dist/schemas/provider-subscriptions.d.ts +1 -1
- package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.js +1 -1
- package/dist/schemas/provider-subscriptions.js.map +1 -1
- package/dist/schemas/public.d.ts.map +1 -1
- package/dist/schemas/public.js.map +1 -1
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/settings.d.ts +7 -5
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +18 -8
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/share.d.ts.map +1 -1
- package/dist/schemas/share.js.map +1 -1
- package/dist/schemas/shared.d.ts +4 -0
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/schemas/shared.js +3 -0
- package/dist/schemas/shared.js.map +1 -1
- package/dist/schemas/system.d.ts +6 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +10 -0
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/usage.d.ts.map +1 -1
- package/dist/schemas/usage.js.map +1 -1
- package/dist/schemas/vpn.d.ts.map +1 -1
- package/dist/schemas/vpn.js.map +1 -1
- package/dist/schemas/webext.d.ts.map +1 -1
- package/dist/schemas/webext.js.map +1 -1
- package/dist/schemas/workflows.d.ts +66 -9
- package/dist/schemas/workflows.d.ts.map +1 -1
- package/dist/schemas/workflows.js +6 -5
- package/dist/schemas/workflows.js.map +1 -1
- package/dist/schemas/workspace-repos.d.ts.map +1 -1
- package/dist/schemas/workspace-repos.js.map +1 -1
- package/dist/schemas/workspace-search.d.ts.map +1 -1
- package/dist/schemas/workspace-search.js.map +1 -1
- package/dist/schemas/workspace-setup.d.ts.map +1 -1
- package/dist/schemas/workspace-setup.js.map +1 -1
- package/dist/schemas/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace-tree.js.map +1 -1
- package/dist/state/arrival.d.ts.map +1 -0
- package/dist/{arrival.js → state/arrival.js} +1 -1
- package/dist/state/arrival.js.map +1 -0
- package/dist/state/contract-lock.d.ts.map +1 -0
- package/dist/{contract-lock.js → state/contract-lock.js} +1 -1
- package/dist/state/contract-lock.js.map +1 -0
- package/dist/{definition.d.ts → state/definition.d.ts} +21 -17
- package/dist/state/definition.d.ts.map +1 -0
- package/dist/{definition.js → state/definition.js} +4 -4
- package/dist/state/definition.js.map +1 -0
- package/dist/state/history-state.d.ts.map +1 -0
- package/dist/{history-state.js → state/history-state.js} +1 -0
- package/dist/state/history-state.js.map +1 -0
- package/dist/state/runtime-state.d.ts.map +1 -0
- package/dist/state/runtime-state.js.map +1 -0
- package/dist/state/starter.d.ts.map +1 -0
- package/dist/state/starter.js.map +1 -0
- package/dist/state/state-portability.d.ts.map +1 -0
- package/dist/state/state-portability.js.map +1 -0
- package/dist/state/versions.d.ts.map +1 -0
- package/dist/state/versions.js.map +1 -0
- package/dist/{workspace-state.d.ts → state/workspace-state.d.ts} +8 -5
- package/dist/state/workspace-state.d.ts.map +1 -0
- package/dist/{workspace-state.js → state/workspace-state.js} +25 -1
- package/dist/state/workspace-state.js.map +1 -0
- package/dist/{documents.d.ts → text/documents.d.ts} +1 -1
- package/dist/text/documents.d.ts.map +1 -0
- package/dist/{documents.js → text/documents.js} +1 -1
- package/dist/text/documents.js.map +1 -0
- package/dist/text/embed.d.ts.map +1 -0
- package/dist/text/embed.js.map +1 -0
- package/dist/text/mentions.d.ts.map +1 -0
- package/dist/text/mentions.js.map +1 -0
- package/dist/text/model-answer.d.ts +3 -0
- package/dist/text/model-answer.d.ts.map +1 -0
- package/dist/text/model-answer.js +3 -0
- package/dist/text/model-answer.js.map +1 -0
- package/dist/text/path-refs.d.ts.map +1 -0
- package/dist/text/path-refs.js.map +1 -0
- package/dist/{shell-regions.d.ts → text/shell-regions.d.ts} +1 -1
- package/dist/text/shell-regions.d.ts.map +1 -0
- package/dist/text/shell-regions.js.map +1 -0
- package/dist/text/title.d.ts.map +1 -0
- package/dist/text/title.js.map +1 -0
- package/dist/{transcript-fold.d.ts → text/transcript-fold.d.ts} +2 -1
- package/dist/text/transcript-fold.d.ts.map +1 -0
- package/dist/{transcript-fold.js → text/transcript-fold.js} +2 -16
- package/dist/text/transcript-fold.js.map +1 -0
- package/dist/text/whisper.d.ts +3 -0
- package/dist/text/whisper.d.ts.map +1 -0
- package/dist/text/whisper.js +11 -0
- package/dist/text/whisper.js.map +1 -0
- package/dist/{workflow-faults.d.ts → text/workflow-faults.d.ts} +1 -1
- package/dist/text/workflow-faults.d.ts.map +1 -0
- package/dist/{workflow-faults.js → text/workflow-faults.js} +1 -1
- package/dist/text/workflow-faults.js.map +1 -0
- package/package.json +70 -70
- package/src/chores/chores.test.ts +4 -10
- package/src/chores/chores.ts +148 -392
- package/src/chores/digest.ts +8 -28
- package/src/chores/extension-update.ts +3 -8
- package/src/chores/fix-deps.ts +4 -18
- package/src/chores/index.ts +2 -2
- package/src/chores/probes.test.ts +7 -43
- package/src/chores/probes.ts +62 -167
- package/src/chores/prompt.ts +10 -34
- package/src/chores/stack.test.ts +6 -45
- package/src/chores/stack.ts +27 -118
- package/src/chores/verdict.test.ts +101 -80
- package/src/chores/verdict.ts +54 -99
- package/src/contracts/accounts.contract.ts +4 -19
- package/src/contracts/agent.contract.ts +7 -22
- package/src/contracts/agents.contract.ts +25 -71
- package/src/contracts/automations.contract.ts +14 -30
- package/src/contracts/capabilities.contract.ts +8 -35
- package/src/contracts/chores.contract.ts +4 -15
- package/src/contracts/endpoints.contract.ts +5 -22
- package/src/contracts/exit.contract.ts +7 -30
- package/src/contracts/extensions.contract.ts +8 -30
- package/src/contracts/git.contract.ts +25 -49
- package/src/contracts/host.contract.ts +9 -44
- package/src/contracts/intentic.contract.ts +1 -1
- package/src/contracts/logs.contract.ts +3 -13
- package/src/contracts/loops.contract.ts +9 -40
- package/src/contracts/personas.contract.ts +22 -30
- package/src/contracts/providers.contract.ts +4 -17
- package/src/contracts/runner.contract.ts +12 -39
- package/src/contracts/safety.contract.ts +5 -14
- package/src/contracts/secrets.contract.ts +4 -22
- package/src/contracts/sessions.contract.ts +1 -1
- package/src/contracts/settings.contract.ts +4 -10
- package/src/contracts/share.contract.ts +3 -9
- package/src/contracts/skills.contract.ts +4 -15
- package/src/contracts/system.contract.ts +26 -52
- package/src/contracts/usage.contract.ts +7 -21
- package/src/contracts/vpn.contract.ts +9 -16
- package/src/contracts/webext.contract.ts +9 -25
- package/src/contracts/workflows.contract.ts +34 -58
- package/src/contracts/workspace.contract.ts +19 -50
- package/src/events/agent-events.ts +345 -0
- package/src/events/cards.ts +286 -0
- package/src/{events.test.ts → events/resume.test.ts} +4 -19
- package/src/events/resume.ts +60 -0
- package/src/events/system-events.ts +139 -0
- package/src/events/transcript.ts +320 -0
- package/src/{conversation-ids.test.ts → ids/conversation-ids.test.ts} +25 -13
- package/src/ids/conversation-ids.ts +178 -0
- package/src/ids/hostnames.ts +129 -0
- package/src/ids/session-names.ts +29 -0
- package/src/ids/share-paths.ts +43 -0
- package/src/{tunnel-ids.test.ts → ids/tunnel-ids.test.ts} +1 -14
- package/src/ids/tunnel-ids.ts +29 -0
- package/src/index.ts +71 -88
- package/src/{agent-catalog.test.ts → models/agent-catalog.test.ts} +19 -93
- package/src/models/agent-catalog.ts +174 -0
- package/src/models/agent-runtimes.ts +201 -0
- package/src/models/capability-ledger.test.ts +84 -0
- package/src/{fast-tier.test.ts → models/fast-tier.test.ts} +7 -18
- package/src/models/fast-tier.ts +36 -0
- package/src/{model-order.test.ts → models/model-order.test.ts} +19 -40
- package/src/models/model-order.ts +163 -0
- package/src/models/model-pins.test.ts +87 -0
- package/src/models/model-pins.ts +57 -0
- package/src/models/model-roles.test.ts +38 -0
- package/src/models/model-roles.ts +180 -0
- package/src/{plan-pools.test.ts → models/plan-pools.test.ts} +6 -11
- package/src/models/plan-pools.ts +65 -0
- package/src/{prompt-complexity.test.ts → models/prompt-complexity.test.ts} +8 -60
- package/src/models/prompt-complexity.ts +215 -0
- package/src/{provider-specs.test.ts → models/provider-specs.test.ts} +18 -47
- package/src/models/provider-specs.ts +272 -0
- package/src/policy/approvals-execution.ts +58 -0
- package/src/{batch-runs.test.ts → policy/batch-runs.test.ts} +4 -20
- package/src/policy/batch-runs.ts +137 -0
- package/src/policy/capability-secrets.ts +5 -0
- package/src/{card-status.ts → policy/card-status.ts} +11 -26
- package/src/{command-classes.test.ts → policy/command-classes.test.ts} +11 -118
- package/src/policy/command-classes.ts +395 -0
- package/src/policy/command-run.ts +65 -0
- package/src/policy/control-scopes.ts +38 -0
- package/src/{credential-material.test.ts → policy/credential-material.test.ts} +4 -26
- package/src/policy/credential-material.ts +91 -0
- package/src/policy/needs-action.ts +5 -0
- package/src/policy/output-fields.ts +86 -0
- package/src/policy/overlay-lint.ts +100 -0
- package/src/{owner-ticket.test.ts → policy/owner-ticket.test.ts} +1 -1
- package/src/{owner-ticket.ts → policy/owner-ticket.ts} +9 -31
- package/src/policy/safety-policy.test.ts +84 -0
- package/src/policy/safety-policy.ts +142 -0
- package/src/policy/search-globs.ts +60 -0
- package/src/protocol/container-requirements.test.ts +72 -0
- package/src/protocol/container-requirements.ts +58 -0
- package/src/protocol/host-protocol.ts +29 -0
- package/src/protocol/ingress-contract.ts +103 -0
- package/src/{ingress-protocol.test.ts → protocol/ingress-protocol.test.ts} +25 -90
- package/src/protocol/ingress-protocol.ts +441 -0
- package/src/protocol/listener-protocol.ts +75 -0
- package/src/{peer-dial.test.ts → protocol/peer-dial.test.ts} +52 -1
- package/src/protocol/peer-dial.ts +207 -0
- package/src/{peer-mcp-server.ts → protocol/peer-mcp-server.ts} +16 -41
- package/src/protocol/request-id.ts +5 -0
- package/src/{routes.test.ts → protocol/routes.test.ts} +14 -22
- package/src/protocol/routes.ts +159 -0
- package/src/protocol/runner-protocol.ts +197 -0
- package/src/protocol/terminal-protocol.ts +13 -0
- package/src/protocol/webext-links.ts +50 -0
- package/src/protocol/webext-protocol.ts +24 -0
- package/src/schemas/activity.ts +22 -30
- package/src/schemas/agent.ts +130 -238
- package/src/schemas/agents.ts +165 -483
- package/src/schemas/approvals.ts +23 -71
- package/src/schemas/automations.ts +145 -249
- package/src/schemas/capabilities.ts +127 -414
- package/src/schemas/ci.ts +56 -108
- package/src/schemas/codebase-health.ts +7 -11
- package/src/schemas/devices.ts +98 -321
- package/src/schemas/engines.ts +16 -44
- package/src/schemas/environment.ts +41 -91
- package/src/schemas/exit.ts +24 -81
- package/src/schemas/extension-updates.ts +42 -87
- package/src/schemas/git-history.ts +30 -84
- package/src/schemas/git.ts +141 -256
- package/src/schemas/history.ts +14 -40
- package/src/schemas/hosts.ts +9 -15
- package/src/schemas/inventory.ts +8 -10
- package/src/schemas/issues.ts +66 -134
- package/src/schemas/logs.ts +15 -34
- package/src/schemas/loops.ts +46 -163
- package/src/schemas/maintenance.ts +47 -172
- package/src/schemas/panels.ts +20 -45
- package/src/schemas/personas.ts +85 -168
- package/src/schemas/plan-limits.ts +58 -197
- package/src/schemas/ports.ts +14 -32
- package/src/schemas/provider-oauth.ts +23 -76
- package/src/schemas/provider-subscriptions.ts +4 -13
- package/src/schemas/public.ts +4 -15
- package/src/schemas/push.ts +8 -36
- package/src/schemas/secrets.ts +20 -64
- package/src/schemas/settings.ts +177 -597
- package/src/schemas/share.ts +14 -32
- package/src/schemas/shared.ts +14 -13
- package/src/schemas/system.ts +46 -78
- package/src/schemas/terminal.ts +41 -120
- package/src/schemas/usage.ts +44 -233
- package/src/schemas/version-seam.test.ts +9 -26
- package/src/schemas/vpn.ts +27 -64
- package/src/schemas/webext.ts +22 -53
- package/src/schemas/workflows.ts +57 -183
- package/src/schemas/workspace-repos.ts +12 -24
- package/src/schemas/workspace-search.ts +17 -35
- package/src/schemas/workspace-setup.ts +4 -11
- package/src/schemas/workspace-tree.ts +32 -91
- package/src/state/arrival.ts +109 -0
- package/src/state/contract-lock.test.ts +17 -0
- package/src/state/contract-lock.ts +49 -0
- package/src/state/definition.ts +143 -0
- package/src/state/history-state.ts +103 -0
- package/src/{runtime-state.test.ts → state/runtime-state.test.ts} +3 -10
- package/src/state/runtime-state.ts +62 -0
- package/src/state/starter.ts +5 -0
- package/src/state/state-portability.ts +27 -0
- package/src/state/versions.ts +26 -0
- package/src/{workspace-state.test.ts → state/workspace-state.test.ts} +65 -173
- package/src/state/workspace-state.ts +669 -0
- package/src/{documents.test.ts → text/documents.test.ts} +1 -1
- package/src/text/documents.ts +42 -0
- package/src/text/embed.ts +132 -0
- package/src/text/mentions.ts +21 -0
- package/src/text/model-answer.ts +9 -0
- package/src/text/path-refs.ts +39 -0
- package/src/text/shell-regions.ts +224 -0
- package/src/{title.test.ts → text/title.test.ts} +13 -32
- package/src/text/title.ts +202 -0
- package/src/{transcript-fold.test.ts → text/transcript-fold.test.ts} +5 -83
- package/src/{transcript-fold.ts → text/transcript-fold.ts} +65 -170
- package/src/text/whisper.test.ts +19 -0
- package/src/text/whisper.ts +17 -0
- package/src/{workflow-faults.test.ts → text/workflow-faults.test.ts} +6 -24
- package/src/{workflow-faults.ts → text/workflow-faults.ts} +20 -60
- package/dist/agent-catalog.d.ts.map +0 -1
- package/dist/agent-catalog.js.map +0 -1
- package/dist/agent-runtimes.d.ts.map +0 -1
- package/dist/agent-runtimes.js.map +0 -1
- package/dist/approvals-execution.d.ts.map +0 -1
- package/dist/approvals-execution.js.map +0 -1
- package/dist/arrival.d.ts.map +0 -1
- package/dist/arrival.js.map +0 -1
- package/dist/batch-runs.d.ts.map +0 -1
- package/dist/batch-runs.js.map +0 -1
- package/dist/capability-env.d.ts.map +0 -1
- package/dist/capability-env.js.map +0 -1
- package/dist/capability-secrets.d.ts.map +0 -1
- package/dist/capability-secrets.js.map +0 -1
- package/dist/card-status.d.ts.map +0 -1
- package/dist/card-status.js.map +0 -1
- package/dist/command-classes.d.ts.map +0 -1
- package/dist/command-classes.js.map +0 -1
- package/dist/command-run.d.ts.map +0 -1
- package/dist/command-run.js.map +0 -1
- package/dist/contract-lock.d.ts.map +0 -1
- package/dist/contract-lock.js.map +0 -1
- package/dist/conversation-ids.d.ts +0 -4
- package/dist/conversation-ids.d.ts.map +0 -1
- package/dist/conversation-ids.js.map +0 -1
- package/dist/credential-material.d.ts.map +0 -1
- package/dist/credential-material.js.map +0 -1
- package/dist/definition.d.ts.map +0 -1
- package/dist/definition.js.map +0 -1
- package/dist/documents.d.ts.map +0 -1
- package/dist/documents.js.map +0 -1
- package/dist/embed.d.ts.map +0 -1
- package/dist/embed.js.map +0 -1
- package/dist/events.d.ts +0 -4336
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -725
- package/dist/events.js.map +0 -1
- package/dist/fast-tier.d.ts.map +0 -1
- package/dist/fast-tier.js.map +0 -1
- package/dist/history-state.d.ts.map +0 -1
- package/dist/history-state.js.map +0 -1
- package/dist/host-protocol.d.ts.map +0 -1
- package/dist/host-protocol.js.map +0 -1
- package/dist/hostnames.d.ts.map +0 -1
- package/dist/hostnames.js.map +0 -1
- package/dist/ingress-contract.d.ts.map +0 -1
- package/dist/ingress-contract.js.map +0 -1
- package/dist/ingress-protocol.d.ts.map +0 -1
- package/dist/ingress-protocol.js.map +0 -1
- package/dist/listener-protocol.d.ts.map +0 -1
- package/dist/listener-protocol.js.map +0 -1
- package/dist/mentions.d.ts.map +0 -1
- package/dist/mentions.js.map +0 -1
- package/dist/model-order.d.ts.map +0 -1
- package/dist/model-order.js.map +0 -1
- package/dist/model-pins.d.ts.map +0 -1
- package/dist/model-pins.js +0 -45
- package/dist/model-pins.js.map +0 -1
- package/dist/model-roles.d.ts.map +0 -1
- package/dist/model-roles.js.map +0 -1
- package/dist/needs-action.d.ts.map +0 -1
- package/dist/needs-action.js.map +0 -1
- package/dist/output-fields.d.ts.map +0 -1
- package/dist/output-fields.js.map +0 -1
- package/dist/overlay-lint.d.ts.map +0 -1
- package/dist/overlay-lint.js.map +0 -1
- package/dist/owner-ticket.d.ts.map +0 -1
- package/dist/owner-ticket.js.map +0 -1
- package/dist/path-refs.d.ts.map +0 -1
- package/dist/path-refs.js.map +0 -1
- package/dist/peer-dial.d.ts.map +0 -1
- package/dist/peer-dial.js.map +0 -1
- package/dist/peer-mcp-server.d.ts.map +0 -1
- package/dist/peer-mcp-server.js.map +0 -1
- package/dist/plan-pools.d.ts.map +0 -1
- package/dist/plan-pools.js.map +0 -1
- package/dist/prompt-complexity.d.ts.map +0 -1
- package/dist/prompt-complexity.js.map +0 -1
- package/dist/provider-specs.d.ts.map +0 -1
- package/dist/provider-specs.js.map +0 -1
- package/dist/request-id.d.ts.map +0 -1
- package/dist/request-id.js.map +0 -1
- package/dist/routes.d.ts.map +0 -1
- package/dist/routes.js.map +0 -1
- package/dist/runner-protocol.d.ts.map +0 -1
- package/dist/runner-protocol.js.map +0 -1
- package/dist/runtime-state.d.ts.map +0 -1
- package/dist/runtime-state.js.map +0 -1
- package/dist/safety-policy.d.ts.map +0 -1
- package/dist/safety-policy.js.map +0 -1
- package/dist/schemas/context.d.ts +0 -30
- package/dist/schemas/context.d.ts.map +0 -1
- package/dist/schemas/context.js +0 -34
- package/dist/schemas/context.js.map +0 -1
- package/dist/search-globs.d.ts.map +0 -1
- package/dist/search-globs.js.map +0 -1
- package/dist/session-names.d.ts.map +0 -1
- package/dist/session-names.js.map +0 -1
- package/dist/share-paths.d.ts.map +0 -1
- package/dist/share-paths.js.map +0 -1
- package/dist/shell-regions.d.ts.map +0 -1
- package/dist/shell-regions.js.map +0 -1
- package/dist/sse.d.ts.map +0 -1
- package/dist/sse.js.map +0 -1
- package/dist/starter.d.ts.map +0 -1
- package/dist/starter.js.map +0 -1
- package/dist/state-portability.d.ts.map +0 -1
- package/dist/state-portability.js.map +0 -1
- package/dist/terminal-protocol.d.ts.map +0 -1
- package/dist/terminal-protocol.js.map +0 -1
- package/dist/title.d.ts.map +0 -1
- package/dist/title.js.map +0 -1
- package/dist/transcript-fold.d.ts.map +0 -1
- package/dist/transcript-fold.js.map +0 -1
- package/dist/tunnel-ids.d.ts.map +0 -1
- package/dist/tunnel-ids.js.map +0 -1
- package/dist/versions.d.ts.map +0 -1
- package/dist/versions.js.map +0 -1
- package/dist/webext-links.d.ts.map +0 -1
- package/dist/webext-links.js.map +0 -1
- package/dist/webext-protocol.d.ts.map +0 -1
- package/dist/webext-protocol.js.map +0 -1
- package/dist/workflow-faults.d.ts.map +0 -1
- package/dist/workflow-faults.js.map +0 -1
- package/dist/workspace-state.d.ts.map +0 -1
- package/dist/workspace-state.js.map +0 -1
- package/src/agent-catalog.ts +0 -316
- package/src/agent-runtimes.ts +0 -419
- package/src/approvals-execution.ts +0 -96
- package/src/arrival.ts +0 -160
- package/src/batch-runs.ts +0 -188
- package/src/capability-ledger.test.ts +0 -140
- package/src/capability-secrets.ts +0 -20
- package/src/command-classes.ts +0 -617
- package/src/command-run.ts +0 -78
- package/src/contract-lock.test.ts +0 -23
- package/src/contract-lock.ts +0 -66
- package/src/conversation-ids.ts +0 -207
- package/src/credential-material.ts +0 -181
- package/src/definition.ts +0 -207
- package/src/documents.ts +0 -67
- package/src/embed.ts +0 -164
- package/src/events.ts +0 -1870
- package/src/fast-tier.ts +0 -72
- package/src/history-state.ts +0 -174
- package/src/host-protocol.ts +0 -36
- package/src/hostnames.ts +0 -180
- package/src/ingress-contract.ts +0 -157
- package/src/ingress-protocol.ts +0 -625
- package/src/listener-protocol.ts +0 -96
- package/src/mentions.ts +0 -25
- package/src/model-order.ts +0 -262
- package/src/model-pins.test.ts +0 -202
- package/src/model-pins.ts +0 -183
- package/src/model-roles.ts +0 -224
- package/src/needs-action.ts +0 -14
- package/src/output-fields.ts +0 -111
- package/src/overlay-lint.ts +0 -116
- package/src/path-refs.ts +0 -59
- package/src/peer-dial.ts +0 -163
- package/src/plan-pools.ts +0 -92
- package/src/prompt-complexity.ts +0 -334
- package/src/provider-specs.ts +0 -432
- package/src/request-id.ts +0 -41
- package/src/routes.ts +0 -219
- package/src/runner-protocol.ts +0 -239
- package/src/runtime-state.ts +0 -140
- package/src/safety-policy.test.ts +0 -88
- package/src/safety-policy.ts +0 -258
- package/src/schemas/context.ts +0 -87
- package/src/search-globs.ts +0 -76
- package/src/session-names.ts +0 -44
- package/src/share-paths.ts +0 -68
- package/src/shell-regions.ts +0 -289
- package/src/starter.ts +0 -13
- package/src/state-portability.ts +0 -56
- package/src/terminal-protocol.ts +0 -16
- package/src/title.ts +0 -267
- package/src/tunnel-ids.ts +0 -57
- package/src/versions.ts +0 -48
- package/src/webext-links.ts +0 -90
- package/src/webext-protocol.ts +0 -27
- package/src/workspace-state.ts +0 -1096
- /package/dist/{hostnames.d.ts → ids/hostnames.d.ts} +0 -0
- /package/dist/{hostnames.js → ids/hostnames.js} +0 -0
- /package/dist/{session-names.d.ts → ids/session-names.d.ts} +0 -0
- /package/dist/{session-names.js → ids/session-names.js} +0 -0
- /package/dist/{share-paths.d.ts → ids/share-paths.d.ts} +0 -0
- /package/dist/{share-paths.js → ids/share-paths.js} +0 -0
- /package/dist/{agent-catalog.js → models/agent-catalog.js} +0 -0
- /package/dist/{agent-runtimes.d.ts → models/agent-runtimes.d.ts} +0 -0
- /package/dist/{agent-runtimes.js → models/agent-runtimes.js} +0 -0
- /package/dist/{fast-tier.js → models/fast-tier.js} +0 -0
- /package/dist/{model-order.d.ts → models/model-order.d.ts} +0 -0
- /package/dist/{model-order.js → models/model-order.js} +0 -0
- /package/dist/{plan-pools.js → models/plan-pools.js} +0 -0
- /package/dist/{prompt-complexity.d.ts → models/prompt-complexity.d.ts} +0 -0
- /package/dist/{prompt-complexity.js → models/prompt-complexity.js} +0 -0
- /package/dist/{provider-specs.d.ts → models/provider-specs.d.ts} +0 -0
- /package/dist/{provider-specs.js → models/provider-specs.js} +0 -0
- /package/dist/{approvals-execution.d.ts → policy/approvals-execution.d.ts} +0 -0
- /package/dist/{approvals-execution.js → policy/approvals-execution.js} +0 -0
- /package/dist/{capability-env.d.ts → policy/capability-env.d.ts} +0 -0
- /package/dist/{capability-env.js → policy/capability-env.js} +0 -0
- /package/dist/{capability-secrets.d.ts → policy/capability-secrets.d.ts} +0 -0
- /package/dist/{capability-secrets.js → policy/capability-secrets.js} +0 -0
- /package/dist/{command-run.js → policy/command-run.js} +0 -0
- /package/dist/{credential-material.d.ts → policy/credential-material.d.ts} +0 -0
- /package/dist/{credential-material.js → policy/credential-material.js} +0 -0
- /package/dist/{needs-action.d.ts → policy/needs-action.d.ts} +0 -0
- /package/dist/{needs-action.js → policy/needs-action.js} +0 -0
- /package/dist/{output-fields.d.ts → policy/output-fields.d.ts} +0 -0
- /package/dist/{output-fields.js → policy/output-fields.js} +0 -0
- /package/dist/{overlay-lint.d.ts → policy/overlay-lint.d.ts} +0 -0
- /package/dist/{overlay-lint.js → policy/overlay-lint.js} +0 -0
- /package/dist/{owner-ticket.d.ts → policy/owner-ticket.d.ts} +0 -0
- /package/dist/{search-globs.d.ts → policy/search-globs.d.ts} +0 -0
- /package/dist/{search-globs.js → policy/search-globs.js} +0 -0
- /package/dist/{ingress-contract.d.ts → protocol/ingress-contract.d.ts} +0 -0
- /package/dist/{ingress-protocol.d.ts → protocol/ingress-protocol.d.ts} +0 -0
- /package/dist/{ingress-protocol.js → protocol/ingress-protocol.js} +0 -0
- /package/dist/{listener-protocol.d.ts → protocol/listener-protocol.d.ts} +0 -0
- /package/dist/{peer-mcp-server.d.ts → protocol/peer-mcp-server.d.ts} +0 -0
- /package/dist/{peer-mcp-server.js → protocol/peer-mcp-server.js} +0 -0
- /package/dist/{request-id.d.ts → protocol/request-id.d.ts} +0 -0
- /package/dist/{request-id.js → protocol/request-id.js} +0 -0
- /package/dist/{routes.d.ts → protocol/routes.d.ts} +0 -0
- /package/dist/{routes.js → protocol/routes.js} +0 -0
- /package/dist/{sse.d.ts → protocol/sse.d.ts} +0 -0
- /package/dist/{sse.js → protocol/sse.js} +0 -0
- /package/dist/{terminal-protocol.js → protocol/terminal-protocol.js} +0 -0
- /package/dist/{webext-links.d.ts → protocol/webext-links.d.ts} +0 -0
- /package/dist/{webext-links.js → protocol/webext-links.js} +0 -0
- /package/dist/{arrival.d.ts → state/arrival.d.ts} +0 -0
- /package/dist/{contract-lock.d.ts → state/contract-lock.d.ts} +0 -0
- /package/dist/{history-state.d.ts → state/history-state.d.ts} +0 -0
- /package/dist/{runtime-state.d.ts → state/runtime-state.d.ts} +0 -0
- /package/dist/{runtime-state.js → state/runtime-state.js} +0 -0
- /package/dist/{starter.d.ts → state/starter.d.ts} +0 -0
- /package/dist/{starter.js → state/starter.js} +0 -0
- /package/dist/{state-portability.d.ts → state/state-portability.d.ts} +0 -0
- /package/dist/{state-portability.js → state/state-portability.js} +0 -0
- /package/dist/{versions.d.ts → state/versions.d.ts} +0 -0
- /package/dist/{versions.js → state/versions.js} +0 -0
- /package/dist/{embed.d.ts → text/embed.d.ts} +0 -0
- /package/dist/{embed.js → text/embed.js} +0 -0
- /package/dist/{mentions.d.ts → text/mentions.d.ts} +0 -0
- /package/dist/{mentions.js → text/mentions.js} +0 -0
- /package/dist/{path-refs.d.ts → text/path-refs.d.ts} +0 -0
- /package/dist/{path-refs.js → text/path-refs.js} +0 -0
- /package/dist/{shell-regions.js → text/shell-regions.js} +0 -0
- /package/dist/{title.d.ts → text/title.d.ts} +0 -0
- /package/dist/{title.js → text/title.js} +0 -0
- /package/src/{hostnames.test.ts → ids/hostnames.test.ts} +0 -0
- /package/src/{share-paths.test.ts → ids/share-paths.test.ts} +0 -0
- /package/src/{capability-env.ts → policy/capability-env.ts} +0 -0
- /package/src/{overlay-lint.test.ts → policy/overlay-lint.test.ts} +0 -0
- /package/src/{search-globs.test.ts → policy/search-globs.test.ts} +0 -0
- /package/src/{ingress-contract.test.ts → protocol/ingress-contract.test.ts} +0 -0
- /package/src/{peer-mcp-server.test.ts → protocol/peer-mcp-server.test.ts} +0 -0
- /package/src/{sse.ts → protocol/sse.ts} +0 -0
- /package/src/{versions.test.ts → state/versions.test.ts} +0 -0
- /package/src/{embed.test.ts → text/embed.test.ts} +0 -0
- /package/src/{mentions.test.ts → text/mentions.test.ts} +0 -0
- /package/src/{path-refs.test.ts → text/path-refs.test.ts} +0 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { Agent, request as h1Request, type IncomingMessage, type OutgoingHttpHeaders, type ServerResponse } from "node:http";
|
|
2
|
+
import {
|
|
3
|
+
type ClientHttp2Session,
|
|
4
|
+
connect as h2Connect,
|
|
5
|
+
constants,
|
|
6
|
+
createServer as createH2Server,
|
|
7
|
+
type IncomingHttpHeaders,
|
|
8
|
+
type ServerHttp2Stream,
|
|
9
|
+
} from "node:http2";
|
|
10
|
+
import { type AddressInfo, createServer as createNetServer, connect as netConnect, type Socket } from "node:net";
|
|
11
|
+
import { Duplex } from "node:stream";
|
|
12
|
+
|
|
13
|
+
// Both ends of the ingress tunnel's h2 session, over any node Duplex, in one file: a wire format with two owners
|
|
14
|
+
// drifts. h2 gives multiplexing and backpressure for free; routing is per h2 stream, since one edge connection can
|
|
15
|
+
// interleave several sandboxes' hosts.
|
|
16
|
+
|
|
17
|
+
// Header hygiene
|
|
18
|
+
|
|
19
|
+
// Headers that must not cross a hop: h2 throws on these, and `host` is replaced by :authority.
|
|
20
|
+
const HOP_BY_HOP = new Set([
|
|
21
|
+
"connection",
|
|
22
|
+
"host",
|
|
23
|
+
"http2-settings",
|
|
24
|
+
"keep-alive",
|
|
25
|
+
"proxy-authenticate",
|
|
26
|
+
"proxy-authorization",
|
|
27
|
+
"proxy-connection",
|
|
28
|
+
"te",
|
|
29
|
+
"trailer",
|
|
30
|
+
"transfer-encoding",
|
|
31
|
+
"upgrade",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
// Headers that survive a hop: pseudo-headers and HOP_BY_HOP removed, values unchanged, including array values for a
|
|
35
|
+
// repeated field like `set-cookie`.
|
|
36
|
+
const endToEnd = (headers: IncomingHttpHeaders): OutgoingHttpHeaders => {
|
|
37
|
+
const kept: OutgoingHttpHeaders = {};
|
|
38
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
39
|
+
if (value !== undefined && !name.startsWith(":") && !HOP_BY_HOP.has(name)) {
|
|
40
|
+
kept[name] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return kept;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// The upgrade envelope
|
|
47
|
+
|
|
48
|
+
// A websocket upgrade rides a CONNECT stream, where the headers an upgrade needs (Connection, Upgrade,
|
|
49
|
+
// Sec-WebSocket-Key) are exactly the ones h2 forbids. The whole h1 request head travels prefixed under `x-ingress-*`
|
|
50
|
+
// and is rebuilt verbatim on the far side, so no header is individually allowlisted.
|
|
51
|
+
const UPGRADE_METHOD_HEADER = "x-ingress-method";
|
|
52
|
+
const UPGRADE_PATH_HEADER = "x-ingress-path";
|
|
53
|
+
const UPGRADE_HEADER_PREFIX = "x-ingress-h-";
|
|
54
|
+
|
|
55
|
+
const upgradeEnvelope = (request: IncomingMessage, authority: string): OutgoingHttpHeaders => {
|
|
56
|
+
const envelope: OutgoingHttpHeaders = {
|
|
57
|
+
[constants.HTTP2_HEADER_METHOD]: constants.HTTP2_METHOD_CONNECT,
|
|
58
|
+
[constants.HTTP2_HEADER_AUTHORITY]: authority,
|
|
59
|
+
[UPGRADE_METHOD_HEADER]: request.method ?? "GET",
|
|
60
|
+
[UPGRADE_PATH_HEADER]: request.url ?? "/",
|
|
61
|
+
};
|
|
62
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
63
|
+
if (value !== undefined) {
|
|
64
|
+
envelope[`${UPGRADE_HEADER_PREFIX}${name}`] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return envelope;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Rebuilds the h1 head an envelope carried; anything without the `x-ingress-h-` prefix is dropped as not part of the
|
|
71
|
+
// original request.
|
|
72
|
+
const upgradeHead = (headers: IncomingHttpHeaders): { method: string; path: string; headers: OutgoingHttpHeaders } => {
|
|
73
|
+
const rebuilt: OutgoingHttpHeaders = {};
|
|
74
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
75
|
+
if (value !== undefined && name.startsWith(UPGRADE_HEADER_PREFIX)) {
|
|
76
|
+
rebuilt[name.slice(UPGRADE_HEADER_PREFIX.length)] = value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
method: single(headers[UPGRADE_METHOD_HEADER]) ?? "GET",
|
|
81
|
+
path: single(headers[UPGRADE_PATH_HEADER]) ?? "/",
|
|
82
|
+
headers: rebuilt,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// First value of a header that should never repeat; a repeated one is taken as its first value.
|
|
87
|
+
const single = (value: string | string[] | undefined): string | undefined => (Array.isArray(value) ? value[0] : value);
|
|
88
|
+
|
|
89
|
+
// Serializes a response head verbatim from `rawHeaders` (order and spelling preserved) since it is written raw onto the
|
|
90
|
+
// browser's socket; latin1, since header values are opaque octets, not utf-8 text.
|
|
91
|
+
const serializeHead = (response: IncomingMessage, drop: ReadonlySet<string>, add: readonly string[]): Buffer => {
|
|
92
|
+
const lines = [`HTTP/${response.httpVersion} ${String(response.statusCode)} ${response.statusMessage ?? ""}`];
|
|
93
|
+
for (let index = 0; index + 1 < response.rawHeaders.length; index += 2) {
|
|
94
|
+
const name = response.rawHeaders[index] as string;
|
|
95
|
+
if (!drop.has(name.toLowerCase())) {
|
|
96
|
+
lines.push(`${name}: ${response.rawHeaders[index + 1] as string}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return Buffer.from(`${[...lines, ...add].join("\r\n")}\r\n\r\n`, "latin1");
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// A non-101 answer on a CONNECT stream needs re-framing: `transfer-encoding` is dropped since the body is already
|
|
103
|
+
// de-chunked, and `connection: close` delimits it instead.
|
|
104
|
+
const DECLINED_UPGRADE_DROP = new Set(["connection", "keep-alive", "transfer-encoding"]);
|
|
105
|
+
const DECLINED_UPGRADE_ADD = ["connection: close"];
|
|
106
|
+
const NOTHING_DROPPED: ReadonlySet<string> = new Set();
|
|
107
|
+
|
|
108
|
+
// Session tuning
|
|
109
|
+
|
|
110
|
+
// Session memory budget shared by every stream on the tunnel; exhausting it kills the whole session, not one request.
|
|
111
|
+
const MAX_SESSION_MEMORY_MB = 128;
|
|
112
|
+
|
|
113
|
+
// Per-stream receive window, larger than h2's 64KB default since this session crosses the internet.
|
|
114
|
+
const INITIAL_WINDOW_SIZE = 1024 * 1024;
|
|
115
|
+
|
|
116
|
+
// Concurrent stream ceiling per sandbox, raised since streams here can stay open for a session's whole life.
|
|
117
|
+
const PEER_MAX_CONCURRENT_STREAMS = 256;
|
|
118
|
+
|
|
119
|
+
// Fixed loopback address; no stream over this tunnel can be pointed anywhere but this container's own listener.
|
|
120
|
+
const LOOPBACK = "127.0.0.1";
|
|
121
|
+
|
|
122
|
+
// The splice
|
|
123
|
+
|
|
124
|
+
// Pipes both directions; `pipe` carries end-of-stream each way on its own. A failure on either side destroys both,
|
|
125
|
+
// since `destroy` is idempotent and the two handlers won't loop.
|
|
126
|
+
const splice = (left: Duplex, right: Duplex): void => {
|
|
127
|
+
left.pipe(right);
|
|
128
|
+
right.pipe(left);
|
|
129
|
+
const fail = (): void => {
|
|
130
|
+
left.destroy();
|
|
131
|
+
right.destroy();
|
|
132
|
+
};
|
|
133
|
+
left.on("error", fail);
|
|
134
|
+
right.on("error", fail);
|
|
135
|
+
// A side that closes without finishing its writes (a reset, a dropped socket) takes the other side down too;
|
|
136
|
+
// `writableFinished` distinguishes that from a graceful FIN already forwarded by the pipe.
|
|
137
|
+
left.on("close", () => {
|
|
138
|
+
if (!right.writableFinished) {
|
|
139
|
+
right.destroy();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
right.on("close", () => {
|
|
143
|
+
if (!left.writableFinished) {
|
|
144
|
+
left.destroy();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// The loopback bridge
|
|
150
|
+
|
|
151
|
+
// Bridges the caller's Duplex onto a real net.Socket: node's Duplex-over-h2 wrapper allows one write in flight, so a
|
|
152
|
+
// same-turn second write throws ERR_INTERNAL_ASSERTION and kills the process. The accepted socket is checked against
|
|
153
|
+
// the one just dialed.
|
|
154
|
+
const loopbackBridge = async (): Promise<{ session: Socket; tunnel: Socket }> => {
|
|
155
|
+
const listener = createNetServer();
|
|
156
|
+
try {
|
|
157
|
+
await new Promise<void>((resolve, reject) => {
|
|
158
|
+
listener.once("error", reject);
|
|
159
|
+
listener.listen(0, LOOPBACK, resolve);
|
|
160
|
+
});
|
|
161
|
+
const accepted = new Promise<Socket>((resolve, reject) => {
|
|
162
|
+
listener.once("connection", resolve);
|
|
163
|
+
listener.once("error", reject);
|
|
164
|
+
});
|
|
165
|
+
const tunnel = netConnect((listener.address() as AddressInfo).port, LOOPBACK);
|
|
166
|
+
await new Promise<void>((resolve, reject) => {
|
|
167
|
+
tunnel.once("connect", resolve);
|
|
168
|
+
tunnel.once("error", reject);
|
|
169
|
+
});
|
|
170
|
+
const session = await accepted;
|
|
171
|
+
if (session.remotePort !== tunnel.localPort) {
|
|
172
|
+
session.destroy();
|
|
173
|
+
tunnel.destroy();
|
|
174
|
+
throw new Error("the loopback bridge accepted a connection that was not its own");
|
|
175
|
+
}
|
|
176
|
+
// Disables Nagle: both ends are local, and frames here are already sized by h2.
|
|
177
|
+
session.setNoDelay(true);
|
|
178
|
+
tunnel.setNoDelay(true);
|
|
179
|
+
return { session, tunnel };
|
|
180
|
+
} finally {
|
|
181
|
+
listener.close();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// The ingress half: an h2 client over the tunnel
|
|
186
|
+
|
|
187
|
+
export interface IngressSession {
|
|
188
|
+
// Forwards one edge request down the tunnel. Resolves once the response is fully written; rejects on failure, and
|
|
189
|
+
// the caller reads `response.headersSent` to tell an untouched response (write your own 502) from one truncated
|
|
190
|
+
// mid-body.
|
|
191
|
+
readonly forwardRequest: (request: IncomingMessage, response: ServerResponse) => Promise<void>;
|
|
192
|
+
// Same for an upgrade, given the hijacked socket and any bytes already read past the request head. Nothing is
|
|
193
|
+
// written to `socket` until the far end accepts, so a rejection leaves it untouched for the caller to answer.
|
|
194
|
+
readonly forwardUpgrade: (request: IncomingMessage, socket: Duplex, head: Buffer) => Promise<void>;
|
|
195
|
+
// Ends the session and its bridge, which ends the caller's duplex and closes the WebSocket.
|
|
196
|
+
readonly close: () => void;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Opens the ingress side of a tunnel; async since the bridge itself is. The connect URL is a placeholder — this session
|
|
200
|
+
// has no host of its own, every request supplies the authority it's routed by.
|
|
201
|
+
export const openIngressSession = async (duplex: Duplex): Promise<IngressSession> => {
|
|
202
|
+
const bridge = await loopbackBridge();
|
|
203
|
+
splice(bridge.tunnel, duplex);
|
|
204
|
+
const session: ClientHttp2Session = h2Connect("http://tunnel.invalid", {
|
|
205
|
+
createConnection: () => bridge.session,
|
|
206
|
+
maxSessionMemory: MAX_SESSION_MEMORY_MB,
|
|
207
|
+
peerMaxConcurrentStreams: PEER_MAX_CONCURRENT_STREAMS,
|
|
208
|
+
settings: { initialWindowSize: INITIAL_WINDOW_SIZE },
|
|
209
|
+
});
|
|
210
|
+
// Without a handler here, a dead or hostile peer raises an uncaught exception and takes every other sandbox's
|
|
211
|
+
// tunnel down with it. Destroying the duplex closes the WebSocket, which the reconnect loop waits on.
|
|
212
|
+
session.on("error", () => duplex.destroy());
|
|
213
|
+
session.on("close", () => duplex.destroy());
|
|
214
|
+
|
|
215
|
+
// Authority to route the stream by. The ingress already refuses any Host that doesn't own a sandbox, so a request
|
|
216
|
+
// with no Host here is a caller bug, not a routing decision.
|
|
217
|
+
const authorityOf = (request: IncomingMessage): string => {
|
|
218
|
+
const host = request.headers.host;
|
|
219
|
+
if (host === undefined || host === "") {
|
|
220
|
+
throw new Error("an ingress request is routed by its Host header, and this one has none");
|
|
221
|
+
}
|
|
222
|
+
return host;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const forwardRequest = (request: IncomingMessage, response: ServerResponse): Promise<void> =>
|
|
226
|
+
new Promise<void>((resolve, reject) => {
|
|
227
|
+
const authority = authorityOf(request);
|
|
228
|
+
// `endStream: false` for every method, not only ones that may carry a body: the request is piped
|
|
229
|
+
// regardless, and an already-ended GET closes the stream with an empty frame.
|
|
230
|
+
const stream = session.request(
|
|
231
|
+
{
|
|
232
|
+
[constants.HTTP2_HEADER_METHOD]: request.method ?? "GET",
|
|
233
|
+
[constants.HTTP2_HEADER_PATH]: request.url ?? "/",
|
|
234
|
+
[constants.HTTP2_HEADER_AUTHORITY]: authority,
|
|
235
|
+
// The edge is HTTPS-only, so this is what the browser used; nothing here routes on it.
|
|
236
|
+
[constants.HTTP2_HEADER_SCHEME]: "https",
|
|
237
|
+
...endToEnd(request.headers),
|
|
238
|
+
},
|
|
239
|
+
{ endStream: false },
|
|
240
|
+
);
|
|
241
|
+
request.pipe(stream);
|
|
242
|
+
|
|
243
|
+
// The browser giving up must reach the daemon: without this, a closed tab leaves the h2 stream, the
|
|
244
|
+
// daemon's own request, and any long-lived generator (SSE) running for nobody. RST_STREAM(CANCEL) unwinds
|
|
245
|
+
// all three.
|
|
246
|
+
response.on("close", () => {
|
|
247
|
+
if (!response.writableFinished) {
|
|
248
|
+
stream.close(constants.NGHTTP2_CANCEL);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
stream.on("response", (headers) => {
|
|
253
|
+
if (response.destroyed) {
|
|
254
|
+
stream.close(constants.NGHTTP2_CANCEL);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
response.writeHead(Number(headers[constants.HTTP2_HEADER_STATUS] ?? 502), endToEnd(headers));
|
|
258
|
+
stream.pipe(response);
|
|
259
|
+
});
|
|
260
|
+
stream.on("error", reject);
|
|
261
|
+
// The response resolves on `finish`, once node has flushed it to the browser, not merely when the h2 stream
|
|
262
|
+
// closes.
|
|
263
|
+
response.on("finish", resolve);
|
|
264
|
+
stream.on("close", () => {
|
|
265
|
+
if (!response.writableEnded) {
|
|
266
|
+
reject(new Error("the tunnel closed the stream before the response was complete"));
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const forwardUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer): Promise<void> =>
|
|
272
|
+
new Promise<void>((resolve, reject) => {
|
|
273
|
+
const stream = session.request(upgradeEnvelope(request, authorityOf(request)), { endStream: false });
|
|
274
|
+
stream.on("error", reject);
|
|
275
|
+
stream.once("response", (headers) => {
|
|
276
|
+
const status = Number(headers[constants.HTTP2_HEADER_STATUS]);
|
|
277
|
+
if (status !== constants.HTTP_STATUS_OK) {
|
|
278
|
+
// The far end refused the upgrade; nothing has reached the browser yet, so the caller still owns
|
|
279
|
+
// the socket.
|
|
280
|
+
stream.close(constants.NGHTTP2_CANCEL);
|
|
281
|
+
reject(new Error(`the tunnel refused an upgrade with :status ${String(status)}`));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// Bytes the client already sent past its request head; dropped, the handshake completes and then hangs
|
|
285
|
+
// on a frame nobody has.
|
|
286
|
+
if (head.length > 0) {
|
|
287
|
+
stream.write(head);
|
|
288
|
+
}
|
|
289
|
+
splice(stream, socket);
|
|
290
|
+
resolve();
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
forwardRequest,
|
|
296
|
+
forwardUpgrade,
|
|
297
|
+
// Graceful GOAWAY first, then the bridge's far half, which the session itself knows nothing about.
|
|
298
|
+
close: () => {
|
|
299
|
+
session.close(() => bridge.tunnel.destroy());
|
|
300
|
+
bridge.tunnel.end();
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// The daemon half: an h2 server over the tunnel, onto the loopback listener
|
|
306
|
+
|
|
307
|
+
export interface ServeIngressSessionOptions {
|
|
308
|
+
// The daemon's own listener; every stream lands there as a plain HTTP/1.1 request or upgrade.
|
|
309
|
+
readonly targetPort: number;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface IngressSessionServer {
|
|
313
|
+
// Sends GOAWAY over the bridge, which ends the caller's duplex once it's done writing the shutdown frame. The
|
|
314
|
+
// WebSocket itself belongs to whoever dialed it.
|
|
315
|
+
readonly close: () => void;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// One h2 server per session, bound to nothing; it exists only to be handed a connection. The h1 hop to the loopback
|
|
319
|
+
// listener runs over a keep-alive agent, so steady traffic reuses sockets; the upgrade path does not.
|
|
320
|
+
export const serveIngressSession = async (duplex: Duplex, options: ServeIngressSessionOptions): Promise<IngressSessionServer> => {
|
|
321
|
+
const bridge = await loopbackBridge();
|
|
322
|
+
splice(bridge.tunnel, duplex);
|
|
323
|
+
const agent = new Agent({ keepAlive: true, maxSockets: PEER_MAX_CONCURRENT_STREAMS });
|
|
324
|
+
const server = createH2Server({
|
|
325
|
+
maxSessionMemory: MAX_SESSION_MEMORY_MB,
|
|
326
|
+
settings: { initialWindowSize: INITIAL_WINDOW_SIZE },
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// A failed session is news for the reconnect loop, not an uncaught exception that takes the whole daemon down.
|
|
330
|
+
// Destroying the duplex closes the WebSocket the loop waits on; `clientError` should never fire but isn't worth
|
|
331
|
+
// crashing over either.
|
|
332
|
+
server.on("sessionError", () => duplex.destroy());
|
|
333
|
+
server.on("clientError", () => duplex.destroy());
|
|
334
|
+
server.on("error", () => duplex.destroy());
|
|
335
|
+
|
|
336
|
+
const forwardToLoopback = (stream: ServerHttp2Stream, headers: IncomingHttpHeaders): void => {
|
|
337
|
+
const local = h1Request({
|
|
338
|
+
host: LOOPBACK,
|
|
339
|
+
port: options.targetPort,
|
|
340
|
+
method: single(headers[constants.HTTP2_HEADER_METHOD]) ?? "GET",
|
|
341
|
+
path: single(headers[constants.HTTP2_HEADER_PATH]) ?? "/",
|
|
342
|
+
// The Host the request was made to, restored where an h1 server reads it; this alone tells a preview, a
|
|
343
|
+
// port and the daemon apart.
|
|
344
|
+
headers: { host: single(headers[constants.HTTP2_HEADER_AUTHORITY]) ?? "", ...endToEnd(headers) },
|
|
345
|
+
agent,
|
|
346
|
+
});
|
|
347
|
+
stream.pipe(local);
|
|
348
|
+
local.on("response", (response) => {
|
|
349
|
+
stream.respond({ [constants.HTTP2_HEADER_STATUS]: response.statusCode ?? 502, ...endToEnd(response.headers) });
|
|
350
|
+
response.pipe(stream);
|
|
351
|
+
});
|
|
352
|
+
// The listener isn't answering; closed with an error code rather than a 502 of our own, since the ingress owns
|
|
353
|
+
// what an unreachable sandbox looks like.
|
|
354
|
+
local.on("error", () => stream.close(constants.NGHTTP2_INTERNAL_ERROR));
|
|
355
|
+
stream.on("error", () => local.destroy());
|
|
356
|
+
// The edge cancelled (RST_STREAM); stop generating a response nobody reads. `aborted` is the only event that
|
|
357
|
+
// means this — on a reset, node fires `aborted` before `finish` and `close`, so a
|
|
358
|
+
// `writableEnded`/`writableFinished` guard there would miss it.
|
|
359
|
+
stream.on("aborted", () => local.destroy());
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const spliceUpgrade = (stream: ServerHttp2Stream, headers: IncomingHttpHeaders): void => {
|
|
363
|
+
const head = upgradeHead(headers);
|
|
364
|
+
// `agent: false`: an upgraded connection stops being HTTP once accepted and can never return to the keep-alive
|
|
365
|
+
// pool the request path above uses.
|
|
366
|
+
const local = h1Request({ host: LOOPBACK, port: options.targetPort, method: head.method, path: head.path, headers: head.headers, agent: false });
|
|
367
|
+
local.on("upgrade", (response, socket, first) => {
|
|
368
|
+
stream.respond({ [constants.HTTP2_HEADER_STATUS]: constants.HTTP_STATUS_OK });
|
|
369
|
+
// Response head written verbatim (see serializeHead), then any bytes already sent past it, then the pipe.
|
|
370
|
+
stream.write(serializeHead(response, NOTHING_DROPPED, []));
|
|
371
|
+
if (first.length > 0) {
|
|
372
|
+
stream.write(first);
|
|
373
|
+
}
|
|
374
|
+
splice(stream, socket);
|
|
375
|
+
});
|
|
376
|
+
// The local server declined to upgrade; its answer goes to the browser with framing that matches the already
|
|
377
|
+
// de-chunked body.
|
|
378
|
+
local.on("response", (response) => {
|
|
379
|
+
stream.respond({ [constants.HTTP2_HEADER_STATUS]: constants.HTTP_STATUS_OK });
|
|
380
|
+
stream.write(serializeHead(response, DECLINED_UPGRADE_DROP, DECLINED_UPGRADE_ADD));
|
|
381
|
+
response.pipe(stream);
|
|
382
|
+
});
|
|
383
|
+
local.on("error", () => stream.close(constants.NGHTTP2_CONNECT_ERROR));
|
|
384
|
+
// An upgrade request carries no body; the client is waiting on the handshake before it says anything else.
|
|
385
|
+
local.end();
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
server.on("stream", (stream, headers) => {
|
|
389
|
+
if (headers[constants.HTTP2_HEADER_METHOD] === constants.HTTP2_METHOD_CONNECT) {
|
|
390
|
+
spliceUpgrade(stream, headers);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
forwardToLoopback(stream, headers);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Creates a server-side session without a listener: the server never binds, it is simply handed a connection.
|
|
397
|
+
server.emit("connection", bridge.session);
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
close: () => {
|
|
401
|
+
agent.destroy();
|
|
402
|
+
server.close();
|
|
403
|
+
bridge.tunnel.end();
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// Reimplements `ws`'s createWebSocketStream, which Bun does not support, so both runtimes get the same Duplex.
|
|
409
|
+
// Preserves byte safety: the write callback fires only once the socket has taken the frame, and a closed socket ends
|
|
410
|
+
// the readable side with `push(null)`.
|
|
411
|
+
export interface TunnelWebSocket {
|
|
412
|
+
readonly send: (data: Buffer, options: { binary: boolean }, callback: (error?: Error) => void) => void;
|
|
413
|
+
readonly close: () => void;
|
|
414
|
+
readonly on: {
|
|
415
|
+
(event: `message`, listener: (data: unknown) => void): unknown;
|
|
416
|
+
(event: `close`, listener: () => void): unknown;
|
|
417
|
+
(event: `error`, listener: (error: Error) => void): unknown;
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export const webSocketDuplex = (socket: TunnelWebSocket): Duplex => {
|
|
422
|
+
const duplex = new Duplex({
|
|
423
|
+
read: () => {},
|
|
424
|
+
write: (chunk: Buffer, _encoding, callback) => {
|
|
425
|
+
socket.send(chunk, { binary: true }, (error) => callback(error ?? null));
|
|
426
|
+
},
|
|
427
|
+
// Half-closing a WebSocket isn't possible; ending the writable side closes the socket outright.
|
|
428
|
+
final: (callback) => {
|
|
429
|
+
socket.close();
|
|
430
|
+
callback();
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
// `message` carries a Buffer for binary frames; a stray text frame arrives as a string and is coerced rather than
|
|
434
|
+
// dropped.
|
|
435
|
+
socket.on(`message`, (data: unknown) => {
|
|
436
|
+
duplex.push(Buffer.isBuffer(data) ? data : Buffer.from(data as string));
|
|
437
|
+
});
|
|
438
|
+
socket.on(`close`, () => duplex.push(null));
|
|
439
|
+
socket.on(`error`, (error: Error) => duplex.destroy(error));
|
|
440
|
+
return duplex;
|
|
441
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ActivityStatusSchema } from "../schemas/activity.js";
|
|
3
|
+
|
|
4
|
+
// Wire between the daemon and an extension's realtime-listener gateway (ext-discord, ext-slack, ext-telegram,
|
|
5
|
+
// ext-whatsapp, ext-imap): the four /listeners/:provider routes (state, dispatch, failure, status). Shared here so both
|
|
6
|
+
// ends compile against one declaration.
|
|
7
|
+
|
|
8
|
+
// One normalized inbound event: the JSON body a realtime source POSTs to /listeners/<provider>/dispatch. A zod schema
|
|
9
|
+
// since it's parsed from untrusted gateway input; `provider` and `type` are open strings, not a core enum.
|
|
10
|
+
export const ListenerMessageSchema = z.object({
|
|
11
|
+
provider: z.string().min(1),
|
|
12
|
+
type: z.string().min(1),
|
|
13
|
+
id: z.string(),
|
|
14
|
+
channelId: z.string(),
|
|
15
|
+
author: z.object({ id: z.string(), name: z.string() }),
|
|
16
|
+
content: z.string(),
|
|
17
|
+
// Discord only: the message @mentions or replies to one of our bots; voice events never set it.
|
|
18
|
+
mentioned: z.boolean().optional(),
|
|
19
|
+
// CI pipeline event: the ref it ran on. Top-level, not in `extra`, since the dispatcher matches triggers on it.
|
|
20
|
+
branch: z.string().optional(),
|
|
21
|
+
// Prior channel messages fetched when tagged; top-level so it reaches the model but skips the activity feed.
|
|
22
|
+
history: z
|
|
23
|
+
.array(
|
|
24
|
+
z.object({
|
|
25
|
+
author: z.object({ id: z.string(), name: z.string() }),
|
|
26
|
+
content: z.string(),
|
|
27
|
+
timestamp: z.string(),
|
|
28
|
+
self: z.boolean().optional(),
|
|
29
|
+
}),
|
|
30
|
+
)
|
|
31
|
+
.optional(),
|
|
32
|
+
timestamp: z.string(),
|
|
33
|
+
// Provider-specific fields:
|
|
34
|
+
// - discord message: guildId, attachments
|
|
35
|
+
// - voice_utterance: path
|
|
36
|
+
// - voice_transcript: path, participants, durationSeconds
|
|
37
|
+
extra: z.record(z.string(), z.unknown()).optional(),
|
|
38
|
+
});
|
|
39
|
+
export type ListenerMessage = z.infer<typeof ListenerMessageSchema>;
|
|
40
|
+
|
|
41
|
+
// One ndjson frame of a /listeners/<provider>/dispatch?stream=1 response: a text delta, a failure sentence, or a
|
|
42
|
+
// terminal marker. A type, not a schema, since only the daemon produces these.
|
|
43
|
+
export interface ListenerDispatchFrame {
|
|
44
|
+
readonly automationId: string;
|
|
45
|
+
readonly delta?: string;
|
|
46
|
+
// The turn's failure, forwarded verbatim since a gateway delivers it into the owner's own channel.
|
|
47
|
+
readonly failed?: string;
|
|
48
|
+
readonly end?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Where a device-linking ceremony stands (whatsapp), reported per status tick; every state here means not yet paired.
|
|
52
|
+
// `since` stamps the current code's age, since WhatsApp reissues a fresh one on each reopen.
|
|
53
|
+
export const ListenerPairingSchema = z.object({
|
|
54
|
+
// waiting: socket up, no code yet (or the last one died with its socket)
|
|
55
|
+
// code: `code` is live, type it on the phone
|
|
56
|
+
// failed: `detail` says what WhatsApp refused
|
|
57
|
+
state: z.enum(["waiting", "code", "failed"]),
|
|
58
|
+
code: z.string().optional(),
|
|
59
|
+
detail: z.string().optional(),
|
|
60
|
+
since: z.number().optional(),
|
|
61
|
+
});
|
|
62
|
+
export type ListenerPairing = z.infer<typeof ListenerPairingSchema>;
|
|
63
|
+
|
|
64
|
+
// Push-based status: a gateway POSTs its connection/voice snapshot to /listeners/<provider>/status, since the daemon
|
|
65
|
+
// holds no provider connection to probe itself. Extends ActivityStatus with whisper's voice-pending flag and each
|
|
66
|
+
// unpaired capability's pairing ceremony by id.
|
|
67
|
+
export const ListenerStatusSchema = ActivityStatusSchema.extend({
|
|
68
|
+
whisperReady: z.boolean().optional(),
|
|
69
|
+
pairing: z.record(z.string(), ListenerPairingSchema).optional(),
|
|
70
|
+
});
|
|
71
|
+
export type ListenerStatus = z.infer<typeof ListenerStatusSchema>;
|
|
72
|
+
|
|
73
|
+
// A connection's place in the reconcile lifecycle: `idle` is up but intentionally holding nothing (no enabled
|
|
74
|
+
// automation), `pairing` is up but waiting on an uncompleted credential ceremony; the rest are the connect loop.
|
|
75
|
+
export type ListenerGatewayPhase = "idle" | "ready" | "pairing" | "connecting" | "disconnected";
|
|
@@ -11,7 +11,7 @@ class FakeSocket implements SocketLike {
|
|
|
11
11
|
closed: { readonly code: number | undefined; readonly reason: string | undefined } | undefined;
|
|
12
12
|
private readonly listeners = new Map<string, Set<(event: { readonly code?: number }) => void>>();
|
|
13
13
|
|
|
14
|
-
addEventListener(type: "open" | "close" | "error", listener: (event: { readonly code?: number }) => void): void {
|
|
14
|
+
addEventListener(type: "open" | "close" | "error" | "message", listener: (event: { readonly code?: number }) => void): void {
|
|
15
15
|
const set = this.listeners.get(type) ?? new Set();
|
|
16
16
|
set.add(listener);
|
|
17
17
|
this.listeners.set(type, set);
|
|
@@ -31,6 +31,10 @@ class FakeSocket implements SocketLike {
|
|
|
31
31
|
this.readyState = 3;
|
|
32
32
|
this.emit("close", code);
|
|
33
33
|
}
|
|
34
|
+
// A frame from the sandbox: the heartbeat, or any call. Only that one arrived matters to the loop.
|
|
35
|
+
says(): void {
|
|
36
|
+
this.emit("message");
|
|
37
|
+
}
|
|
34
38
|
private emit(type: string, code?: number): void {
|
|
35
39
|
for (const listener of this.listeners.get(type) ?? []) {
|
|
36
40
|
listener(code === undefined ? {} : { code });
|
|
@@ -38,6 +42,9 @@ class FakeSocket implements SocketLike {
|
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
// This door's silence deadline, named so the assertions can read it off the same number the loop is given.
|
|
46
|
+
const SILENCE_MS = 30_000;
|
|
47
|
+
|
|
41
48
|
// A ladder that answers with a fixed delay and records what it was told, so the test can read the held time.
|
|
42
49
|
const ladder = (delay = 1_000) => {
|
|
43
50
|
const held: number[] = [];
|
|
@@ -64,6 +71,7 @@ const dialling = () => {
|
|
|
64
71
|
hello: () => ({ type: "hello", token: "iht_test", version: "1.0.0" }),
|
|
65
72
|
attach: (socket) => void attached.push(socket),
|
|
66
73
|
backoff: ladder(),
|
|
74
|
+
silenceMs: SILENCE_MS,
|
|
67
75
|
log: (message) => void said.push(message),
|
|
68
76
|
revoked,
|
|
69
77
|
});
|
|
@@ -105,6 +113,46 @@ test("a drop redials on the ladder, telling it how long the socket held", async
|
|
|
105
113
|
}
|
|
106
114
|
});
|
|
107
115
|
|
|
116
|
+
/* THE DROP NOBODY REPORTS, which is the one that used to last for days: a far end that is gone while the socket
|
|
117
|
+
* stays open — a sandbox container recreated behind a port relay that outlived it, a NAT that forgot the flow, a
|
|
118
|
+
* laptop's wifi suspended mid-session. Note what this test never calls: `drops`. Nothing closes, nothing errors,
|
|
119
|
+
* and the loop has to reach the conclusion on its own or hold a dead link forever. */
|
|
120
|
+
test("a socket that goes silent is abandoned and redialled, though no close ever arrives", async () => {
|
|
121
|
+
vi.useFakeTimers();
|
|
122
|
+
try {
|
|
123
|
+
const { link, sockets, said } = dialling();
|
|
124
|
+
await vi.waitFor(() => expect(sockets).toHaveLength(1));
|
|
125
|
+
sockets[0]?.opens();
|
|
126
|
+
|
|
127
|
+
// A frame inside every window holds the link: this is the sandbox's heartbeat, three beats of it.
|
|
128
|
+
for (let beat = 0; beat < 3; beat += 1) {
|
|
129
|
+
await vi.advanceTimersByTimeAsync(SILENCE_MS - 1_000);
|
|
130
|
+
sockets[0]?.says();
|
|
131
|
+
}
|
|
132
|
+
expect(link.state()).toBe("open");
|
|
133
|
+
expect(sockets).toHaveLength(1);
|
|
134
|
+
|
|
135
|
+
// Then the beats stop, and nothing else happens: no close, no error.
|
|
136
|
+
await vi.advanceTimersByTimeAsync(SILENCE_MS);
|
|
137
|
+
expect(said.at(-1)).toBe(`nothing heard for ${SILENCE_MS / 1_000}s; reconnecting in 1s`);
|
|
138
|
+
expect(sockets[0]?.closed).toEqual({ code: 1000, reason: "no heartbeat" });
|
|
139
|
+
expect(link.state()).toBe("connecting");
|
|
140
|
+
|
|
141
|
+
await vi.advanceTimersByTimeAsync(1_000);
|
|
142
|
+
await vi.waitFor(() => expect(sockets).toHaveLength(2));
|
|
143
|
+
|
|
144
|
+
// The close an abandoned socket may still emit minutes later must not put a second loop on the link.
|
|
145
|
+
sockets[0]?.drops(1006);
|
|
146
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
147
|
+
expect(sockets).toHaveLength(2);
|
|
148
|
+
|
|
149
|
+
link.stop();
|
|
150
|
+
await link.done;
|
|
151
|
+
} finally {
|
|
152
|
+
vi.useRealTimers();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
108
156
|
test("a refused enrollment (1008) is never retried and is reported once", async () => {
|
|
109
157
|
vi.useFakeTimers();
|
|
110
158
|
try {
|
|
@@ -142,6 +190,7 @@ test("a stop during resolution opens nothing, and a socket a slow resolver still
|
|
|
142
190
|
hello: () => ({}),
|
|
143
191
|
attach: () => undefined,
|
|
144
192
|
backoff: ladder(),
|
|
193
|
+
silenceMs: SILENCE_MS,
|
|
145
194
|
log: () => undefined,
|
|
146
195
|
revoked: () => undefined,
|
|
147
196
|
});
|
|
@@ -166,6 +215,7 @@ test("a stop during resolution opens nothing, and a socket a slow resolver still
|
|
|
166
215
|
hello: () => ({}),
|
|
167
216
|
attach: () => undefined,
|
|
168
217
|
backoff: ladder(),
|
|
218
|
+
silenceMs: SILENCE_MS,
|
|
169
219
|
log: () => undefined,
|
|
170
220
|
revoked: () => undefined,
|
|
171
221
|
});
|
|
@@ -191,6 +241,7 @@ test("a pairing that is gone by the next attempt ends the loop rather than diall
|
|
|
191
241
|
hello: () => ({}),
|
|
192
242
|
attach: () => undefined,
|
|
193
243
|
backoff: ladder(0),
|
|
244
|
+
silenceMs: SILENCE_MS,
|
|
194
245
|
log: () => undefined,
|
|
195
246
|
revoked: () => undefined,
|
|
196
247
|
});
|