@intentic/sandbox-contract 1.334.0 → 1.335.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 +8 -3
- package/dist/contracts/accounts.contract.d.ts +11 -11
- package/dist/contracts/activity.contract.d.ts +1 -0
- package/dist/contracts/activity.contract.d.ts.map +1 -1
- package/dist/contracts/activity.contract.js +1 -1
- package/dist/contracts/activity.contract.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +102 -18
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +163 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +10 -1
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/audit.contract.d.ts +84 -0
- package/dist/contracts/audit.contract.d.ts.map +1 -0
- package/dist/contracts/audit.contract.js +43 -0
- package/dist/contracts/audit.contract.js.map +1 -0
- package/dist/contracts/automations.contract.d.ts +15 -0
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.d.ts +10 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/compliance.contract.d.ts +163 -0
- package/dist/contracts/compliance.contract.d.ts.map +1 -0
- package/dist/contracts/compliance.contract.js +41 -0
- package/dist/contracts/compliance.contract.js.map +1 -0
- package/dist/contracts/device.contract.d.ts +6 -0
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +2 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/loops.contract.d.ts +15 -0
- package/dist/contracts/loops.contract.d.ts.map +1 -1
- package/dist/contracts/needs.contract.d.ts +49 -0
- package/dist/contracts/needs.contract.d.ts.map +1 -1
- package/dist/contracts/offload.contract.d.ts +5 -0
- package/dist/contracts/offload.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.d.ts +10 -0
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.d.ts +2 -0
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js +4 -0
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +42 -10
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +17 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +84 -0
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +7 -0
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +16 -2
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/workflows.contract.d.ts +30 -0
- package/dist/contracts/workflows.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +3 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/events/agent-events.d.ts +74 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +1 -0
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/requests.d.ts +45 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/system-events.d.ts +12 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/transcript.d.ts +117 -0
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/index.d.ts +828 -73
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/models/agent-catalog.d.ts +18 -3
- package/dist/models/agent-catalog.d.ts.map +1 -1
- package/dist/models/agent-catalog.js +61 -12
- package/dist/models/agent-catalog.js.map +1 -1
- package/dist/models/agent-runtimes.d.ts +5 -2
- package/dist/models/agent-runtimes.d.ts.map +1 -1
- package/dist/models/agent-runtimes.js +73 -40
- package/dist/models/agent-runtimes.js.map +1 -1
- package/dist/models/model-setups.d.ts +5 -0
- package/dist/models/model-setups.d.ts.map +1 -1
- package/dist/models/provider-specs.d.ts +153 -32
- package/dist/models/provider-specs.d.ts.map +1 -1
- package/dist/models/provider-specs.js +97 -11
- package/dist/models/provider-specs.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/sandbox-power.d.ts +7 -2
- package/dist/policy/sandbox-power.d.ts.map +1 -1
- package/dist/policy/sandbox-power.js +34 -1
- package/dist/policy/sandbox-power.js.map +1 -1
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +1 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/doors/listener-protocol.d.ts +43 -1
- package/dist/protocol/doors/listener-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/listener-protocol.js +10 -0
- package/dist/protocol/doors/listener-protocol.js.map +1 -1
- package/dist/protocol/raw/raw-json-routes.d.ts +92 -0
- package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-json-routes.js +2 -1
- package/dist/protocol/raw/raw-json-routes.js.map +1 -1
- package/dist/protocol/raw/raw-routes.d.ts +13 -0
- package/dist/protocol/raw/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-routes.js +3 -0
- package/dist/protocol/raw/raw-routes.js.map +1 -1
- package/dist/schemas/activity.d.ts +2 -0
- package/dist/schemas/activity.d.ts.map +1 -1
- package/dist/schemas/agent.d.ts +34 -0
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +7 -6
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +7 -0
- package/dist/schemas/agents-list.d.ts.map +1 -1
- package/dist/schemas/agents.d.ts +18 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/ai-literacy.d.ts +54 -0
- package/dist/schemas/ai-literacy.d.ts.map +1 -0
- package/dist/schemas/ai-literacy.js +15 -0
- package/dist/schemas/ai-literacy.js.map +1 -0
- package/dist/schemas/audit.d.ts +166 -0
- package/dist/schemas/audit.d.ts.map +1 -0
- package/dist/schemas/audit.js +100 -0
- package/dist/schemas/audit.js.map +1 -0
- package/dist/schemas/automations.d.ts +27 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js +11 -0
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/ci.d.ts +10 -0
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/compliance.d.ts +423 -0
- package/dist/schemas/compliance.d.ts.map +1 -0
- package/dist/schemas/compliance.js +135 -0
- package/dist/schemas/compliance.js.map +1 -0
- package/dist/schemas/data-protection.d.ts +28 -0
- package/dist/schemas/data-protection.d.ts.map +1 -0
- package/dist/schemas/data-protection.js +49 -0
- package/dist/schemas/data-protection.js.map +1 -0
- package/dist/schemas/devices.d.ts +12 -0
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/engines.d.ts +22 -1
- package/dist/schemas/engines.d.ts.map +1 -1
- package/dist/schemas/engines.js +1 -1
- package/dist/schemas/engines.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +4 -0
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/git/git.d.ts +33 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/git/git.js +29 -0
- package/dist/schemas/git/git.js.map +1 -1
- package/dist/schemas/hosts.d.ts +36 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +2 -0
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/intentic-os.d.ts +117 -0
- package/dist/schemas/intentic-os.d.ts.map +1 -0
- package/dist/schemas/intentic-os.js +66 -0
- package/dist/schemas/intentic-os.js.map +1 -0
- package/dist/schemas/loops.d.ts +15 -0
- package/dist/schemas/loops.d.ts.map +1 -1
- package/dist/schemas/members.d.ts +90 -0
- package/dist/schemas/members.d.ts.map +1 -1
- package/dist/schemas/members.js +73 -3
- package/dist/schemas/members.js.map +1 -1
- package/dist/schemas/needs.d.ts +56 -0
- package/dist/schemas/needs.d.ts.map +1 -1
- package/dist/schemas/offload.d.ts +5 -0
- package/dist/schemas/offload.d.ts.map +1 -1
- package/dist/schemas/personas.d.ts +10 -0
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.d.ts +20 -0
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/provider-oauth.js +1 -1
- package/dist/schemas/providers/provider-oauth.js.map +1 -1
- package/dist/schemas/providers/usage.d.ts +1 -0
- package/dist/schemas/providers/usage.d.ts.map +1 -1
- package/dist/schemas/providers/usage.js +4 -0
- package/dist/schemas/providers/usage.js.map +1 -1
- package/dist/schemas/settings.d.ts +48 -0
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +14 -0
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/system.d.ts +8 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +2 -0
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/workflows.d.ts +50 -0
- package/dist/schemas/workflows.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.d.ts +4 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +16 -1
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/definition.d.ts +80 -4
- 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 +2 -0
- package/dist/state/history-state.js.map +1 -1
- package/package.json +5 -5
- package/src/contracts/activity.contract.ts +1 -1
- package/src/contracts/agents.contract.ts +13 -1
- package/src/contracts/audit.contract.ts +48 -0
- package/src/contracts/compliance.contract.ts +57 -0
- package/src/contracts/providers.contract.ts +9 -0
- package/src/contracts/settings.contract.ts +7 -0
- package/src/events/agent-events.ts +4 -0
- package/src/index.ts +11 -0
- package/src/models/agent-catalog.test.ts +317 -53
- package/src/models/agent-catalog.ts +115 -22
- package/src/models/agent-runtimes.ts +273 -75
- package/src/models/capability-ledger.test.ts +12 -1
- package/src/models/provider-specs.test.ts +42 -7
- package/src/models/provider-specs.ts +160 -20
- package/src/policy/reserved-servers.ts +2 -1
- package/src/policy/sandbox-power.ts +67 -8
- package/src/policy/tests/sandbox-power.test.ts +59 -1
- package/src/policy/turned-away.ts +2 -0
- package/src/protocol/doors/listener-protocol.ts +74 -6
- package/src/protocol/raw/raw-json-routes.ts +2 -1
- package/src/protocol/raw/raw-routes.ts +7 -0
- package/src/schemas/activity.ts +2 -2
- package/src/schemas/agent.ts +22 -9
- package/src/schemas/ai-literacy.ts +17 -0
- package/src/schemas/audit.ts +131 -0
- package/src/schemas/automations.ts +13 -0
- package/src/schemas/compliance.ts +195 -0
- package/src/schemas/daemon-health.test.ts +2 -0
- package/src/schemas/data-protection.ts +99 -0
- package/src/schemas/engines.ts +1 -1
- package/src/schemas/git/git.ts +46 -0
- package/src/schemas/hosts.ts +5 -0
- package/src/schemas/intentic-os.test.ts +86 -0
- package/src/schemas/intentic-os.ts +130 -0
- package/src/schemas/members.test.ts +47 -0
- package/src/schemas/members.ts +141 -6
- package/src/schemas/providers/provider-oauth.ts +1 -1
- package/src/schemas/providers/usage.ts +6 -0
- package/src/schemas/settings.ts +32 -0
- package/src/schemas/system.ts +2 -0
- package/src/schemas/workspace/workspace-tree.ts +26 -1
- package/src/state/history-state.ts +7 -0
|
@@ -8,7 +8,7 @@ export type ExecutionBackend = "shell" | "js";
|
|
|
8
8
|
|
|
9
9
|
export interface AgentCapabilities {
|
|
10
10
|
// Which loop serves the turn; `opencode-gemini` stays separate since adapter health keys off this field.
|
|
11
|
-
readonly runtime: "claude-code" | "codex" | "opencode" | "opencode-gemini" | "acp" | "devin" | "pi" | "cursor";
|
|
11
|
+
readonly runtime: "claude-code" | "codex" | "opencode" | "opencode-gemini" | "acp" | "devin" | "kimi-cli" | "grok-build" | "pi" | "cursor" | "muse";
|
|
12
12
|
// Mid-turn injection (the SteeringQueue behind /agent/steer); needs the SDK's streaming-input mode.
|
|
13
13
|
readonly steering: boolean;
|
|
14
14
|
// How much of the permission-mode axis the runtime honours: every PermissionMode, or just propose-then-approve.
|
|
@@ -49,8 +49,14 @@ export interface AgentCapabilities {
|
|
|
49
49
|
// refuse-only - the same channel, but a clock forces a refusal instead of a park.
|
|
50
50
|
// none - no seam before a command runs; treated as tainted, never as clean.
|
|
51
51
|
readonly rulebook: "hooks" | "approval" | "refuse-only" | "none";
|
|
52
|
-
//
|
|
53
|
-
|
|
52
|
+
// How far the sandbox's stored secrets reach this runtime and are kept from its model:
|
|
53
|
+
// masked - a `{{secret:…}}` reference resolves in the shell, and a stored value is masked out of every tool result,
|
|
54
|
+
// file reads included (the Claude Code loop's PostToolUse hook; Pi's extension, whose tool_result handler sees all).
|
|
55
|
+
// shell - a reference resolves in shell commands and the daemon's own tools, and a value is masked out of what a
|
|
56
|
+
// command prints and those tools' results, since the daemon runs or wraps the shell; a file the agent reads, a
|
|
57
|
+
// fetched page and an MCP result reach the model as they are (Cursor refuses a read of a file holding one instead).
|
|
58
|
+
// none - neither: a reference stays text, and a value reaches the model as the tool read it.
|
|
59
|
+
readonly secrets: "masked" | "shell" | "none";
|
|
54
60
|
// Whether the privacy shield can stand between this loop and its provider: `gateway` when the daemon names the base
|
|
55
61
|
// URL the loop sends its model requests to (so the gateway reads and masks every byte of them); `hooks` when the wire
|
|
56
62
|
// is the vendor's own but every channel the model reads through passes the daemon first (the prompt and instructions
|
|
@@ -94,66 +100,119 @@ export const CLAUDE_CODE: AgentCapabilities = {
|
|
|
94
100
|
toolAllowlist: true,
|
|
95
101
|
};
|
|
96
102
|
|
|
97
|
-
// Codex app-server: item-level events, the turn's remote MCP servers
|
|
98
|
-
//
|
|
99
|
-
// stay unwired.
|
|
103
|
+
// Codex app-server: item-level events, the turn's remote MCP servers and the daemon's own over http, per-thread hooks
|
|
104
|
+
// on the door's policy gate, and its seams (steer, a question request, approval requests, the skills list, the shared
|
|
105
|
+
// mount namespace). Plugins stay unwired.
|
|
100
106
|
export const CODEX: AgentCapabilities = {
|
|
101
107
|
runtime: "codex",
|
|
102
108
|
steering: true,
|
|
103
|
-
|
|
109
|
+
// Every mode: `default` raises the per-tool card on each command, patch and sandbox widening Codex asks about
|
|
110
|
+
// (known-safe commands never ask); plan runs Codex's own plan mode under the shared plan card; the rest run.
|
|
111
|
+
permissions: "modes",
|
|
104
112
|
questions: true,
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
// The daemon's own servers (ui, accounts, secrets, subagents, watch, deps, diagnostics, code, gate) ride the turn's
|
|
114
|
+
// door lease beside its remote mounts (runtimes/daemon-tools/daemon-servers.ts), each with its own tool timeout.
|
|
115
|
+
mcp: "tools",
|
|
116
|
+
// The JS backend is the door's `code` server, its scripts consulted against the turn's gate before they run.
|
|
117
|
+
execution: ["shell", "js"],
|
|
107
118
|
effort: true,
|
|
108
|
-
|
|
119
|
+
// Asks app-server for the tier a model publishes as Fast (serviceTier "priority"), which model/list badges.
|
|
120
|
+
fastMode: true,
|
|
109
121
|
isolation: "namespace",
|
|
110
122
|
commands: true,
|
|
111
|
-
|
|
112
|
-
|
|
123
|
+
// The gate's PreToolUse answer rewrites each shell command through bin/tmux-run into the conversation's agent tmux
|
|
124
|
+
// session, as the Claude loop's Bash hook does (codex-hooks.ts). Codex's own `write_stdin` then reaches tmux-run,
|
|
125
|
+
// not the program in the pane, and a call tmux-run returns from early ends Codex's process for it.
|
|
126
|
+
terminals: true,
|
|
127
|
+
// Failures arrive typed (codexErrorInfo): a transport or capacity failure is coded provider-outage, a spent
|
|
128
|
+
// allowance rate_limit, a full window context-overflow, so the breaker counts them and auto-resume re-runs them.
|
|
129
|
+
recovery: true,
|
|
113
130
|
warm: false,
|
|
114
|
-
//
|
|
131
|
+
// thread/start's own fields: baseInstructions replaces Codex's base prompt, developerInstructions adds a developer
|
|
132
|
+
// message.
|
|
115
133
|
instructions: "replace",
|
|
116
134
|
skillDiscovery: "native",
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
// A per-thread PreToolUse hook puts every function tool (the shell, apply_patch, every MCP tool, spawn_agent) to the
|
|
136
|
+
// door's gate before it runs, which may park it on a card (codex-hooks.ts). Codex fails a hook open, so the gate is
|
|
137
|
+
// confirmed connected before the turn starts, a command or patch Codex asks approval for runs only if the gate
|
|
138
|
+
// allowed that very call, and a call that starts unanswered stops the turn. Codex's own subagents' threads never
|
|
139
|
+
// connect the gate, so there the rules reach only the commands and patches Codex asks about.
|
|
140
|
+
rulebook: "hooks",
|
|
141
|
+
// Shell commands resolve `{{secret:…}}` in the gate's rewrite and run under a wrapper that masks stored values in
|
|
142
|
+
// their output (codex-mask-script.ts); apply_patch, view_image and hosted tools pass no wrapper.
|
|
143
|
+
secrets: "shell",
|
|
120
144
|
// Its model provider's base_url is the daemon's, written into the per-thread config.
|
|
121
145
|
privacy: "gateway",
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
146
|
+
// The gate's PreToolUse refuses every call off the list, fail closed on the turn's own thread as above; with a list
|
|
147
|
+
// Codex's hosted search and pictures, its image viewer, question tool and own subagents are switched off, the shell
|
|
148
|
+
// too unless listed, and each MCP server is cut to its listed tools (`enabled_tools`). The residual: a known-safe
|
|
149
|
+
// read-only command off the list runs if the in-process gate fails after it connected, and the turn is then stopped.
|
|
150
|
+
toolAllowlist: true,
|
|
125
151
|
};
|
|
126
152
|
|
|
127
153
|
// OpenCode (the Grok runtime): its own agentic loop and tools, with the turn's remote MCP servers mounted on the shared
|
|
128
|
-
// server per conversation
|
|
154
|
+
// server per conversation, driven over OpenCode 2's session API (runtimes/opencode).
|
|
129
155
|
export const OPENCODE: AgentCapabilities = {
|
|
130
156
|
runtime: "opencode",
|
|
131
|
-
steering:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
157
|
+
// The turn's steering queue is sent as OpenCode steers (`session.prompt` with `delivery: "steer"`): taken in at the
|
|
158
|
+
// model's next step, or starting the next execution of the same turn once its work is done; the turn stays open until
|
|
159
|
+
// the session says it took each one in.
|
|
160
|
+
steering: true,
|
|
161
|
+
// `default` puts every edit, fetch and command the rulebook let through on a per-tool card (session rules asking about
|
|
162
|
+
// them, answered from the card, never "always"); `plan` is still the emulated propose-then-approve, since OpenCode's
|
|
163
|
+
// own plan agent has no card of its own.
|
|
164
|
+
permissions: "modes",
|
|
165
|
+
// OpenCode's `question` tool raises a form, drawn as a question card and answered from it; a form no card can carry
|
|
166
|
+
// is cancelled with a sentence telling the model to carry on.
|
|
167
|
+
questions: true,
|
|
168
|
+
// The turn's remote servers and the daemon's own (ui, accounts, secrets, subagents, watch, deps, diagnostics, code),
|
|
169
|
+
// served through the MCP door on the turn's lease (daemon-tools/door-tools.ts) and added at runtime under the
|
|
170
|
+
// conversation's own names, each session's own rules showing it only its own (opencode-mcp.ts); no plugins.
|
|
171
|
+
mcp: "tools",
|
|
172
|
+
// The daemon's JS backend is the door's `code` server, each script consulted against the turn's gate through the
|
|
173
|
+
// relay the loop attaches (runtimes/daemon-tools/turn-relay.ts).
|
|
174
|
+
execution: ["shell", "js"],
|
|
175
|
+
// The turn's tier is the session's model variant, where the model declares that tier: the Grok 3 Mini line on xAI,
|
|
176
|
+
// and every Google model the translator publishes a thinking scale for.
|
|
177
|
+
effort: true,
|
|
138
178
|
fastMode: false,
|
|
179
|
+
// One `opencode serve` serves every conversation from the daemon's own mount namespace. A server per conversation
|
|
180
|
+
// spawned into its turn's namespace (as Codex and Cursor spawn) is not built, for three reasons found 2026-10-12: its
|
|
181
|
+
// sessions would live in a data dir of their own, so every conversation's existing sessions would have to move there
|
|
182
|
+
// (session.export/import) and back; the xAI sign-in would have to be copied into each (credential.create), and two
|
|
183
|
+
// servers refreshing one OAuth grant is untested; and the shell script's socket and the data dir sit under the
|
|
184
|
+
// daemon's auth dir, which an anchored turn's /work does not show and an agent domain must not reach.
|
|
139
185
|
isolation: "cwd",
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
186
|
+
// OpenCode's command list is published each turn, and a `/name` prompt runs as that command.
|
|
187
|
+
commands: true,
|
|
188
|
+
// OpenCode runs its shell as the daemon's script, which runs each command through tmux-run in the conversation's tmux
|
|
189
|
+
// session, and the turn surfaces it with a `terminal` frame (runtimes/opencode/shell/opencode-shell.ts).
|
|
190
|
+
terminals: true,
|
|
191
|
+
// Failures are coded from OpenCode's own failure types: a spent allowance `rate_limit`, a provider's transport,
|
|
192
|
+
// internal or timeout failure (and a retry the turn will not wait out, or a silent provider) `provider-outage`, a
|
|
193
|
+
// session past its window `context-overflow`, an unroutable model `model-unavailable`.
|
|
194
|
+
recovery: true,
|
|
143
195
|
warm: false,
|
|
144
|
-
//
|
|
145
|
-
|
|
196
|
+
// A prompt that replaces the base (the owner's own under `custom`, a small window's paragraph) runs on the daemon's
|
|
197
|
+
// twin agents, whose base is blank, so it is the whole system text; anything else is added to OpenCode's own base.
|
|
198
|
+
instructions: "replace",
|
|
146
199
|
skillDiscovery: "prompt",
|
|
147
|
-
// OpenCode raises its permission asks for
|
|
148
|
-
//
|
|
200
|
+
// OpenCode raises its permission asks for every shell command, a subagent's included (the server's own rules ask about
|
|
201
|
+
// them all, and a child session inherits them); the daemon answers from the rulebook, a hold parked on a card while
|
|
202
|
+
// the turn's inactivity watchdog is held. The JS backend consults the same gate. Not `hooks`: which calls ask is still
|
|
203
|
+
// OpenCode's permission config (the daemon's rules make it every shell command), and an edit or an MCP call is asked
|
|
204
|
+
// about only where `default` mode puts it on a person's card.
|
|
149
205
|
rulebook: "approval",
|
|
150
|
-
|
|
206
|
+
// The daemon's shell script resolves a command's secret references after the rulebook judged it, and masks what it
|
|
207
|
+
// prints back to the references before OpenCode reads it (runtimes/opencode/shell/opencode-shell.ts). A file the read tool opens is not.
|
|
208
|
+
secrets: "shell",
|
|
151
209
|
// The shared server's provider baseURLs are written by the daemon at spawn.
|
|
152
210
|
privacy: "gateway",
|
|
153
|
-
//
|
|
154
|
-
// so
|
|
155
|
-
//
|
|
156
|
-
|
|
211
|
+
// A turn's list becomes its session's rules: every action denied, the listed ones allowed, the server's asks kept
|
|
212
|
+
// after them, so the model is offered only the listed tools and OpenCode refuses a call to any other; a subagent's
|
|
213
|
+
// session inherits them. Every built-in tool has its own permission action (checked against 2.0.26), and a shell entry
|
|
214
|
+
// narrowed to a command is checked against each command's ask (runtimes/opencode/allowlist/opencode-allowlist.ts).
|
|
215
|
+
toolAllowlist: true,
|
|
157
216
|
};
|
|
158
217
|
|
|
159
218
|
// The same OpenCode loop, serving Gemini instead of xAI, identical abilities. The Claude Code loop announces itself in
|
|
@@ -164,25 +223,44 @@ export const OPENCODE_GEMINI: AgentCapabilities = {
|
|
|
164
223
|
};
|
|
165
224
|
|
|
166
225
|
// Any agent speaking the Agent Client Protocol: a documented floor, not the native ceiling. Publishes commands and
|
|
167
|
-
// terminals, takes the turn's remote MCP servers when it advertises http MCP,
|
|
226
|
+
// terminals, takes the turn's remote MCP servers when it advertises http MCP, and uses what else the agent advertises
|
|
227
|
+
// per session (its modes, its `thought_level` option, form elicitation); what no agent is bound to advertise stays off.
|
|
168
228
|
export const ACP: AgentCapabilities = {
|
|
169
229
|
runtime: "acp",
|
|
170
230
|
steering: false,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
231
|
+
// Every mode: a `default` turn puts each call the agent asks permission for on a person's card (acp-permissions.ts),
|
|
232
|
+
// a plan turn runs the daemon's two phases with the agent's own plan mode under the first where it has one, and the
|
|
233
|
+
// turn's posture moves the session into the agent's matching mode by id or name (acp-modes.ts).
|
|
234
|
+
permissions: "modes",
|
|
235
|
+
// Form elicitation is advertised, and a form parks on the question card (acp-elicitation.ts); whether the agent asks
|
|
236
|
+
// through it is its own choice, as which calls it asks permission for is.
|
|
237
|
+
questions: true,
|
|
238
|
+
// The turn's remote mounts and the daemon's own servers (ui, accounts, secrets, subagents, watch, deps, diagnostics,
|
|
239
|
+
// code) on its door lease (daemon-servers.ts): over http where the agent advertises http MCP, else through the
|
|
240
|
+
// daemon's stdio proxy (acp-mcp-proxy.ts), the transport every ACP agent takes. A warm session keeps the servers it
|
|
241
|
+
// opened with, so one a later turn adds is seen from the next session on.
|
|
242
|
+
mcp: "tools",
|
|
243
|
+
// The JS backend is the door's `code` server, each script asked of the turn's gate before it runs.
|
|
244
|
+
execution: ["shell", "js"],
|
|
245
|
+
// A session's `thought_level` option takes the turn's effort where the agent offers one (acp-model.ts), but this
|
|
246
|
+
// record is every agent's and most offer none, so the picker shows no scale.
|
|
175
247
|
effort: false,
|
|
176
248
|
fastMode: false,
|
|
249
|
+
// One warm process serves every conversation on the agent, each session in its own cwd; a mount namespace belongs to
|
|
250
|
+
// one turn, so a process shared across conversations can stand in none of them. Keying the pool by namespace would
|
|
251
|
+
// give up the warm sessions the pool exists for.
|
|
177
252
|
isolation: "cwd",
|
|
178
253
|
commands: true,
|
|
179
254
|
terminals: true,
|
|
255
|
+
// A failure the agent words as a spent allowance or an outgrown window is coded (acp-agent.ts ACP_FAILURES), but the
|
|
256
|
+
// words are each agent's own and the protocol marks no outage, so nothing promises the codes auto-resume keys off.
|
|
180
257
|
recovery: false,
|
|
181
258
|
warm: false,
|
|
182
259
|
// ACP's calls carry no system field: the agent owns its instructions, the persona note rides the message.
|
|
183
260
|
instructions: "none",
|
|
184
261
|
skillDiscovery: "prompt",
|
|
185
|
-
// In the protocol floor, so every agent has it; which calls it asks about is entirely its own choice.
|
|
262
|
+
// In the protocol floor, so every agent has it; which calls it asks about is entirely its own choice. A terminal the
|
|
263
|
+
// daemon runs for it (terminal/create) is asked about here too, unless the permission for it already was.
|
|
186
264
|
rulebook: "approval",
|
|
187
265
|
secrets: "none",
|
|
188
266
|
// The agent picks its own provider and endpoint from its own login and environment.
|
|
@@ -193,38 +271,91 @@ export const ACP: AgentCapabilities = {
|
|
|
193
271
|
|
|
194
272
|
// Devin's own CLI (`devin acp`), the ACP floor with one seam an installed agent lacks: the daemon picks the model, from
|
|
195
273
|
// the account's own list, through the session's model option. Its own runtime name, as OpenCode's Gemini twin has, since
|
|
196
|
-
// adapter health keys off this field and Devin's readiness is an account and an engine, not an installed card.
|
|
274
|
+
// adapter health keys off this field and Devin's readiness is an account and an engine, not an installed card. Its
|
|
275
|
+
// modes (`accept-edits`, `smart`, `ask`, `plan`, `bypass` as of CLI 3000.11.3) carry the floor's posture mapping.
|
|
197
276
|
export const DEVIN: AgentCapabilities = {
|
|
198
277
|
...ACP,
|
|
199
278
|
runtime: "devin",
|
|
279
|
+
// Devin's sessions offer no `thought_level` option (CLI 3000.11.3); the model probe reads one should it appear
|
|
280
|
+
// (devin-catalog.ts), and the floor already forwards the turn's effort to it.
|
|
281
|
+
effort: false,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// Moonshot's Kimi Code CLI (`kimi acp`), the ACP floor where the CLI's handshake grants more (2.1.1): the daemon picks the
|
|
285
|
+
// model from the account's own list through the session's `model` option, and a session offers a `thinking` option in
|
|
286
|
+
// the protocol's `thought_level` category, `off` plus the efforts the model declares, which the turn's effort settles
|
|
287
|
+
// (acp-model.ts). Its modes (`default`, `plan`, `auto`, `yolo`) carry the floor's posture mapping, and its ask-user
|
|
288
|
+
// tool raises a form elicitation, which parks on the question card. It advertises http MCP, so the turn's servers
|
|
289
|
+
// reach it directly. Its own runtime name, since its readiness is a CLI sign-in and an engine, not an installed card.
|
|
290
|
+
export const KIMI_CLI: AgentCapabilities = {
|
|
291
|
+
...ACP,
|
|
292
|
+
runtime: "kimi-cli",
|
|
293
|
+
effort: true,
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// xAI's Grok Build CLI (`grok agent stdio`), the ACP floor where its handshake grants more (1.0.52): the model through the
|
|
297
|
+
// session's `model` option and the turn's effort through its `thought_level` option (each model's own levels, `low` to
|
|
298
|
+
// `xhigh`). Its modes are `default`, `plan` and `ask`: no bypass mode, so a turn that runs without asking stays in
|
|
299
|
+
// `default` and the floor answers each permission it raises from the rulebook. It advertises http MCP.
|
|
300
|
+
export const GROK_BUILD: AgentCapabilities = {
|
|
301
|
+
...ACP,
|
|
302
|
+
runtime: "grok-build",
|
|
303
|
+
effort: true,
|
|
304
|
+
// Its ask-user tool reaches its own client through an xAI protocol extension, not form elicitation, so the daemon
|
|
305
|
+
// switches the tool off for every session it opens (grok-build-cli.ts) rather than leave the model asking nobody.
|
|
306
|
+
questions: false,
|
|
200
307
|
};
|
|
201
308
|
|
|
202
309
|
// Pi driven over its RPC mode: above the ACP floor and below the Claude Code ceiling. Real mid-turn steering, an effort
|
|
203
|
-
// scale,
|
|
310
|
+
// scale, a published command list, and a process started per turn with the daemon's instructions, skills, MCP servers
|
|
311
|
+
// and namespace (runtimes/pi/pi-rpc.ts). No approval channel: the daemon's own Pi extension stands in front of every
|
|
312
|
+
// tool instead (runtimes/pi/pi-hooks.ts).
|
|
204
313
|
export const PI: AgentCapabilities = {
|
|
205
314
|
runtime: "pi",
|
|
206
315
|
steering: true,
|
|
207
316
|
permissions: "plan",
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
317
|
+
// The daemon's own Pi extension registers an `ask_user` tool on Pi's dialogs, which park on the question card
|
|
318
|
+
// (pi-extension.ts, pi-extension-ui.ts).
|
|
319
|
+
questions: true,
|
|
320
|
+
// The turn's remote servers and the daemon's own (daemon-servers.ts), mounted through the same extension with Pi's
|
|
321
|
+
// built-in MCP and declared to the model; Pi has it from 0.99, an older Pi mounts none, and the turn says so rather
|
|
322
|
+
// than the picker.
|
|
323
|
+
mcp: "tools",
|
|
324
|
+
// The JS backend is the door's `code` server, each script asked of the turn's gate before it runs.
|
|
325
|
+
execution: ["shell", "js"],
|
|
211
326
|
effort: true,
|
|
212
327
|
fastMode: false,
|
|
213
|
-
|
|
328
|
+
// An anchored turn's Pi is entered into its mount namespace (nsenter), as Codex's and Cursor's are.
|
|
329
|
+
isolation: "namespace",
|
|
214
330
|
commands: true,
|
|
215
|
-
|
|
216
|
-
|
|
331
|
+
// The extension's `tool_call` hook rewrites each bash line through bin/tmux-run into the conversation's agent tmux
|
|
332
|
+
// session, as the Claude loop's Bash hook does (pi-hooks.ts).
|
|
333
|
+
terminals: true,
|
|
334
|
+
// Pi reports a provider failure as its own event (auto_retry_end, an errored message_end) carrying the provider's
|
|
335
|
+
// sentence, status code included, which the shared rules code (pi-events.ts PI_FAILURES).
|
|
336
|
+
recovery: true,
|
|
217
337
|
warm: false,
|
|
218
|
-
// Pi's
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
338
|
+
// `--system-prompt` replaces Pi's base and `--append-system-prompt` adds to it, both per process; `--no-context-files`
|
|
339
|
+
// keeps Pi from loading AGENTS.md a second time beside the daemon's own note.
|
|
340
|
+
instructions: "replace",
|
|
341
|
+
// `--skill` per loaded skill, the persona's filter applied, with Pi's own discovery off (`--no-skills`).
|
|
342
|
+
skillDiscovery: "native",
|
|
343
|
+
// The daemon's extension, loaded with `-e` ahead of any other and whatever the card's command says of discovery, puts
|
|
344
|
+
// every tool call (MCP and codemode calls included) to the turn's own hook socket before it runs, where a held one
|
|
345
|
+
// parks on a card while Pi waits (pi-hooks.ts). A call it cannot ask about is refused, as a handler that throws is,
|
|
346
|
+
// and the turn does not start on a Pi whose extension never said its hooks are in place. It declines trust in the
|
|
347
|
+
// project, so nothing the agent writes into the workspace loads as an extension after it; one the owner installed
|
|
348
|
+
// for Pi itself still sees a call after the rules did.
|
|
349
|
+
rulebook: "hooks",
|
|
350
|
+
// Shell lines resolve `{{secret:…}}` before they run, and the extension's `tool_result` hook masks every stored value
|
|
351
|
+
// in every tool's result, file reads included, as the Claude loop's PostToolUse does; a result it cannot mask is
|
|
352
|
+
// withheld.
|
|
353
|
+
secrets: "masked",
|
|
224
354
|
// Pi calls its provider from its own login; the daemon names no endpoint.
|
|
225
355
|
privacy: "none",
|
|
226
|
-
//
|
|
227
|
-
|
|
356
|
+
// The same socket refuses every call off the turn's list, Pi's tools read under the Claude loop's names (bash as
|
|
357
|
+
// Bash, find as Glob) and MCP tools under the same `mcp__<server>__<tool>`; fail closed as above.
|
|
358
|
+
toolAllowlist: true,
|
|
228
359
|
};
|
|
229
360
|
|
|
230
361
|
// Cursor's own runtime, driven through `@cursor/sdk` from this daemon's process; an embedding surface, so most seams
|
|
@@ -233,8 +364,12 @@ export const CURSOR: AgentCapabilities = {
|
|
|
233
364
|
runtime: "cursor",
|
|
234
365
|
// Run.steer injects into the live run; only a `complete_delivered` ack transfers ownership of the message.
|
|
235
366
|
steering: true,
|
|
236
|
-
//
|
|
237
|
-
|
|
367
|
+
// Every mode. `default` puts each call that changes something on the per-tool card: the preToolUse and
|
|
368
|
+
// beforeMCPExecution hooks park on it for Cursor's own tools and an MCP server's, a shell command after the rules
|
|
369
|
+
// unless their own card stood in, and the daemon's custom tools ask in their handlers, which Cursor never asks about
|
|
370
|
+
// (cursor-approvals.ts). `plan` runs the daemon's two phases with Cursor's read-only plan mode under the first; the
|
|
371
|
+
// rest run.
|
|
372
|
+
permissions: "modes",
|
|
238
373
|
// True since the daemon supplies its own ask tool; Cursor's own can fabricate an answer, so it's disallowed.
|
|
239
374
|
questions: true,
|
|
240
375
|
// The turn's remote MCP servers plus host callbacks; everything but a Claude Code plugin checkout.
|
|
@@ -248,27 +383,90 @@ export const CURSOR: AgentCapabilities = {
|
|
|
248
383
|
// The SDK agent of an anchored turn runs in a runtime process born in the turn's mount namespace (the daemon keeps
|
|
249
384
|
// the loop, the tools and the hook gate), so its shell and its edits see the worktree at /work.
|
|
250
385
|
isolation: "namespace",
|
|
251
|
-
// Cursor's commands are files on disk the SDK loads but doesn't publish back, so
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
386
|
+
// Cursor's commands are files on disk (`.cursor/commands/*.md`) the SDK loads but doesn't publish back, so the daemon
|
|
387
|
+
// reads them itself, publishes the list and sends `/name` as the command's text (cursor-commands.ts).
|
|
388
|
+
commands: true,
|
|
389
|
+
// Every shell command runs through the hook script, which the daemon hands the command as a bin/tmux-run line, so it
|
|
390
|
+
// runs in the `agent-<session>` tmux session the panel attaches to, as a Claude Code turn's Bash does
|
|
391
|
+
// (cursor-terminal.ts). Where tmux-run is not in the image the command runs as the script's own child.
|
|
392
|
+
terminals: true,
|
|
255
393
|
// The SDK throws typed errors instead of dissolving a refusal into prose, so the adapter files coded frames.
|
|
256
394
|
recovery: true,
|
|
257
395
|
warm: false,
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
396
|
+
// The owner's replacement prompt replaces Cursor's base through AgentOptions.systemPrompt on an account entitled to
|
|
397
|
+
// it. The entitlement is server-side and answered only by a send, so a turn tries it and an account refused runs the
|
|
398
|
+
// turn again with the replacement folded onto the base through `beforeSubmitPrompt`, remembered for its later turns
|
|
399
|
+
// (cursor-agent.ts); everything else the daemon adds always rides that append.
|
|
400
|
+
instructions: "replace",
|
|
401
|
+
// Cursor's own loader reads every SKILL.md under `.agents/skills/` of each workspace root it is given: the cwd holds
|
|
402
|
+
// the loaded skills, and the worn persona's kit is laid out as a second root (`local.dirs`); a skill the persona
|
|
403
|
+
// withholds is refused at the read tool, the seam the Claude loop's `Skill(<name>)` denial is (cursor-skills.ts).
|
|
404
|
+
skillDiscovery: "native",
|
|
262
405
|
// The full hook tier, the only foreign runtime to reach it: a hold parks since the vendor waits on the hook.
|
|
263
406
|
rulebook: "hooks",
|
|
264
|
-
//
|
|
265
|
-
|
|
407
|
+
// Every shell command runs through the hook script: a `{{secret:name}}` reference resolves into what the script runs once
|
|
408
|
+
// the rules let the command through, and what it prints is masked back before Cursor reads it. Not "masked": Cursor's
|
|
409
|
+
// read tool can be refused but not rewritten, so a file holding a stored value is refused there, and what grep, list
|
|
410
|
+
// or an MCP server hands back is not read at all (cursor-secrets.ts).
|
|
411
|
+
secrets: "shell",
|
|
266
412
|
// Cursor's own RPC to its own servers, so no gateway; but the daemon owns every channel the model reads through:
|
|
267
413
|
// it hands over the prompt and instructions, its hooks stand before each file read and rewrite each shell command
|
|
268
414
|
// to mask the output, the tools that read past both (grep, ls, glob, semantic search, fetch, lints) are withheld,
|
|
269
415
|
// and MCP goes through the masking proxy (runtimes/cursor/cursor-shield.ts).
|
|
270
416
|
privacy: "hooks",
|
|
271
|
-
//
|
|
272
|
-
//
|
|
417
|
+
// Three layers (cursor-tool-list.ts): the `tools` option offers only the listed built-ins, a header Cursor's backend
|
|
418
|
+
// holds the main loop and, with `subagentInherit`, every `Task` child to; only the listed MCP servers and custom
|
|
419
|
+
// tools are mounted, and each custom tool checks the list in its handler; and every call Cursor's local executors run
|
|
420
|
+
// passes preToolUse or beforeMCPExecution, which check it (a `Bash(...)` narrowing included) and refuse a call they
|
|
421
|
+
// cannot place in a turn. A turn carrying a list does not start unless those hooks are installed, and a hook the
|
|
422
|
+
// daemon cannot answer refuses a live turn's call.
|
|
423
|
+
toolAllowlist: true,
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// Muse Code, Meta's coding agent, driven over the Muse Session Protocol: one `muse serve` host per turn, born in the turn's
|
|
427
|
+
// mount namespace, its session kept in Muse's own store so the next turn resumes it (runtimes/muse). Meta's own loop for
|
|
428
|
+
// Meta's key, and a host for any other model API whose turn the daemon's translator serves on the Responses wire.
|
|
429
|
+
export const MUSE: AgentCapabilities = {
|
|
430
|
+
runtime: "muse",
|
|
431
|
+
// turn/steer into the running turn; a steer that arrives after it ended starts the next turn of the same phase.
|
|
432
|
+
steering: true,
|
|
433
|
+
// Every mode: sessions run under approval mode `promptUnmatched`, so Muse raises every shell command off its own allow
|
|
434
|
+
// rules. `default` puts each one the rulebook lets through on the per-tool card; plan runs a planning phase on Muse's
|
|
435
|
+
// `:read-only` profile (every approval refused) under the shared plan card, then executes on `:ask-me`; the rest run,
|
|
436
|
+
// the rulebook still answering every command. Workspace file edits raise nothing on `:ask-me`, so they get no card.
|
|
437
|
+
permissions: "modes",
|
|
438
|
+
// userInput/request parks on the question card and is answered back (userInput/answer, userInput/cancel).
|
|
439
|
+
questions: true,
|
|
440
|
+
// The turn's remote list and the daemon's own servers through the door (daemonServersFor), both as the session's
|
|
441
|
+
// own streamable-HTTP MCP config; no plugin checkouts.
|
|
442
|
+
mcp: "tools",
|
|
443
|
+
// The door's `code` server mounts the JS backend, its scripts consulted against the gate the loop attaches.
|
|
444
|
+
execution: ["shell", "js"],
|
|
445
|
+
// turn/start's reasoningEffort, in Muse's own tier names (the model list says which a model takes).
|
|
446
|
+
effort: true,
|
|
447
|
+
fastMode: false,
|
|
448
|
+
// The host is nsentered into an anchored turn's namespace, so its shell and edits see the worktree at /work.
|
|
449
|
+
isolation: "namespace",
|
|
450
|
+
// Muse's skills are not published back as a list, and a `/name` prompt is not turned into a skill input part.
|
|
451
|
+
commands: false,
|
|
452
|
+
terminals: false,
|
|
453
|
+
// Failures arrive typed (TurnError): a quota-exhausted one is coded rate_limit, a window the session outgrew
|
|
454
|
+
// context-overflow, a model call Muse retried and could not get through provider-outage, a host gone quiet
|
|
455
|
+
// provider-outage too; turn/retryScheduled is shown as the in-turn retry it is (muse-stream.ts).
|
|
456
|
+
recovery: true,
|
|
457
|
+
warm: false,
|
|
458
|
+
// No MSP call carries a system prompt (session config takes only MCP servers), so the daemon's notes ride the
|
|
459
|
+
// message and the owner's replacement prompt is not applied.
|
|
460
|
+
instructions: "none",
|
|
461
|
+
// Muse loads a trusted workspace's own skills from its own directories, which are not the daemon's; the daemon names
|
|
462
|
+
// the loaded ones in the opener.
|
|
463
|
+
skillDiscovery: "prompt",
|
|
464
|
+
// Muse's approval channel, answered from the rulebook; which commands Muse runs without asking (its own allow rules)
|
|
465
|
+
// is its choice.
|
|
466
|
+
rulebook: "approval",
|
|
467
|
+
secrets: "none",
|
|
468
|
+
// A Meta turn talks to api.meta.ai, a base the daemon does not name; Muse also reads files it never shows the daemon.
|
|
469
|
+
privacy: "none",
|
|
470
|
+
// Edits and reads run without asking anyone, so no answer the daemon gives can keep a call off a list.
|
|
273
471
|
toolAllowlist: false,
|
|
274
472
|
};
|
|
@@ -47,7 +47,9 @@ const LEDGER: Record<keyof AgentCapabilities, Backing> = {
|
|
|
47
47
|
commands: "descriptive",
|
|
48
48
|
terminals: "descriptive",
|
|
49
49
|
recovery: "descriptive",
|
|
50
|
-
// descriptive:
|
|
50
|
+
// descriptive: where masking happens is each runtime's own wiring (the Claude Code loop's PostToolUse hook, Pi's
|
|
51
|
+
// extension, the shell wrappers of Codex and Cursor, OpenCode's daemon-run shell script); nothing gates a turn on it,
|
|
52
|
+
// and each answer short of the ceiling reaches the user as its own limitationsOf sentence.
|
|
51
53
|
secrets: "descriptive",
|
|
52
54
|
};
|
|
53
55
|
|
|
@@ -86,6 +88,15 @@ describe("a descriptive claim reaches the user", () => {
|
|
|
86
88
|
});
|
|
87
89
|
});
|
|
88
90
|
|
|
91
|
+
// A middle answer has words of its own, distinct from the floor's: a runtime that masks only its shell says so.
|
|
92
|
+
it("secrets' middle answer is disclosed apart from its floor", () => {
|
|
93
|
+
const shell = limitationsOf({ ...CEILING, secrets: "shell" });
|
|
94
|
+
const none = limitationsOf({ ...CEILING, secrets: "none" });
|
|
95
|
+
expect(shell).toHaveLength(1);
|
|
96
|
+
expect(none).toHaveLength(1);
|
|
97
|
+
expect(shell).not.toEqual(none);
|
|
98
|
+
});
|
|
99
|
+
|
|
89
100
|
it("is a real split: neither side is empty", () => {
|
|
90
101
|
expect(fieldsWhere("enforced").length).toBeGreaterThan(0);
|
|
91
102
|
expect(fieldsWhere("descriptive").length).toBeGreaterThan(0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PROVIDER_BRAND_PATHS } from "@intentic/constants";
|
|
2
|
-
import { accessFor, capabilitiesOf, harnessChoosable, PROVIDER_ACCESS, PROVIDER_VENDOR, PROVIDERS, providerLabel } from "./agent-catalog.js";
|
|
2
|
+
import { accessFor, capabilitiesOf, harnessChoosable, limitationsOf, PROVIDER_ACCESS, PROVIDER_VENDOR, PROVIDERS, providerLabel } from "./agent-catalog.js";
|
|
3
3
|
import {
|
|
4
4
|
ACCESS_COST,
|
|
5
5
|
cliProxyIdOf,
|
|
@@ -102,18 +102,21 @@ test("no provider id can be mistaken for an endpoint or a pinned selection", ()
|
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
test("
|
|
105
|
+
test("every provider offers its own default loop, and each offered loop runs a different runtime", () => {
|
|
106
106
|
for (const spec of PROVIDER_SPECS) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
const offered = Object.entries(spec.loops.offered);
|
|
108
|
+
expect(Object.keys(spec.loops.offered), `${spec.id}'s default loop is not offered`).toContain(spec.loops.default);
|
|
109
|
+
// Two loops on one runtime would be a chip whose positions run the same thing.
|
|
110
|
+
const runtimes = offered.map(([, offer]) => offer?.capabilities.runtime);
|
|
111
|
+
expect(new Set(runtimes).size, `${spec.id} offers two loops on one runtime`).toBe(runtimes.length);
|
|
112
|
+
expect(harnessChoosable(spec.id), spec.id).toBe(offered.length > 1);
|
|
110
113
|
}
|
|
111
114
|
});
|
|
112
115
|
|
|
113
|
-
test("a minted provider runs
|
|
116
|
+
test("a minted provider runs Claude Code where asked, and Meta's key its own Muse Code by default", () => {
|
|
114
117
|
for (const provider of MINTED_PROVIDERS) {
|
|
115
|
-
expect(capabilitiesOf(provider, "native").runtime, provider).toBe("claude-code");
|
|
116
118
|
expect(capabilitiesOf(provider, "claude-code").runtime, provider).toBe("claude-code");
|
|
119
|
+
expect(capabilitiesOf(provider, "native").runtime, provider).toBe(provider === "meta" ? "muse" : "claude-code");
|
|
117
120
|
}
|
|
118
121
|
});
|
|
119
122
|
|
|
@@ -136,3 +139,35 @@ test("a list of ids names known providers once each, in its own order", () => {
|
|
|
136
139
|
expect(nativeProvidersIn(null)).toEqual([]);
|
|
137
140
|
expect(nativeProvidersIn(undefined)).toEqual([]);
|
|
138
141
|
});
|
|
142
|
+
|
|
143
|
+
// Cursor's own runtime: its project commands are read and published by the daemon, and the owner's replacement prompt
|
|
144
|
+
// replaces Cursor's base where the account is entitled to (the fallback for one that is not is the append).
|
|
145
|
+
test("cursor publishes its commands and replaces its base prompt", () => {
|
|
146
|
+
const cursor = capabilitiesOf("cursor", "native");
|
|
147
|
+
expect(cursor.runtime).toBe("cursor");
|
|
148
|
+
expect(cursor.commands).toBe(true);
|
|
149
|
+
expect(cursor.instructions).toBe("replace");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// What the hook script and the SDK's own seams carry on Cursor's runtime: per-tool cards in `default` mode, the shell in
|
|
153
|
+
// the terminal panel, its own skill loader, and a tool list nothing gets past (runtimes/cursor/).
|
|
154
|
+
test("cursor holds every mode, a tool list, the terminal panel and its own skills", () => {
|
|
155
|
+
const cursor = capabilitiesOf("cursor", "native");
|
|
156
|
+
expect(cursor.permissions).toBe("modes");
|
|
157
|
+
expect(cursor.terminals).toBe(true);
|
|
158
|
+
expect(cursor.skillDiscovery).toBe("native");
|
|
159
|
+
expect(cursor.toolAllowlist).toBe(true);
|
|
160
|
+
expect(limitationsOf(cursor)).toEqual(["no plugins", "secrets masked in shell output only, not in files the agent reads"]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Devin runs the ACP floor under its own name: what the floor gained (approvals, questions) it has too, and the effort
|
|
164
|
+
// scale it does not advertise stays off.
|
|
165
|
+
test("devin is the ACP floor under its own name", () => {
|
|
166
|
+
const devin = capabilitiesOf("devin", "native");
|
|
167
|
+
const floor = capabilitiesOf("some-installed-agent", "native");
|
|
168
|
+
expect(devin.runtime).toBe("devin");
|
|
169
|
+
expect({ ...devin, runtime: floor.runtime }).toEqual(floor);
|
|
170
|
+
expect(devin.permissions).toBe("modes");
|
|
171
|
+
expect(devin.questions).toBe(true);
|
|
172
|
+
expect(devin.effort).toBe(false);
|
|
173
|
+
});
|