@intentic/sandbox-contract 1.326.0 → 1.328.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 +24 -12
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +29 -20
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/probes.d.ts +1 -0
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js +81 -12
- package/dist/chores/probes.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +1467 -6
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +2 -2
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +1391 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +1 -1
- package/dist/contracts/automations.contract.d.ts +123 -4
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +13 -2
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +79 -8
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/chores.contract.d.ts +2 -0
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.d.ts +2 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.d.ts +52 -0
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +2 -0
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +42 -33
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +17 -7
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +192 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js +37 -1
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/needs.contract.d.ts +1009 -0
- package/dist/contracts/needs.contract.d.ts.map +1 -1
- package/dist/contracts/pages.contract.d.ts +34 -0
- package/dist/contracts/pages.contract.d.ts.map +1 -0
- package/dist/contracts/pages.contract.js +49 -0
- package/dist/contracts/pages.contract.js.map +1 -0
- package/dist/contracts/phone.contract.d.ts +78 -0
- package/dist/contracts/phone.contract.d.ts.map +1 -0
- package/dist/contracts/phone.contract.js +11 -0
- package/dist/contracts/phone.contract.js.map +1 -0
- package/dist/contracts/privacy.contract.d.ts +20 -0
- package/dist/contracts/privacy.contract.d.ts.map +1 -1
- package/dist/contracts/privacy.contract.js +12 -2
- package/dist/contracts/privacy.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +648 -127
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +1 -1
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +88 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +20 -1
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +184 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +16 -58
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +10 -1
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +227 -32
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +18 -1
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/documents/conversions.d.ts.map +1 -1
- package/dist/documents/conversions.js +2 -1
- package/dist/documents/conversions.js.map +1 -1
- package/dist/documents/read.d.ts.map +1 -1
- package/dist/documents/read.js +4 -4
- package/dist/documents/read.js.map +1 -1
- package/dist/events/agent-events.d.ts +747 -1
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +14 -1
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/requests.d.ts +40 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/requests.js +39 -0
- package/dist/events/requests.js.map +1 -1
- package/dist/events/system-events.d.ts +120 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/transcript.d.ts +1131 -1
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +9 -1
- package/dist/events/transcript.js.map +1 -1
- package/dist/ids/hostnames.d.ts +2 -0
- package/dist/ids/hostnames.d.ts.map +1 -1
- package/dist/ids/hostnames.js +18 -15
- package/dist/ids/hostnames.js.map +1 -1
- package/dist/ids/sandbox-id.d.ts +2 -0
- package/dist/ids/sandbox-id.d.ts.map +1 -0
- package/dist/ids/sandbox-id.js +2 -0
- package/dist/ids/sandbox-id.js.map +1 -0
- package/dist/ids/tunnel-ids.d.ts +1 -1
- package/dist/ids/tunnel-ids.d.ts.map +1 -1
- package/dist/ids/tunnel-ids.js +1 -1
- package/dist/ids/tunnel-ids.js.map +1 -1
- package/dist/index.d.ts +4902 -177
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -9
- package/dist/index.js.map +1 -1
- package/dist/models/agent-catalog.d.ts +0 -1
- package/dist/models/agent-catalog.d.ts.map +1 -1
- package/dist/models/agent-catalog.js +0 -1
- package/dist/models/agent-catalog.js.map +1 -1
- package/dist/models/agent-runtimes.d.ts +1 -1
- package/dist/models/agent-runtimes.d.ts.map +1 -1
- package/dist/models/agent-runtimes.js +1 -1
- package/dist/models/agent-runtimes.js.map +1 -1
- package/dist/models/provider-specs.d.ts +1 -0
- package/dist/models/provider-specs.d.ts.map +1 -1
- package/dist/models/provider-specs.js +11 -0
- package/dist/models/provider-specs.js.map +1 -1
- package/dist/netd/browser-wire.d.ts.map +1 -0
- package/dist/netd/browser-wire.js.map +1 -0
- package/dist/{front → netd}/generated/browser-wire.d.ts +8 -0
- package/dist/netd/generated/browser-wire.d.ts.map +1 -0
- package/dist/netd/generated/browser-wire.js.map +1 -0
- package/dist/{front → netd}/generated/wire.d.ts +20 -11
- package/dist/netd/generated/wire.d.ts.map +1 -0
- package/dist/{front → netd}/generated/wire.js.map +1 -1
- package/dist/netd/netd-wire.d.ts +9 -0
- package/dist/netd/netd-wire.d.ts.map +1 -0
- package/dist/netd/netd-wire.js +8 -0
- package/dist/netd/netd-wire.js.map +1 -0
- package/dist/policy/credential-material.d.ts +2 -0
- package/dist/policy/credential-material.d.ts.map +1 -1
- package/dist/policy/credential-material.js +14 -8
- package/dist/policy/credential-material.js.map +1 -1
- package/dist/policy/message-limits.d.ts +14 -0
- package/dist/policy/message-limits.d.ts.map +1 -0
- package/dist/policy/message-limits.js +15 -0
- package/dist/policy/message-limits.js.map +1 -0
- package/dist/policy/request-status.d.ts.map +1 -1
- package/dist/policy/request-status.js +9 -1
- 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 +1 -0
- 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 +2 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/container-requirements.d.ts.map +1 -1
- package/dist/protocol/container-requirements.js +3 -4
- package/dist/protocol/container-requirements.js.map +1 -1
- package/dist/protocol/doors/host-protocol.d.ts.map +1 -0
- package/dist/protocol/doors/host-protocol.js.map +1 -0
- package/dist/protocol/{listener-protocol.d.ts → doors/listener-protocol.d.ts} +22 -0
- package/dist/protocol/doors/listener-protocol.d.ts.map +1 -0
- package/dist/protocol/doors/listener-protocol.js +38 -0
- package/dist/protocol/doors/listener-protocol.js.map +1 -0
- package/dist/protocol/doors/phone-links.d.ts +16 -0
- package/dist/protocol/doors/phone-links.d.ts.map +1 -0
- package/dist/protocol/doors/phone-links.js +28 -0
- package/dist/protocol/doors/phone-links.js.map +1 -0
- package/dist/protocol/doors/phone-protocol.d.ts +47 -0
- package/dist/protocol/doors/phone-protocol.d.ts.map +1 -0
- package/dist/protocol/doors/phone-protocol.js +33 -0
- package/dist/protocol/doors/phone-protocol.js.map +1 -0
- package/dist/protocol/doors/runner-protocol.d.ts.map +1 -0
- package/dist/protocol/{runner-protocol.js → doors/runner-protocol.js} +1 -1
- package/dist/protocol/doors/runner-protocol.js.map +1 -0
- package/dist/protocol/{webext-links.d.ts → doors/webext-links.d.ts} +1 -0
- package/dist/protocol/doors/webext-links.d.ts.map +1 -0
- package/dist/protocol/{webext-links.js → doors/webext-links.js} +1 -0
- package/dist/protocol/doors/webext-links.js.map +1 -0
- package/dist/protocol/doors/webext-protocol.d.ts.map +1 -0
- package/dist/protocol/doors/webext-protocol.js.map +1 -0
- package/dist/protocol/edge-verdict.d.ts +1 -1
- package/dist/protocol/edge-verdict.d.ts.map +1 -1
- package/dist/protocol/headers.d.ts +4 -0
- package/dist/protocol/headers.d.ts.map +1 -0
- package/dist/protocol/headers.js +4 -0
- package/dist/protocol/headers.js.map +1 -0
- package/dist/protocol/ingress-contract.d.ts +1 -1
- package/dist/protocol/ingress-contract.d.ts.map +1 -1
- package/dist/protocol/ingress-contract.js +1 -5
- package/dist/protocol/ingress-contract.js.map +1 -1
- package/dist/protocol/peer-dial.d.ts.map +1 -1
- package/dist/protocol/peer-dial.js +18 -36
- package/dist/protocol/peer-dial.js.map +1 -1
- package/dist/protocol/raw/extension-protocol.d.ts +47 -0
- package/dist/protocol/raw/extension-protocol.d.ts.map +1 -0
- package/dist/protocol/raw/extension-protocol.js +32 -0
- package/dist/protocol/raw/extension-protocol.js.map +1 -0
- package/dist/protocol/raw/raw-json-routes.d.ts +855 -0
- package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -0
- package/dist/protocol/raw/raw-json-routes.js +28 -0
- package/dist/protocol/raw/raw-json-routes.js.map +1 -0
- package/dist/protocol/{raw-routes.d.ts → raw/raw-routes.d.ts} +50 -3
- package/dist/protocol/raw/raw-routes.d.ts.map +1 -0
- package/dist/protocol/{raw-routes.js → raw/raw-routes.js} +17 -3
- package/dist/protocol/raw/raw-routes.js.map +1 -0
- package/dist/protocol/raw/route-path.d.ts +3 -0
- package/dist/protocol/raw/route-path.d.ts.map +1 -0
- package/dist/protocol/raw/route-path.js +8 -0
- package/dist/protocol/raw/route-path.js.map +1 -0
- package/dist/protocol/route-meta.d.ts +1 -1
- package/dist/protocol/route-meta.d.ts.map +1 -1
- package/dist/protocol/routes.d.ts +1 -0
- package/dist/protocol/routes.d.ts.map +1 -1
- package/dist/protocol/routes.js +8 -0
- package/dist/protocol/routes.js.map +1 -1
- package/dist/protocol/sse.d.ts +2 -1
- package/dist/protocol/sse.d.ts.map +1 -1
- package/dist/protocol/sse.js +23 -12
- package/dist/protocol/sse.js.map +1 -1
- package/dist/protocol/tunnel-bulk.js +1 -1
- package/dist/protocol/tunnel-bulk.js.map +1 -1
- package/dist/protocol/vitals.d.ts +2 -1
- package/dist/protocol/vitals.d.ts.map +1 -1
- package/dist/protocol/vitals.js +1 -0
- package/dist/protocol/vitals.js.map +1 -1
- package/dist/schemas/activity.d.ts +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 +6 -0
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +9 -4
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +404 -0
- package/dist/schemas/agents-list.d.ts.map +1 -0
- package/dist/schemas/agents-list.js +14 -0
- package/dist/schemas/agents-list.js.map +1 -0
- package/dist/schemas/agents.d.ts +203 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +44 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automations.d.ts +235 -347
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js +82 -13
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/capabilities.d.ts +43 -8
- package/dist/schemas/capabilities.d.ts.map +1 -1
- package/dist/schemas/capabilities.js +6 -2
- package/dist/schemas/capabilities.js.map +1 -1
- package/dist/schemas/ci.d.ts +4 -0
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +8 -0
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/devices.d.ts +67 -0
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +8 -0
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/engines.d.ts +57 -0
- package/dist/schemas/engines.d.ts.map +1 -1
- package/dist/schemas/engines.js +4 -0
- package/dist/schemas/engines.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +329 -0
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/extension-updates.js +68 -3
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/git/git.d.ts +11 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/git/git.js +4 -4
- package/dist/schemas/git/git.js.map +1 -1
- package/dist/schemas/history.d.ts +2 -0
- package/dist/schemas/history.d.ts.map +1 -1
- package/dist/schemas/history.js.map +1 -1
- package/dist/schemas/hosts.d.ts +74 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +10 -1
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/loopback-catch.d.ts +1 -0
- package/dist/schemas/loopback-catch.d.ts.map +1 -1
- package/dist/schemas/loopback-catch.js +1 -0
- package/dist/schemas/loopback-catch.js.map +1 -1
- package/dist/schemas/maintenance.d.ts +8 -0
- package/dist/schemas/maintenance.d.ts.map +1 -1
- package/dist/schemas/maintenance.js +6 -0
- package/dist/schemas/maintenance.js.map +1 -1
- package/dist/schemas/members.d.ts +58 -0
- package/dist/schemas/members.d.ts.map +1 -0
- package/dist/schemas/members.js +16 -0
- package/dist/schemas/members.js.map +1 -0
- package/dist/schemas/metrics.d.ts +10 -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/needs.d.ts +1159 -1
- package/dist/schemas/needs.d.ts.map +1 -1
- package/dist/schemas/needs.js +25 -3
- package/dist/schemas/needs.js.map +1 -1
- package/dist/schemas/offload.js +1 -1
- package/dist/schemas/offload.js.map +1 -1
- package/dist/schemas/peer-enrollment.d.ts +7 -0
- package/dist/schemas/peer-enrollment.d.ts.map +1 -0
- package/dist/schemas/peer-enrollment.js +6 -0
- package/dist/schemas/peer-enrollment.js.map +1 -0
- package/dist/schemas/phone.d.ts +231 -0
- package/dist/schemas/phone.d.ts.map +1 -0
- package/dist/schemas/phone.js +57 -0
- package/dist/schemas/phone.js.map +1 -0
- package/dist/schemas/privacy.d.ts +41 -0
- package/dist/schemas/privacy.d.ts.map +1 -1
- package/dist/schemas/privacy.js +20 -3
- package/dist/schemas/privacy.js.map +1 -1
- package/dist/schemas/project-delivery.d.ts +94 -0
- package/dist/schemas/project-delivery.d.ts.map +1 -0
- package/dist/schemas/project-delivery.js +35 -0
- package/dist/schemas/project-delivery.js.map +1 -0
- package/dist/schemas/providers/plan-limits.d.ts +7 -0
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +22 -1
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/providers/usage.d.ts +1 -2
- package/dist/schemas/providers/usage.d.ts.map +1 -1
- package/dist/schemas/providers/usage.js +1 -2
- package/dist/schemas/providers/usage.js.map +1 -1
- package/dist/schemas/push.d.ts +1 -0
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/secrets.d.ts +99 -0
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +34 -3
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/settings-history.d.ts +1 -1
- package/dist/schemas/settings-history.d.ts.map +1 -1
- package/dist/schemas/settings-history.js +1 -0
- package/dist/schemas/settings-history.js.map +1 -1
- package/dist/schemas/settings.d.ts +13 -58
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +8 -13
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/terminal.d.ts +32 -0
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js +37 -0
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/updates.d.ts +1 -0
- package/dist/schemas/updates.d.ts.map +1 -1
- package/dist/schemas/updates.js +4 -0
- package/dist/schemas/updates.js.map +1 -1
- package/dist/schemas/workspace/workspace-search.d.ts +1 -0
- package/dist/schemas/workspace/workspace-search.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-search.js.map +1 -1
- package/dist/schemas/workspace/workspace-tree.d.ts +3 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +22 -5
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/arrival.d.ts +59 -0
- package/dist/state/arrival.d.ts.map +1 -1
- package/dist/state/arrival.js +17 -0
- package/dist/state/arrival.js.map +1 -1
- package/dist/state/contract-lock.js +2 -2
- package/dist/state/contract-lock.js.map +1 -1
- package/dist/state/definition.d.ts +82 -16
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/history-state.d.ts.map +1 -1
- package/dist/state/history-state.js +38 -0
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/runtime-state.d.ts +6 -0
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js +2 -0
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/state/workspace-state.d.ts +24 -6
- package/dist/state/workspace-state.d.ts.map +1 -1
- package/dist/state/workspace-state.js +29 -7
- package/dist/state/workspace-state.js.map +1 -1
- package/dist/text/embed.d.ts +10 -0
- package/dist/text/embed.d.ts.map +1 -1
- package/dist/text/embed.js +25 -0
- package/dist/text/embed.js.map +1 -1
- package/dist/text/pages.d.ts +53 -0
- package/dist/text/pages.d.ts.map +1 -0
- package/dist/text/pages.js +230 -0
- package/dist/text/pages.js.map +1 -0
- 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 +30 -2
- package/dist/text/transcript-fold.js.map +1 -1
- package/dist/webext/index.d.ts +3 -2
- package/dist/webext/index.d.ts.map +1 -1
- package/dist/webext/index.js +3 -2
- package/dist/webext/index.js.map +1 -1
- package/package.json +77 -22
- package/src/chores/chores.ts +41 -21
- package/src/chores/{probes.test.ts → probes.integration.test.ts} +134 -1
- package/src/chores/probes.ts +128 -14
- package/src/chores/verdict.test.ts +29 -0
- package/src/contracts/agent.contract.ts +2 -2
- package/src/contracts/agents.contract.ts +1 -1
- package/src/contracts/automations.contract.ts +19 -1
- package/src/contracts/device.contract.ts +5 -0
- package/src/contracts/endpoints.contract.ts +32 -26
- package/src/contracts/extensions.contract.ts +49 -0
- package/src/contracts/pages.contract.ts +61 -0
- package/src/contracts/phone.contract.ts +21 -0
- package/src/contracts/privacy.contract.ts +13 -1
- package/src/contracts/runner.contract.ts +1 -1
- package/src/contracts/secrets.contract.ts +25 -0
- package/src/contracts/settings.contract.ts +10 -0
- package/src/contracts/system.contract.ts +26 -0
- package/src/documents/conversions.ts +3 -1
- package/src/documents/read.ts +4 -5
- package/src/events/agent-events.ts +27 -3
- package/src/events/requests.ts +47 -0
- package/src/events/transcript.ts +14 -0
- package/src/ids/hostnames.fixture.json +14 -10
- package/src/ids/hostnames.test.ts +21 -2
- package/src/ids/hostnames.ts +34 -15
- package/src/ids/sandbox-id.ts +3 -0
- package/src/ids/tunnel-ids.ts +1 -2
- package/src/index.ts +29 -12
- package/src/models/agent-catalog.ts +1 -2
- package/src/models/agent-runtimes.ts +12 -6
- package/src/models/provider-specs.test.ts +12 -0
- package/src/models/provider-specs.ts +16 -0
- package/src/{front → netd}/browser-wire.ts +1 -1
- package/src/{front → netd}/generated/browser-wire.json +80 -7
- package/src/{front → netd}/generated/browser-wire.ts +34 -7
- package/src/{front/generated/front-wire.json → netd/generated/netd-wire.json} +103 -41
- package/src/{front → netd}/generated/tunnel.json +15 -1
- package/src/{front → netd}/generated/wire.ts +26 -21
- package/src/netd/netd-wire.ts +24 -0
- package/src/{front → netd}/wire-manifests.test.ts +31 -11
- package/src/policy/credential-material.ts +39 -11
- package/src/policy/message-limits.ts +25 -0
- package/src/policy/request-status.ts +10 -1
- package/src/policy/reserved-servers.ts +3 -2
- package/src/policy/tests/credential-material.test.ts +49 -1
- package/src/policy/tests/message-limits.test.ts +27 -0
- package/src/policy/tests/reserved-servers.test.ts +3 -3
- package/src/policy/turned-away.ts +5 -1
- package/src/protocol/container-requirements.ts +4 -5
- package/src/protocol/{listener-protocol.ts → doors/listener-protocol.ts} +37 -15
- package/src/protocol/doors/phone-links.ts +50 -0
- package/src/protocol/doors/phone-protocol.test.ts +136 -0
- package/src/protocol/doors/phone-protocol.ts +71 -0
- package/src/protocol/{runner-protocol.ts → doors/runner-protocol.ts} +1 -1
- package/src/protocol/{webext-links.ts → doors/webext-links.ts} +4 -0
- package/src/protocol/edge-verdict.ts +1 -1
- package/src/protocol/headers.ts +14 -0
- package/src/protocol/ingress-contract.ts +6 -10
- package/src/protocol/peer-dial.test.ts +83 -4
- package/src/protocol/peer-dial.ts +33 -40
- package/src/protocol/raw/extension-protocol.ts +59 -0
- package/src/protocol/raw/raw-json-routes.ts +61 -0
- package/src/protocol/{raw-routes.ts → raw/raw-routes.ts} +40 -7
- package/src/protocol/raw/route-path.ts +13 -0
- package/src/protocol/route-meta.ts +4 -4
- package/src/protocol/routes.ts +12 -0
- package/src/protocol/sse.test.ts +49 -0
- package/src/protocol/sse.ts +29 -14
- package/src/protocol/tunnel-bulk.test.ts +1 -1
- package/src/protocol/tunnel-bulk.ts +2 -2
- package/src/protocol/vitals.test.ts +7 -7
- package/src/protocol/vitals.ts +12 -7
- package/src/schemas/activity.ts +1 -0
- package/src/schemas/agent.ts +11 -4
- package/src/schemas/agents-list.ts +24 -0
- package/src/schemas/agents.ts +71 -2
- package/src/schemas/automations.ts +126 -24
- package/src/schemas/capabilities.ts +13 -3
- package/src/schemas/ci.ts +10 -0
- package/src/schemas/devices.ts +24 -0
- package/src/schemas/engines.ts +7 -0
- package/src/schemas/extension-updates.ts +93 -3
- package/src/schemas/git/git.ts +15 -4
- package/src/schemas/history.ts +2 -0
- package/src/schemas/hosts.ts +23 -1
- package/src/schemas/loopback-catch.ts +6 -1
- package/src/schemas/maintenance.ts +9 -0
- package/src/schemas/members.ts +33 -0
- package/src/schemas/metrics.ts +21 -3
- package/src/schemas/needs.ts +36 -3
- package/src/schemas/offload.ts +1 -1
- package/src/schemas/peer-enrollment.ts +14 -0
- package/src/schemas/phone.ts +121 -0
- package/src/schemas/privacy.ts +36 -7
- package/src/schemas/project-delivery.ts +78 -0
- package/src/schemas/providers/plan-limits.ts +27 -3
- package/src/schemas/providers/usage.ts +3 -3
- package/src/schemas/push.ts +1 -0
- package/src/schemas/secrets.ts +54 -3
- package/src/schemas/settings-history.ts +2 -0
- package/src/schemas/settings.ts +20 -22
- package/src/schemas/terminal.ts +50 -0
- package/src/schemas/updates.test.ts +47 -0
- package/src/schemas/updates.ts +4 -0
- package/src/schemas/workspace/workspace-search.ts +2 -0
- package/src/schemas/workspace/workspace-tree.ts +40 -12
- package/src/state/arrival.ts +40 -0
- package/src/state/contract-lock.test.ts +1 -1
- package/src/state/contract-lock.ts +5 -5
- package/src/state/history-state.ts +72 -1
- package/src/state/runtime-state.ts +4 -0
- package/src/state/workspace-state.ts +65 -20
- package/src/text/embed.test.ts +21 -1
- package/src/text/embed.ts +50 -3
- package/src/text/pages.test.ts +161 -0
- package/src/text/pages.ts +344 -0
- package/src/text/transcript-fold.test.ts +22 -0
- package/src/text/transcript-fold.ts +41 -2
- package/src/webext/index.ts +3 -2
- package/dist/front/browser-wire.d.ts.map +0 -1
- package/dist/front/browser-wire.js.map +0 -1
- package/dist/front/front-wire.d.ts +0 -6
- package/dist/front/front-wire.d.ts.map +0 -1
- package/dist/front/front-wire.js +0 -5
- package/dist/front/front-wire.js.map +0 -1
- package/dist/front/generated/browser-wire.d.ts.map +0 -1
- package/dist/front/generated/browser-wire.js.map +0 -1
- package/dist/front/generated/wire.d.ts.map +0 -1
- package/dist/protocol/host-protocol.d.ts.map +0 -1
- package/dist/protocol/host-protocol.js.map +0 -1
- package/dist/protocol/listener-protocol.d.ts.map +0 -1
- package/dist/protocol/listener-protocol.js +0 -33
- package/dist/protocol/listener-protocol.js.map +0 -1
- package/dist/protocol/raw-routes.d.ts.map +0 -1
- package/dist/protocol/raw-routes.js.map +0 -1
- package/dist/protocol/request-id.d.ts +0 -2
- package/dist/protocol/request-id.d.ts.map +0 -1
- package/dist/protocol/request-id.js +0 -2
- package/dist/protocol/request-id.js.map +0 -1
- package/dist/protocol/runner-protocol.d.ts.map +0 -1
- package/dist/protocol/runner-protocol.js.map +0 -1
- package/dist/protocol/webext-links.d.ts.map +0 -1
- package/dist/protocol/webext-links.js.map +0 -1
- package/dist/protocol/webext-protocol.d.ts.map +0 -1
- package/dist/protocol/webext-protocol.js.map +0 -1
- package/src/front/front-wire.ts +0 -15
- package/src/protocol/request-id.ts +0 -2
- /package/dist/{front → netd}/browser-wire.d.ts +0 -0
- /package/dist/{front → netd}/browser-wire.js +0 -0
- /package/dist/{front → netd}/generated/browser-wire.js +0 -0
- /package/dist/{front → netd}/generated/wire.js +0 -0
- /package/dist/protocol/{host-protocol.d.ts → doors/host-protocol.d.ts} +0 -0
- /package/dist/protocol/{host-protocol.js → doors/host-protocol.js} +0 -0
- /package/dist/protocol/{runner-protocol.d.ts → doors/runner-protocol.d.ts} +0 -0
- /package/dist/protocol/{webext-protocol.d.ts → doors/webext-protocol.d.ts} +0 -0
- /package/dist/protocol/{webext-protocol.js → doors/webext-protocol.js} +0 -0
- /package/src/protocol/{host-protocol.ts → doors/host-protocol.ts} +0 -0
- /package/src/protocol/{webext-protocol.ts → doors/webext-protocol.ts} +0 -0
|
@@ -193,6 +193,22 @@ const STATE_FILES = [
|
|
|
193
193
|
why: "Scheduler bookkeeping nothing in the browser renders: what a catch-up fire produces reaches the run ledger, which carries the automations key.",
|
|
194
194
|
portability: "carry",
|
|
195
195
|
},
|
|
196
|
+
// What each watch's check saw last (automations/automations-store.ts), so `fireOn: change` can say what moved and
|
|
197
|
+
// the list can show the last value. `carry`: a restored sandbox must not read every release it already saw as new.
|
|
198
|
+
{
|
|
199
|
+
path: ".intentic/records/automation-watch.json",
|
|
200
|
+
invalidates: [],
|
|
201
|
+
why: "Declared by the intentic.automations extension's contributes.files, `automations` is its query key, not core's.",
|
|
202
|
+
portability: "carry",
|
|
203
|
+
},
|
|
204
|
+
// One file per automation that a guard command may keep between runs ($AUTOMATION_STATE); the daemon only makes the
|
|
205
|
+
// directory and deletes an automation's file with it. `carry`: it is the guard's memory of what it already saw.
|
|
206
|
+
{
|
|
207
|
+
path: ".intentic/records/automation-state/",
|
|
208
|
+
invalidates: [],
|
|
209
|
+
why: "A guard's own scratch file; the daemon never reads it and nothing in the browser renders it.",
|
|
210
|
+
portability: "carry",
|
|
211
|
+
},
|
|
196
212
|
{
|
|
197
213
|
path: ".intentic/records/approvals/",
|
|
198
214
|
invalidates: [],
|
|
@@ -312,6 +328,16 @@ const STATE_FILES = [
|
|
|
312
328
|
// Owner's per-extension update posture (notify/agent/auto, advisory opt-out). `carry`: a decision about the
|
|
313
329
|
// extension, not the machine.
|
|
314
330
|
{ path: ".intentic/config/extension-update-policy.json", invalidates: ["extensions"], portability: "carry", versioned: true },
|
|
331
|
+
// Which installed extensions run from a source checkout instead of their pinned clone (extensions/extension-dev.ts).
|
|
332
|
+
// Local and never versioned: it can name a conversation's worktree, a path that means nothing in a commit or on
|
|
333
|
+
// another machine. `extensions` because the row says where it runs from, and a rebuild reported here is what offers
|
|
334
|
+
// the reload.
|
|
335
|
+
{
|
|
336
|
+
path: ".intentic/local/extension-dev.json",
|
|
337
|
+
invalidates: ["extensions"],
|
|
338
|
+
portability: "derived",
|
|
339
|
+
note: "Extensions run their pinned versions on the target; point one at its source checkout again there if you were working on it.",
|
|
340
|
+
},
|
|
315
341
|
// `carry`: evidence is about the extension, not the machine; dropping it would make every permission look unused
|
|
316
342
|
// rather than simply unmeasured.
|
|
317
343
|
{
|
|
@@ -320,14 +346,13 @@ const STATE_FILES = [
|
|
|
320
346
|
why: "Which of the routes each extension DECLARED it has actually called, the evidence behind the permissions list on its row. The one entry here whose empty set is a RATE decision rather than an architectural one: every browser with the app open reports its batch on a timer, so wiring this to the `extensions` query would refetch the whole list every few seconds for a figure nobody is watching change. The tab reads it when it loads, which is when anyone is reading it.",
|
|
321
347
|
portability: "carry",
|
|
322
348
|
},
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
// target's ownership.
|
|
349
|
+
// The roster's address before 2026-10-06 (now the history volume's `identity/members.json`). Holds no credential but
|
|
350
|
+
// stays `identity`, not `carry`: an access list that traveled would let a source sandbox hand itself the target's
|
|
351
|
+
// ownership, and a pre-move copy may still sit here.
|
|
327
352
|
{
|
|
328
353
|
path: ".intentic/identity/members.json",
|
|
329
354
|
invalidates: [],
|
|
330
|
-
why: "
|
|
355
|
+
why: "Where releases before 2026-10-06 kept the daemon's enforced roster; it now lives on the history volume (`identity/members.json`), off the workspace every turn writes, and nothing reads this copy. Kept declared, locked and never exported, since it may still hold a pre-move roster a rollback reads.",
|
|
331
356
|
portability: "identity",
|
|
332
357
|
note: "Re-invite collaborators from the Access tab, a grant is the platform's record, and the target enforces its own copy.",
|
|
333
358
|
},
|
|
@@ -375,14 +400,15 @@ const STATE_FILES = [
|
|
|
375
400
|
why: "Rebuildable indexes and caches, the iq index and its vector sidecar, the whisper model, fileq's derived/ markdown shadows of binary files; ignored by the watcher and recreated from carried workspace content.",
|
|
376
401
|
portability: "derived",
|
|
377
402
|
},
|
|
378
|
-
// Extension runtime scratch, one directory per extension via `
|
|
379
|
-
//
|
|
403
|
+
// Extension runtime scratch, one directory per extension via `extensionStateDir` below (the only way an extension
|
|
404
|
+
// may name a home here), plus the gateways' published control addresses. Resume watermarks and cached tokens; all
|
|
405
|
+
// of it expires or re-derives.
|
|
380
406
|
{
|
|
381
407
|
path: ".intentic/local/runtime/",
|
|
382
408
|
invalidates: [],
|
|
383
409
|
why: "Extension runtime scratch (watermarks, cached short-lived tokens); nothing renders it and gateways re-derive it.",
|
|
384
410
|
portability: "derived",
|
|
385
|
-
outsideWriter: "extensions, through
|
|
411
|
+
outsideWriter: "extensions, through extensionStateDir below",
|
|
386
412
|
},
|
|
387
413
|
{
|
|
388
414
|
path: ".intentic/local/tmp/",
|
|
@@ -447,7 +473,7 @@ const STATE_FILES = [
|
|
|
447
473
|
{
|
|
448
474
|
path: ".intentic/identity/control-tokens.json",
|
|
449
475
|
invalidates: [],
|
|
450
|
-
why: "
|
|
476
|
+
why: "Where releases before 2026-10-06 kept the hashed control tokens; they now live on the history volume (`identity/control-tokens.json`), and nothing reads this copy.",
|
|
451
477
|
portability: "identity",
|
|
452
478
|
backup: false,
|
|
453
479
|
note: "Mint fresh control tokens, the old ones authenticate against the source sandbox.",
|
|
@@ -455,7 +481,7 @@ const STATE_FILES = [
|
|
|
455
481
|
{
|
|
456
482
|
path: ".intentic/identity/owner.json",
|
|
457
483
|
invalidates: [],
|
|
458
|
-
why: "
|
|
484
|
+
why: "Where releases before 2026-10-06 kept the bound owner; it now lives on the history volume (`identity/owner.json`), and nothing reads this copy.",
|
|
459
485
|
portability: "identity",
|
|
460
486
|
},
|
|
461
487
|
{
|
|
@@ -464,13 +490,13 @@ const STATE_FILES = [
|
|
|
464
490
|
why: "The workspace identity, read from the /events hello frame rather than as a file.",
|
|
465
491
|
portability: "identity",
|
|
466
492
|
},
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
// a
|
|
493
|
+
// The passkeys' address before the passkeys-off-workspace step (now the history volume's `identity/passkeys.json`):
|
|
494
|
+
// public keys, the owner's require-a-passkey switch and the hashes of their recovery codes. Stays `identity`, since
|
|
495
|
+
// a pre-move copy may still sit here and a passkey admits its holder to THIS sandbox.
|
|
470
496
|
{
|
|
471
497
|
path: ".intentic/identity/passkeys.json",
|
|
472
498
|
invalidates: [],
|
|
473
|
-
why: "
|
|
499
|
+
why: "Where earlier releases kept the passkeys registered with this sandbox, whether one is required to open it, and the hashes of the owner's recovery codes; they now live on the history volume (`identity/passkeys.json`), off the workspace every turn writes, and nothing reads this copy.",
|
|
474
500
|
portability: "identity",
|
|
475
501
|
note: "Passkeys are bound to the sandbox they were registered with: add them again on the new one from its Access tab.",
|
|
476
502
|
},
|
|
@@ -606,10 +632,28 @@ export const UNBACKED_STATE_PATHS: readonly string[] = WORKSPACE_STATE_FILES.fil
|
|
|
606
632
|
(file) => file.path,
|
|
607
633
|
);
|
|
608
634
|
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
|
|
635
|
+
// A name made safe as one path segment. Extension identities are already validated slugs joined by a dot; the replace
|
|
636
|
+
// is defence in depth.
|
|
637
|
+
const segmentOf = (name: string): string => name.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
|
|
638
|
+
|
|
639
|
+
// The only way an extension may name a home for its own state, workspace-relative and forward-slash so the browser
|
|
640
|
+
// bundle can hold it too. Keyed by the extension's identity (`publisher.name`, extensionIdOf), like its settings and its
|
|
641
|
+
// switch, so it survives an update, a re-install and dev mode. The daemon creates it and hands it to the extension's
|
|
642
|
+
// code as `api.stateDir`; an agent-side CLI of the same extension names it by its own identity.
|
|
643
|
+
export const extensionStateDir = (identity: string): string => `${STATE_GROUP_DIR.local}/runtime/extensions/${segmentOf(identity)}`;
|
|
644
|
+
|
|
645
|
+
// Its counterpart for what can be fetched or built again (`api.cacheDir`), under the rebuildable cache the watcher
|
|
646
|
+
// ignores and no backup carries.
|
|
647
|
+
export const extensionCacheDir = (identity: string): string => `${STATE_GROUP_DIR.local}/cache/extensions/${segmentOf(identity)}`;
|
|
648
|
+
|
|
649
|
+
// Where an extension kept its state before the directory was keyed by identity: its bare manifest name. Read only by
|
|
650
|
+
// the daemon, which moves a first-party extension's directory from here to extensionStateDir once.
|
|
651
|
+
export const legacyExtensionStateDir = (name: string): string => `${STATE_GROUP_DIR.local}/runtime/extensions/${segmentOf(name)}`;
|
|
652
|
+
|
|
653
|
+
// Where a gateway publishes its loopback control address for the agent's CLI to read (`publishGatewayUrl`), keyed by
|
|
654
|
+
// the listener provider the gateway serves. Beside the extensions' own directories rather than inside one, since the
|
|
655
|
+
// provider is the rendezvous both sides know, and the CLI never learns which extension owns it.
|
|
656
|
+
export const extensionGatewayUrlFile = (provider: string): string => `${STATE_GROUP_DIR.local}/runtime/gateways/${segmentOf(provider)}.url`;
|
|
613
657
|
|
|
614
658
|
// Manifests the unreadable-manifest notice reports on: exactly the entries that declare `manifests` in
|
|
615
659
|
// Report broken manifests only when a file change can refresh their notice.
|
|
@@ -619,8 +663,9 @@ export const REPORTED_MANIFEST_PATHS: readonly string[] = WORKSPACE_STATE_FILES.
|
|
|
619
663
|
|
|
620
664
|
// Files on the daemon's own volume whose unreadable records are reported too, named by their absolute path there: the
|
|
621
665
|
// conversation registry's rows, one of which this build could not read costs that conversation until a build that can
|
|
622
|
-
// runs. Reported, never repaired from the card (no route edits them), and refreshed whenever the card is fetched.
|
|
623
|
-
|
|
666
|
+
// runs. Reported, never repaired from the card (no route edits them), and refreshed whenever the card is fetched. The
|
|
667
|
+
// boot record (2026-10-05) is reported when a restart storm kept a boot from resuming the turns it cut.
|
|
668
|
+
export const REPORTED_VOLUME_FILES: readonly string[] = [`${HISTORY_ROOT}/conversations.db`, `${HISTORY_ROOT}/boot-history.json`];
|
|
624
669
|
|
|
625
670
|
// Accepts either separator; the daemon holds these as platform paths and normalizing at every call site is what
|
|
626
671
|
// eventually gets forgotten.
|
package/src/text/embed.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { webcrypto } from "node:crypto";
|
|
2
2
|
import { stubGlobal, unstubAllGlobals } from "@intentic/testing/bun";
|
|
3
|
-
import { EmbedError, embedFailure, embedUrl, fetchEmbedJson, solveProofOfWork } from "./embed.js";
|
|
3
|
+
import { DEFAULT_ACCENT, EmbedError, embedFailure, embedUrl, escapeHtml, fetchEmbedJson, onAccent, parseHex, solveProofOfWork } from "./embed.js";
|
|
4
4
|
|
|
5
5
|
/* The wire every embed speaks before it speaks its own, against a fake fetch and the real WebCrypto. */
|
|
6
6
|
|
|
@@ -72,3 +72,23 @@ test("an http:// page is told the truth, in the embed's own words, instead of ha
|
|
|
72
72
|
);
|
|
73
73
|
Object.defineProperty(globalThis, "crypto", { value: webcrypto, configurable: true });
|
|
74
74
|
});
|
|
75
|
+
|
|
76
|
+
test("an accent is read as three channels from either hex spelling, and anything else is unreadable", () => {
|
|
77
|
+
expect(parseHex(DEFAULT_ACCENT)).toEqual([228, 113, 0]);
|
|
78
|
+
expect(parseHex(" #FA0 ")).toEqual([255, 170, 0]);
|
|
79
|
+
expect(parseHex("rebeccapurple")).toBeUndefined();
|
|
80
|
+
expect(parseHex("#12345")).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// The default orange is where a brightness threshold gets it wrong: it read as dark and put white on it, at 3.15:1.
|
|
84
|
+
test("the label on an accent is whichever of the dark ink and white contrasts more, so the default orange gets dark text", () => {
|
|
85
|
+
expect(onAccent(DEFAULT_ACCENT, "#111827")).toBe("#111827");
|
|
86
|
+
expect(onAccent(DEFAULT_ACCENT, "#201c19")).toBe("#201c19");
|
|
87
|
+
expect(onAccent("#1a3d8f", "#111827")).toBe("#ffffff");
|
|
88
|
+
expect(onAccent("#fde047", "#111827")).toBe("#111827");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("escaped text stays text both between tags and inside a quoted attribute", () => {
|
|
92
|
+
expect(escapeHtml(`<img src=x onerror="alert('hi')"> & more`)).toBe("<img src=x onerror="alert('hi')"> & more");
|
|
93
|
+
expect(escapeHtml("Report a problem")).toBe("Report a problem");
|
|
94
|
+
});
|
package/src/text/embed.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// The zod-free half of an embed's wire, shared by the two embeds (webchat-widget, issue-sdk) and the daemon's
|
|
2
|
-
//
|
|
3
|
-
// (measured at 1.1 MB for two strings).
|
|
1
|
+
// The zod-free half of an embed's wire and look, shared by the two embeds (webchat-widget, issue-sdk) and the daemon's
|
|
2
|
+
// doors behind them. No imports, ever: this bundles into someone else's page, and the contract's barrel would drag in
|
|
3
|
+
// zod (measured at 1.1 MB for two strings).
|
|
4
4
|
|
|
5
5
|
// Where an embed talks to: the daemon it came from, and the automation it is the public face of.
|
|
6
6
|
export interface EmbedEndpoint {
|
|
@@ -130,3 +130,50 @@ export const embedEndpointOf = (script: HTMLScriptElement): EmbedEndpoint | unde
|
|
|
130
130
|
}
|
|
131
131
|
return { automationId, base: (script.dataset["base"] ?? new URL(script.src, window.location.href).origin).replace(/\/$/, "") };
|
|
132
132
|
};
|
|
133
|
+
|
|
134
|
+
// The frames of a Visitor chat reply, streamed as server-sent events on the POST that sent the message: a chunk of the
|
|
135
|
+
// answer, the notice that the owner reviews it first, the one failure sentence a visitor sees, and the end of the turn.
|
|
136
|
+
export const WEBCHAT_EVENT = { delta: "delta", pending: "pending", error: "error", done: "done" } as const;
|
|
137
|
+
|
|
138
|
+
// Intentic's brand orange (`--color-brand-600`): the accent of an embed nobody configured, so it still looks like the
|
|
139
|
+
// product, and what an embed paints when it cannot read the configured one.
|
|
140
|
+
export const DEFAULT_ACCENT = "#e47100";
|
|
141
|
+
|
|
142
|
+
// The red, green and blue of a `#rgb` or `#rrggbb` colour, undefined for anything else. The embeds do their colour maths
|
|
143
|
+
// here rather than in CSS: an unsupported color-mix() is invalid at computed-value time and would paint nothing.
|
|
144
|
+
export const parseHex = (value: string): [number, number, number] | undefined => {
|
|
145
|
+
const digits = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim())?.[1];
|
|
146
|
+
if (digits === undefined) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
const full = digits.length === 3 ? [...digits].map((char) => char + char).join("") : digits;
|
|
150
|
+
const channel = (at: number): number => Number.parseInt(full.slice(at, at + 2), 16);
|
|
151
|
+
return [channel(0), channel(2), channel(4)];
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// One sRGB channel on WCAG's linear scale.
|
|
155
|
+
const linear = (channel: number): number => {
|
|
156
|
+
const unit = channel / 255;
|
|
157
|
+
return unit <= 0.03928 ? unit / 12.92 : ((unit + 0.055) / 1.055) ** 2.4;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// WCAG relative luminance; an unreadable colour scores 0, which only ever picks a label and is never shown.
|
|
161
|
+
const luminance = (color: string): number => {
|
|
162
|
+
const [r, g, b] = parseHex(color) ?? [0, 0, 0];
|
|
163
|
+
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const contrast = (a: number, b: number): number => (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
|
167
|
+
|
|
168
|
+
// The label on a solid accent: the embed's own dark ink or white, whichever contrasts more. Measured, not assumed:
|
|
169
|
+
// white on the default orange is 3.15:1, under AA, where either embed's dark ink clears 5:1, and comparing the two works
|
|
170
|
+
// for any accent a customer picks.
|
|
171
|
+
export const onAccent = (accent: string, dark: string): string => {
|
|
172
|
+
const field = luminance(accent);
|
|
173
|
+
return contrast(field, luminance(dark)) >= contrast(field, luminance("#ffffff")) ? dark : "#ffffff";
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// Text for innerHTML, safe both between tags and inside a quoted attribute: neither an owner's config nor what a
|
|
177
|
+
// visitor typed is trusted with markup.
|
|
178
|
+
export const escapeHtml = (value: string): string =>
|
|
179
|
+
value.replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char] ?? char);
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { AgentEvent } from "../events/agent-events.js";
|
|
2
|
+
import type { Page } from "../events/requests.js";
|
|
3
|
+
import { settledRequests } from "../policy/request-status.js";
|
|
4
|
+
import {
|
|
5
|
+
intoHead,
|
|
6
|
+
mcpAppDataScript,
|
|
7
|
+
PAGE_FALLBACK_THEMES,
|
|
8
|
+
PAGE_THEME_VARIABLES,
|
|
9
|
+
pageThemeCss,
|
|
10
|
+
publishedPage,
|
|
11
|
+
readMcpAppData,
|
|
12
|
+
sealedPage,
|
|
13
|
+
SEALED_PAGE_POLICY,
|
|
14
|
+
sizedFirst,
|
|
15
|
+
standalonePage,
|
|
16
|
+
} from "./pages.js";
|
|
17
|
+
import { foldTurn, userRow } from "./transcript-fold.js";
|
|
18
|
+
|
|
19
|
+
// path-literals: content, a page's stored path as a transcript row carries it
|
|
20
|
+
const PAGE: Page = { id: "a1b2c3d4e5", title: "Q3 revenue", path: ".intentic/records/artifacts/pages/c1/a1b2c3d4e5.r0.html" };
|
|
21
|
+
|
|
22
|
+
describe("intoHead", () => {
|
|
23
|
+
it("puts markup first inside an existing head", () => {
|
|
24
|
+
expect(intoHead(`<!doctype html><html><head><title>x</title></head><body></body></html>`, `<i>`)).toBe(
|
|
25
|
+
`<!doctype html><html><head><i><title>x</title></head><body></body></html>`,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("makes a head inside the html element when the page wrote none", () => {
|
|
30
|
+
expect(intoHead(`<html lang="en"><body>hi</body></html>`, `<i>`)).toBe(`<html lang="en"><head><i></head><body>hi</body></html>`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("makes one after a lone doctype, and for a bare fragment", () => {
|
|
34
|
+
expect(intoHead(`<!DOCTYPE html><p>hi</p>`, `<i>`)).toBe(`<!DOCTYPE html><head><i></head><p>hi</p>`);
|
|
35
|
+
expect(intoHead(`<p>hi</p>`, `<i>`)).toBe(`<!doctype html><head><i></head><p>hi</p>`);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("never takes a head written inside a script or comment for the real one", () => {
|
|
39
|
+
const html = `<!-- <head> --><html><head><script>const s = "<head>";</script></head></html>`;
|
|
40
|
+
expect(intoHead(html, `<i>`)).toBe(`<!-- <head> --><html><head><i><script>const s = "<head>";</script></head></html>`);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("sealedPage", () => {
|
|
45
|
+
it("leads with the policy, then the theme and the bootstrap, before the page's own head", () => {
|
|
46
|
+
const sealed = sealedPage(`<html><head><style>body{color:red}</style></head><body></body></html>`, PAGE_FALLBACK_THEMES.dark);
|
|
47
|
+
const policy = sealed.indexOf(SEALED_PAGE_POLICY);
|
|
48
|
+
const theme = sealed.indexOf(`id="intentic-theme"`);
|
|
49
|
+
const own = sealed.indexOf(`body{color:red}`);
|
|
50
|
+
expect(policy).toBeGreaterThan(-1);
|
|
51
|
+
expect(policy).toBeLessThan(theme);
|
|
52
|
+
expect(theme).toBeLessThan(own);
|
|
53
|
+
expect(sealed).toContain(`window.intentic=`);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("keeps the theme's values from ending the rule they sit in", () => {
|
|
57
|
+
const hostile = { ...PAGE_FALLBACK_THEMES.light, variables: { ...PAGE_FALLBACK_THEMES.light.variables, "--foreground": `red;}</style><script>x()` } };
|
|
58
|
+
expect(pageThemeCss(hostile)).not.toContain(`</style>`);
|
|
59
|
+
expect(pageThemeCss(hostile)).toContain(`--foreground:red/stylescriptx();`);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("names every theme variable", () => {
|
|
63
|
+
const css = pageThemeCss(PAGE_FALLBACK_THEMES.dark);
|
|
64
|
+
for (const name of PAGE_THEME_VARIABLES) {
|
|
65
|
+
expect(css).toContain(`${name}:`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("standalonePage", () => {
|
|
71
|
+
it("carries defaults at no specificity, so the chat's theme and the page's own rules win", () => {
|
|
72
|
+
const stored = standalonePage(`<html><head></head><body>x</body></html>`);
|
|
73
|
+
expect(stored).toContain(`:where(:root){`);
|
|
74
|
+
expect(stored).toContain(`@media (prefers-color-scheme: light)`);
|
|
75
|
+
expect(stored).not.toMatch(/(^|[^(]):root\{/);
|
|
76
|
+
expect(stored).toContain(`if(!window.intentic)`);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("pages in the fold", () => {
|
|
81
|
+
const fold = (events: readonly AgentEvent[]) => foldTurn([userRow("show me", 1, [])], events).slice(1);
|
|
82
|
+
|
|
83
|
+
it("draws a page on the bubble whose call showed it, and starts the next words below", () => {
|
|
84
|
+
const rows = fold([
|
|
85
|
+
{ kind: "tool_call", id: "t1", name: "mcp__ui__show_page", category: "other", status: "in_progress" },
|
|
86
|
+
{ kind: "page", page: PAGE },
|
|
87
|
+
{ kind: "tool_call_update", id: "t1", status: "completed" },
|
|
88
|
+
{ kind: "delta", text: "Revenue doubled." },
|
|
89
|
+
]);
|
|
90
|
+
expect(rows).toHaveLength(2);
|
|
91
|
+
expect(rows[0]?.page).toEqual(PAGE);
|
|
92
|
+
expect(rows[0]?.tools?.[0]?.status).toBe("completed");
|
|
93
|
+
expect(rows[1]).toEqual({ role: "assistant", text: "Revenue doubled." });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("folds an earlier drawing away when the page is redrawn", () => {
|
|
97
|
+
const redrawn: Page = { ...PAGE, path: PAGE.path.replace(".r0.", ".r1."), revision: 1 };
|
|
98
|
+
const rows = fold([
|
|
99
|
+
{ kind: "page", page: PAGE },
|
|
100
|
+
{ kind: "delta", text: "Here." },
|
|
101
|
+
{ kind: "text_end" },
|
|
102
|
+
{ kind: "page", page: redrawn },
|
|
103
|
+
]);
|
|
104
|
+
expect(rows[0]?.page?.superseded).toBe(true);
|
|
105
|
+
expect(rows.at(-1)?.page).toEqual(redrawn);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("parks a page asked on as a card, and settles it with what the page sent", () => {
|
|
109
|
+
const rows = fold([
|
|
110
|
+
{ kind: "page_ask", requestId: "r1", page: PAGE },
|
|
111
|
+
{ kind: "resolved", requestId: "r1", reply: { kind: "page_ask", requestId: "r1", value: `{"pick":"B"}` } },
|
|
112
|
+
]);
|
|
113
|
+
expect(rows[0]?.pageAsk).toEqual({ requestId: "r1", page: PAGE, status: "answered", value: `{"pick":"B"}` });
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("draws nothing for a draft: it is live state, never transcript", () => {
|
|
117
|
+
expect(fold([{ kind: "page_draft", callId: "t1", at: 0, text: "<p>" }])).toEqual([]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("reads a dismissal, or a turn that died, as cancelled with no value", () => {
|
|
121
|
+
const card = { pageAsk: { requestId: "r1", page: PAGE, status: "pending" as const } };
|
|
122
|
+
expect(settledRequests(card, { kind: "page_ask", requestId: "r1", cancelled: true }).pageAsk).toEqual({ ...card.pageAsk, status: "cancelled" });
|
|
123
|
+
expect(settledRequests(card, undefined).pageAsk?.status).toBe("cancelled");
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("an MCP app's call, kept inside its page", () => {
|
|
128
|
+
it("reads back exactly what was stored, markup in its values included", () => {
|
|
129
|
+
const data = { server: "maps", tool: "show_map", input: { q: "</script><b>" }, result: { content: [{ type: "text", text: "<i>3</i>" }] } };
|
|
130
|
+
const stored = standalonePage(intoHead(`<html><head></head><body></body></html>`, mcpAppDataScript(data)));
|
|
131
|
+
expect(stored).not.toContain("</script><b>");
|
|
132
|
+
expect(readMcpAppData(stored)).toEqual(data);
|
|
133
|
+
expect(readMcpAppData(`<html></html>`)).toBeUndefined();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe("publishedPage", () => {
|
|
138
|
+
it("seals a stored page off the network and has it say its height to the page around it", () => {
|
|
139
|
+
const published = publishedPage(standalonePage(`<html><head></head><body>x</body></html>`));
|
|
140
|
+
expect(published.indexOf(SEALED_PAGE_POLICY)).toBeLessThan(published.indexOf(`intentic-page-defaults`));
|
|
141
|
+
expect(published).toContain(`ui/notifications/size-changed`);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("sizedFirst", () => {
|
|
146
|
+
const page = `<!DOCTYPE html><html><head><script>var a = "</script>";</script></head><body>x</body></html>`;
|
|
147
|
+
const shell = sizedFirst(page);
|
|
148
|
+
|
|
149
|
+
it("carries the page whole inside one script the page cannot close", () => {
|
|
150
|
+
expect(shell.startsWith(`<!DOCTYPE html><script>`)).toBe(true);
|
|
151
|
+
expect(shell.endsWith(`</script>`)).toBe(true);
|
|
152
|
+
// The only `</` left is the shell's own closing tag: the page's markup cannot end the script early.
|
|
153
|
+
expect(shell.split(`</`).length).toBe(2);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("writes back exactly the page it was given", () => {
|
|
157
|
+
const literal = /var page=(".*?"),done=/.exec(shell)?.[1];
|
|
158
|
+
expect(literal).toBeDefined();
|
|
159
|
+
expect(JSON.parse(literal!)).toBe(page);
|
|
160
|
+
});
|
|
161
|
+
});
|