@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ProviderBrand } from "@intentic/constants";
|
|
2
|
-
import
|
|
2
|
+
import type { AgentLoop } from "../schemas/agent.js";
|
|
3
|
+
import { type AgentCapabilities, CLAUDE_CODE, CODEX, CURSOR, DEVIN, GROK_BUILD, KIMI_CLI, MUSE, OPENCODE, OPENCODE_GEMINI } from "./agent-runtimes.js";
|
|
3
4
|
|
|
4
5
|
// Every fact about a provider more than one surface needs, one row each, replacing lists that drifted out of sync.
|
|
5
6
|
// `access` (cost) and `auth` (connection) stay separate: conflating them mis-describes Z.ai, a prepaid plan spent
|
|
@@ -43,8 +44,47 @@ export interface MintedVariant {
|
|
|
43
44
|
readonly flow: "device" | "redirect";
|
|
44
45
|
// ANTHROPIC_BASE_URL for a turn minted here; no version segment, the harness appends /v1/messages itself.
|
|
45
46
|
readonly anthropicBase: string;
|
|
46
|
-
// Where this estate's catalog is read from: an OpenAI-compatible root, with its version segment.
|
|
47
|
+
// Where this estate's catalog is read from: an OpenAI-compatible root, with its version segment. Also the Chat
|
|
48
|
+
// Completions root a loop speaking that wire (OpenCode) sends its turns to.
|
|
47
49
|
readonly catalogBase: string;
|
|
50
|
+
// The estate's OpenAI Responses root, with its version segment, for a loop that speaks only that wire (Codex); absent
|
|
51
|
+
// where the vendor publishes none, which keeps such a loop off this estate.
|
|
52
|
+
readonly responsesBase?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// What a vendor's own terms say about one loop serving its subscription, when there is something worth saying. Shown
|
|
56
|
+
// quietly (an icon and its hover card, never a banner): the owner keeps these routes by choice, and the note is there so
|
|
57
|
+
// nobody runs one without being able to find out.
|
|
58
|
+
// - unlisted: the vendor names the clients it supports and this loop is not among them; nothing on record forbids it.
|
|
59
|
+
// - against-terms: the vendor's terms forbid it, and have been enforced against accounts.
|
|
60
|
+
export interface LoopTerms {
|
|
61
|
+
readonly status: "unlisted" | "against-terms";
|
|
62
|
+
// The vendor's position in one sentence, for the hover card.
|
|
63
|
+
readonly note: string;
|
|
64
|
+
// Where the vendor says it.
|
|
65
|
+
readonly source: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// One loop a provider can run on: what that pair can do, and what the vendor says about it when there is anything to say.
|
|
69
|
+
export interface LoopOffer {
|
|
70
|
+
readonly capabilities: AgentCapabilities;
|
|
71
|
+
// Absent where the vendor sanctions this loop or says nothing about it.
|
|
72
|
+
readonly terms?: LoopTerms;
|
|
73
|
+
// What a chip calls this loop when the provider's own name would not say which program runs it: the `vendor` loop of
|
|
74
|
+
// a provider whose other loops also carry its name (Grok Build beside Grok on OpenCode). Absent: loopLabel's own.
|
|
75
|
+
readonly label?: string;
|
|
76
|
+
// The variant the provider's own account door (/accounts/{provider}) signs this loop in under, for a loop whose
|
|
77
|
+
// credential is a sign-in of its own rather than the one the provider's other loops spend: a vendor CLI's login. An
|
|
78
|
+
// account the door lists carries the same word as its `variant`, which is how a picker knows which loop it serves.
|
|
79
|
+
// Absent: the loop spends the provider's default credential.
|
|
80
|
+
readonly door?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// The loops a provider runs on. `default` is what `native` (and a turn naming no loop) resolves to, and must be one of
|
|
84
|
+
// `offered`; offering a provider a new loop is one more entry in `offered`, plus the adapter that runs it.
|
|
85
|
+
export interface ProviderLoops {
|
|
86
|
+
readonly default: AgentLoop;
|
|
87
|
+
readonly offered: Partial<Record<AgentLoop, LoopOffer>>;
|
|
48
88
|
}
|
|
49
89
|
|
|
50
90
|
export interface ProviderSpec {
|
|
@@ -63,10 +103,17 @@ export interface ProviderSpec {
|
|
|
63
103
|
readonly auth: ProviderAuth;
|
|
64
104
|
// Whether a plan-limit reading is obtainable, so a blank meter is told apart from a plan that publishes none.
|
|
65
105
|
readonly planLimits: boolean;
|
|
66
|
-
// The
|
|
67
|
-
readonly
|
|
106
|
+
// The loops it runs on; one offered loop means the loop is not a choice for it.
|
|
107
|
+
readonly loops: ProviderLoops;
|
|
68
108
|
}
|
|
69
109
|
|
|
110
|
+
// Kimi's word on the two loops it documents for an API key, reached here on the translator's sign-in.
|
|
111
|
+
const KIMI_TRANSLATED: LoopTerms = {
|
|
112
|
+
status: "unlisted",
|
|
113
|
+
note: "Kimi documents OpenCode and Codex with a Kimi Code API key. Here they reach your plan through a translator's sign-in instead, which Kimi doesn't list.",
|
|
114
|
+
source: "https://www.kimi.com/en/help/kimi-code/third-party-agents",
|
|
115
|
+
};
|
|
116
|
+
|
|
70
117
|
// satisfies checks each row's shape; as const keeps ids/auth kinds literal, so NativeProvider stays a union.
|
|
71
118
|
export const PROVIDER_SPECS = [
|
|
72
119
|
{
|
|
@@ -79,8 +126,7 @@ export const PROVIDER_SPECS = [
|
|
|
79
126
|
access: { kind: "subscription", requirement: "Claude subscription", runs: "Claude Code" },
|
|
80
127
|
auth: { kind: "oauth" },
|
|
81
128
|
planLimits: true,
|
|
82
|
-
|
|
83
|
-
runtimes: { native: CLAUDE_CODE, claudeCode: CLAUDE_CODE },
|
|
129
|
+
loops: { default: "claude-code", offered: { "claude-code": { capabilities: CLAUDE_CODE } } },
|
|
84
130
|
},
|
|
85
131
|
{
|
|
86
132
|
id: "codex",
|
|
@@ -92,7 +138,29 @@ export const PROVIDER_SPECS = [
|
|
|
92
138
|
access: { kind: "subscription", requirement: "ChatGPT subscription", runs: "Codex" },
|
|
93
139
|
auth: { kind: "translator", cliProxy: "codex" },
|
|
94
140
|
planLimits: true,
|
|
95
|
-
|
|
141
|
+
loops: {
|
|
142
|
+
default: "codex",
|
|
143
|
+
offered: {
|
|
144
|
+
codex: { capabilities: CODEX },
|
|
145
|
+
"claude-code": {
|
|
146
|
+
capabilities: CLAUDE_CODE,
|
|
147
|
+
terms: {
|
|
148
|
+
status: "unlisted",
|
|
149
|
+
note: "OpenAI lets a ChatGPT plan run in Codex and in the apps it lists for Sign in with ChatGPT (OpenCode, Pi, T3 and others). Claude Code, reached here through a translator, isn't among them.",
|
|
150
|
+
source: "https://help.openai.com/en/articles/20001542",
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
// The plan through the bundled translator's Responses surface, not OpenCode's own sign-in.
|
|
154
|
+
opencode: {
|
|
155
|
+
capabilities: OPENCODE,
|
|
156
|
+
terms: {
|
|
157
|
+
status: "unlisted",
|
|
158
|
+
note: "OpenAI lists OpenCode among the apps a ChatGPT plan may sign in to, through OpenCode's own sign-in. Here OpenCode reaches the plan through a translator instead, which OpenAI doesn't list.",
|
|
159
|
+
source: "https://help.openai.com/en/articles/20001542",
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
96
164
|
},
|
|
97
165
|
{
|
|
98
166
|
id: "grok",
|
|
@@ -105,7 +173,32 @@ export const PROVIDER_SPECS = [
|
|
|
105
173
|
// The app says grok, CLIProxyAPI says xai; Grok alone also runs natively, not just through the translator.
|
|
106
174
|
auth: { kind: "translator", cliProxy: "xai" },
|
|
107
175
|
planLimits: false,
|
|
108
|
-
|
|
176
|
+
loops: {
|
|
177
|
+
default: "opencode",
|
|
178
|
+
offered: {
|
|
179
|
+
opencode: { capabilities: OPENCODE },
|
|
180
|
+
// xAI's own CLI, signed in through its own device login (not OpenCode's), and free to run on a SuperGrok
|
|
181
|
+
// or X Premium plan: it is the client xAI ships for that subscription.
|
|
182
|
+
vendor: { capabilities: GROK_BUILD, label: "Grok Build", door: "grok-build" },
|
|
183
|
+
"claude-code": {
|
|
184
|
+
capabilities: CLAUDE_CODE,
|
|
185
|
+
terms: {
|
|
186
|
+
status: "unlisted",
|
|
187
|
+
note: "xAI turns SuperGrok sign-in on for OpenCode, Hermes, OpenClaw and Kilo Code. Claude Code, reached here through a translator, isn't among them.",
|
|
188
|
+
source: "https://x.ai/news/grok-opencode",
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
// The translator's xAI sign-in on its Responses surface, a sign-in of its own beside OpenCode's.
|
|
192
|
+
codex: {
|
|
193
|
+
capabilities: CODEX,
|
|
194
|
+
terms: {
|
|
195
|
+
status: "unlisted",
|
|
196
|
+
note: "xAI turns SuperGrok sign-in on for OpenCode, Hermes, OpenClaw and Kilo Code. Codex, reached here through a translator, isn't among them.",
|
|
197
|
+
source: "https://x.ai/news/grok-opencode",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
109
202
|
},
|
|
110
203
|
{
|
|
111
204
|
id: "kimi",
|
|
@@ -117,8 +210,19 @@ export const PROVIDER_SPECS = [
|
|
|
117
210
|
access: { kind: "subscription", requirement: "Kimi Code subscription", runs: "Kimi Code" },
|
|
118
211
|
auth: { kind: "translator", cliProxy: "kimi" },
|
|
119
212
|
planLimits: true,
|
|
120
|
-
//
|
|
121
|
-
|
|
213
|
+
// Claude Code stays the default: the translator's subscription is what most sandboxes already hold. Kimi's own CLI signs
|
|
214
|
+
// in with its own device login, Kimi's sanctioned client for the plan. Kimi documents Claude Code, OpenCode and Codex
|
|
215
|
+
// with a Kimi Code API key; Codex and OpenCode here reach the plan through the translator's sign-in instead, which
|
|
216
|
+
// Kimi doesn't list, hence their note. Claude Code predates the note and stays as it was.
|
|
217
|
+
loops: {
|
|
218
|
+
default: "claude-code",
|
|
219
|
+
offered: {
|
|
220
|
+
"claude-code": { capabilities: CLAUDE_CODE },
|
|
221
|
+
vendor: { capabilities: KIMI_CLI, label: "Kimi CLI", door: "kimi-cli" },
|
|
222
|
+
codex: { capabilities: CODEX, terms: KIMI_TRANSLATED },
|
|
223
|
+
opencode: { capabilities: OPENCODE, terms: KIMI_TRANSLATED },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
122
226
|
},
|
|
123
227
|
{
|
|
124
228
|
// Labelled for the account (Google), not the model family: this channel vends Claude and GPT-OSS beside Gemini.
|
|
@@ -132,8 +236,20 @@ export const PROVIDER_SPECS = [
|
|
|
132
236
|
// antigravity is Google's own agent product, the name CLIProxyAPI files this credential under.
|
|
133
237
|
auth: { kind: "translator", cliProxy: "antigravity" },
|
|
134
238
|
planLimits: true,
|
|
135
|
-
// The only routed provider
|
|
136
|
-
|
|
239
|
+
// The only routed provider without Claude Code: Google refuses any request announcing that loop.
|
|
240
|
+
loops: {
|
|
241
|
+
default: "opencode",
|
|
242
|
+
offered: {
|
|
243
|
+
opencode: {
|
|
244
|
+
capabilities: OPENCODE_GEMINI,
|
|
245
|
+
terms: {
|
|
246
|
+
status: "against-terms",
|
|
247
|
+
note: "Google's Antigravity terms don't allow its sign-in in third-party clients such as OpenCode, and Google has suspended accounts for it.",
|
|
248
|
+
source: "https://antigravity.google/terms/",
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
137
253
|
},
|
|
138
254
|
{
|
|
139
255
|
// Cursor's own runtime via Anysphere's SDK; labelled for the account since it vends several vendors' models.
|
|
@@ -147,8 +263,8 @@ export const PROVIDER_SPECS = [
|
|
|
147
263
|
access: { kind: "subscription", requirement: "Cursor Pro subscription", runs: "Cursor Agent" },
|
|
148
264
|
auth: { kind: "oauth" },
|
|
149
265
|
planLimits: false,
|
|
150
|
-
//
|
|
151
|
-
|
|
266
|
+
// There is no route to Cursor but its own SDK.
|
|
267
|
+
loops: { default: "vendor", offered: { vendor: { capabilities: CURSOR } } },
|
|
152
268
|
},
|
|
153
269
|
{
|
|
154
270
|
// Cognition's Devin through its own CLI (`devin acp`); labelled for the account, since it vends many vendors'
|
|
@@ -165,10 +281,11 @@ export const PROVIDER_SPECS = [
|
|
|
165
281
|
auth: { kind: "oauth" },
|
|
166
282
|
// Devin publishes its quota only on its own pages and in its CLI's interactive view, nothing a key can read.
|
|
167
283
|
planLimits: false,
|
|
168
|
-
// The CLI is the only door, so
|
|
169
|
-
|
|
284
|
+
// The CLI is the only door, so the loop is not a choice.
|
|
285
|
+
loops: { default: "vendor", offered: { vendor: { capabilities: DEVIN } } },
|
|
170
286
|
},
|
|
171
|
-
// The two minted providers need no
|
|
287
|
+
// The two minted providers need no translator hop: each has its own endpoint for the minted key. Meta's key is a Muse
|
|
288
|
+
// Code key, so its own loop is Muse Code; Z.ai's runs under Claude Code against its Anthropic Messages endpoint.
|
|
172
289
|
{
|
|
173
290
|
id: "meta",
|
|
174
291
|
label: "Meta",
|
|
@@ -177,7 +294,7 @@ export const PROVIDER_SPECS = [
|
|
|
177
294
|
destination: "Meta",
|
|
178
295
|
brand: "meta",
|
|
179
296
|
// A subscription like the rest: the device sign-in mints a plan key, and the plan is what a turn spends.
|
|
180
|
-
access: { kind: "subscription", requirement: "Muse Code subscription", runs: "Muse Spark
|
|
297
|
+
access: { kind: "subscription", requirement: "Muse Code subscription", runs: "Muse Spark in Muse Code" },
|
|
181
298
|
auth: {
|
|
182
299
|
kind: "minted",
|
|
183
300
|
// Preserve the minted variant id because stored accounts reference it.
|
|
@@ -197,7 +314,21 @@ export const PROVIDER_SPECS = [
|
|
|
197
314
|
},
|
|
198
315
|
// No quota surface a minted key can read: the row shows no meter and says so, not an empty one reading as zero.
|
|
199
316
|
planLimits: false,
|
|
200
|
-
|
|
317
|
+
// Muse Code is the use Meta's terms sanction for the key, so it says nothing; Claude Code stays on offer, quietly noted.
|
|
318
|
+
loops: {
|
|
319
|
+
default: "muse",
|
|
320
|
+
offered: {
|
|
321
|
+
muse: { capabilities: MUSE },
|
|
322
|
+
"claude-code": {
|
|
323
|
+
capabilities: CLAUDE_CODE,
|
|
324
|
+
terms: {
|
|
325
|
+
status: "against-terms",
|
|
326
|
+
note: "Meta's terms say a Muse Code subscription key is for use with Muse Code only. Here it runs under Claude Code.",
|
|
327
|
+
source: "https://dev.meta.ai/docs/muse-code/subscriptions",
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
},
|
|
201
332
|
},
|
|
202
333
|
{
|
|
203
334
|
id: "zai",
|
|
@@ -221,6 +352,8 @@ export const PROVIDER_SPECS = [
|
|
|
221
352
|
flow: "device",
|
|
222
353
|
anthropicBase: "https://api.z.ai/api/anthropic",
|
|
223
354
|
catalogBase: "https://api.z.ai/api/coding/paas/v4",
|
|
355
|
+
// Z.ai's dedicated Responses endpoint for Codex (docs.z.ai/devpack/tool/codex).
|
|
356
|
+
responsesBase: "https://api.z.ai/api/v1",
|
|
224
357
|
},
|
|
225
358
|
{
|
|
226
359
|
id: "bigmodel",
|
|
@@ -230,11 +363,18 @@ export const PROVIDER_SPECS = [
|
|
|
230
363
|
flow: "redirect",
|
|
231
364
|
anthropicBase: "https://open.bigmodel.cn/api/anthropic",
|
|
232
365
|
catalogBase: "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
366
|
+
// BigModel's equivalent (docs.bigmodel.cn/cn/coding-plan/tool/codex).
|
|
367
|
+
responsesBase: "https://open.bigmodel.cn/api/v1",
|
|
233
368
|
},
|
|
234
369
|
],
|
|
235
370
|
},
|
|
236
371
|
planLimits: false,
|
|
237
|
-
|
|
372
|
+
// The GLM Coding Plan lists Claude Code, Codex and OpenCode among its tools, each on the minted key aimed at the
|
|
373
|
+
// estate's own endpoints: Anthropic Messages, Responses and Chat Completions respectively.
|
|
374
|
+
loops: {
|
|
375
|
+
default: "claude-code",
|
|
376
|
+
offered: { "claude-code": { capabilities: CLAUDE_CODE }, codex: { capabilities: CODEX }, opencode: { capabilities: OPENCODE } },
|
|
377
|
+
},
|
|
238
378
|
},
|
|
239
379
|
] as const satisfies readonly ProviderSpec[];
|
|
240
380
|
|
|
@@ -9,7 +9,7 @@ import { contributedServerMintingKinds } from "@intentic/extension-manifest";
|
|
|
9
9
|
// - outside: the server carries content from beyond the container (a web page, a provider's verbatim sentence)
|
|
10
10
|
export type ServerProvenance = "control" | "outside";
|
|
11
11
|
|
|
12
|
-
// Every server agent/run/agent.ts
|
|
12
|
+
// Every server agent/run/agent.ts, agent/run/harness/harness-servers.ts and runtimes/daemon-tools/daemon-servers.ts mount themselves, plus the browser router's two
|
|
13
13
|
// names (web, browser) and the virtual desktop's (desktop), which a turn mounts on its lease at the daemon's MCP door
|
|
14
14
|
// (browser-tools.ts, desktop/desktop-tools.ts) and which the text scan reads from their constants. A server added anywhere else without a row here fails the conformance test in the sandbox guard package.
|
|
15
15
|
export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
|
|
@@ -23,6 +23,7 @@ export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
|
|
|
23
23
|
watch: "control", // harness: condition watches
|
|
24
24
|
deps: "control", // harness: dependency readiness
|
|
25
25
|
diagnostics: "outside", // harness: two tools relay a provider's own sentence verbatim
|
|
26
|
+
gate: "control", // daemon-servers: the policy gate a runtime's own hooks call through the door (runtimes/daemon-tools/policy-gate-server.ts)
|
|
26
27
|
web: "outside", // the turn's mounts: the anonymous browser router; the page is the internet
|
|
27
28
|
browser: "outside", // the turn's mounts: the signed-in browser router; the page is the internet
|
|
28
29
|
desktop: "outside", // the turn's mounts: the sandbox's own virtual desktop; whatever its windows show is outside content
|
|
@@ -8,8 +8,12 @@ import type { CommandSpan } from "./command-classes.js";
|
|
|
8
8
|
// working (hosts/host-restart-guard.ts), and the device agent, whose "Manage sandboxes" switch decides whether anything
|
|
9
9
|
// may do this at all (the machine's tools/shell.ts). The same verbs and the same wording, so a command and the tool
|
|
10
10
|
// that does the same job cannot drift apart.
|
|
11
|
+
//
|
|
12
|
+
// (2026-10-13) On Intentic OS the machine itself is managed the same way: `ic os update|rollback|reboot|channel`, and the
|
|
13
|
+
// `bootc upgrade|switch|rollback` under it, change what the whole box boots, and the ones that reboot it stop every
|
|
14
|
+
// sandbox on it at once. They are read here as the os_* device tools' twins, under the same switch.
|
|
11
15
|
|
|
12
|
-
/** The sandbox operations a command can name, in the words `ic sandbox` spells them. */
|
|
16
|
+
/** The sandbox operations a command can name, in the words `ic sandbox` spells them, and the OS ones in `ic os`'s. */
|
|
13
17
|
export type SandboxPowerOp =
|
|
14
18
|
| "start"
|
|
15
19
|
| "stop"
|
|
@@ -23,7 +27,12 @@ export type SandboxPowerOp =
|
|
|
23
27
|
| "dev"
|
|
24
28
|
| "resize"
|
|
25
29
|
| "restore"
|
|
26
|
-
| "connect"
|
|
30
|
+
| "connect"
|
|
31
|
+
// The machine's OS (Intentic OS), in `ic os`'s verbs; a bootc spelling reads as the same op.
|
|
32
|
+
| "os-update"
|
|
33
|
+
| "os-rollback"
|
|
34
|
+
| "os-reboot"
|
|
35
|
+
| "os-channel";
|
|
27
36
|
|
|
28
37
|
/** The owner's own word for an operation, as a card or a refusal says it ("<doing> this sandbox now?"). */
|
|
29
38
|
export const SANDBOX_POWER_DOING = {
|
|
@@ -40,17 +49,23 @@ export const SANDBOX_POWER_DOING = {
|
|
|
40
49
|
resize: "Restart with new resources",
|
|
41
50
|
restore: "Restore a backup over",
|
|
42
51
|
connect: "Reinstall",
|
|
52
|
+
// The OS ops stop a sandbox only when they reboot, which takes every sandbox on the machine with it.
|
|
53
|
+
"os-update": "Update and reboot the machine running",
|
|
54
|
+
"os-rollback": "Roll back and reboot the machine running",
|
|
55
|
+
"os-reboot": "Reboot the machine running",
|
|
56
|
+
"os-channel": "Switch images and reboot the machine running",
|
|
43
57
|
} as const satisfies Record<SandboxPowerOp, string>;
|
|
44
58
|
|
|
45
59
|
/** One command that manages a sandbox container, and what it aims at. */
|
|
46
60
|
export interface SandboxPowerCommand {
|
|
47
|
-
|
|
61
|
+
/** `ic` for `ic sandbox` and `ic os`, `bootc` for the OS's own tool under `ic os`. */
|
|
62
|
+
readonly via: "ic" | "docker" | "bootc";
|
|
48
63
|
readonly op: SandboxPowerOp;
|
|
49
64
|
/** Whether it ends the turns of a sandbox that is running; false for a start, a download, a resource ask saved for later. */
|
|
50
65
|
readonly stops: boolean;
|
|
51
66
|
/** The slugs (`ic`) or container names (`docker`) it names, as written; an expansion (`$x`, `$(…)`, `*`) stays as typed. */
|
|
52
67
|
readonly targets: readonly string[];
|
|
53
|
-
/** Names none: `ic sandbox restart` alone (the only sandbox the device runs), `remove --all`, `docker stop` fed from a pipe. */
|
|
68
|
+
/** Names none: `ic sandbox restart` alone (the only sandbox the device runs), `remove --all`, `docker stop` fed from a pipe, and every OS op, which is the whole machine's. */
|
|
54
69
|
readonly unnamed: boolean;
|
|
55
70
|
/** The fragment, so a card can point at it. */
|
|
56
71
|
readonly span: CommandSpan;
|
|
@@ -63,6 +78,10 @@ const IC_INVOCATION = /(?<![\w.$-])ic(?:\.exe)?["']?\s+sandbox\s+([a-z][a-z-]*)(
|
|
|
63
78
|
// `docker stop`, `docker container rm`, podman alike. A global option between the program and the verb
|
|
64
79
|
// (`docker -H host stop x`) is not read: the verb then follows an option, and the command is left unrecognised.
|
|
65
80
|
const DOCKER_INVOCATION = /(?<![\w.$-])(?:docker|podman)(?:\.exe)?["']?\s+(?:container\s+)?(stop|restart|rm|remove|kill)(?![\w-])/gi;
|
|
81
|
+
// `ic os <verb>` and `bootc <verb>`, the machine's OS. Only the verbs that change what it boots; `status`, `health`,
|
|
82
|
+
// `record` and `pair` read or set up and are left alone, as is a `--check` that only asks the registry.
|
|
83
|
+
const IC_OS_INVOCATION = /(?<![\w.$-])ic(?:\.exe)?["']?\s+os\s+([a-z][a-z-]*)(?![\w-])/gi;
|
|
84
|
+
const BOOTC_INVOCATION = /(?<![\w.$-])bootc["']?\s+([a-z][a-z-]*)(?![\w-])/gi;
|
|
66
85
|
|
|
67
86
|
const IC_VERBS = new Map<string, SandboxPowerOp>([
|
|
68
87
|
["start", "start"],
|
|
@@ -90,6 +109,21 @@ const DOCKER_VERBS = new Map<string, SandboxPowerOp>([
|
|
|
90
109
|
["remove", "remove"],
|
|
91
110
|
]);
|
|
92
111
|
|
|
112
|
+
const IC_OS_VERBS = new Map<string, SandboxPowerOp>([
|
|
113
|
+
["update", "os-update"],
|
|
114
|
+
["rollback", "os-rollback"],
|
|
115
|
+
["reboot", "os-reboot"],
|
|
116
|
+
["channel", "os-channel"],
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
// `bootc switch` is what `ic os channel` runs, to any image; `update` is read as `upgrade`'s other spelling.
|
|
120
|
+
const BOOTC_VERBS = new Map<string, SandboxPowerOp>([
|
|
121
|
+
["upgrade", "os-update"],
|
|
122
|
+
["update", "os-update"],
|
|
123
|
+
["switch", "os-channel"],
|
|
124
|
+
["rollback", "os-rollback"],
|
|
125
|
+
]);
|
|
126
|
+
|
|
93
127
|
// The flags of each program that take their value as the next word, so the value is not read as a slug.
|
|
94
128
|
const IC_VALUE_FLAGS: ReadonlySet<string> = new Set([
|
|
95
129
|
"--channel",
|
|
@@ -110,6 +144,7 @@ const IC_VALUE_FLAGS: ReadonlySet<string> = new Set([
|
|
|
110
144
|
"--tail",
|
|
111
145
|
]);
|
|
112
146
|
const DOCKER_VALUE_FLAGS: ReadonlySet<string> = new Set(["-t", "--time", "-s", "--signal"]);
|
|
147
|
+
const OS_VALUE_FLAGS: ReadonlySet<string> = new Set(["--wait", "--transport", "--target-imgref"]);
|
|
113
148
|
|
|
114
149
|
// The simple command that starts the text: up to the first `|`, `;`, `&` or newline outside quotes. A `&` right after
|
|
115
150
|
// `>` or `<` is a redirection (`2>&1`), which ends nothing.
|
|
@@ -194,8 +229,27 @@ const icAim = (op: SandboxPowerOp, { positionals, flags }: Operands): Aim => {
|
|
|
194
229
|
return { stops: true, targets: positionals, all };
|
|
195
230
|
};
|
|
196
231
|
|
|
232
|
+
// Whether an OS op reboots the machine now, which stops every sandbox on it; undefined for a check that only asks the
|
|
233
|
+
// registry, which manages nothing. A reboot always does; the rest stage for the next boot unless told `--apply`.
|
|
234
|
+
const osStops = (op: SandboxPowerOp, { flags }: Operands): boolean | undefined => {
|
|
235
|
+
if (op === "os-update" && flags.has("--check")) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
return op === "os-reboot" || flags.has("--apply");
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// The OS ops in `command`, through `ic os` or bootc. Each names the whole machine, so none names a target.
|
|
242
|
+
const osPowerCommands = (command: string, via: "ic" | "bootc", regions: readonly CommandSpan[]): SandboxPowerCommand[] =>
|
|
243
|
+
[...command.matchAll(via === "ic" ? IC_OS_INVOCATION : BOOTC_INVOCATION)].flatMap((invocation) => {
|
|
244
|
+
const op = (via === "ic" ? IC_OS_VERBS : BOOTC_VERBS).get((invocation[1] ?? "").toLowerCase());
|
|
245
|
+
const span = { start: invocation.index, end: invocation.index + invocation[0].length };
|
|
246
|
+
const stops = op === undefined ? undefined : osStops(op, operandsOf(wordsOf(command.slice(span.end)), OS_VALUE_FLAGS));
|
|
247
|
+
return op === undefined || stops === undefined ? [] : [{ via, op, stops, targets: [], unnamed: true, span, live: isLive(span, regions) }];
|
|
248
|
+
});
|
|
249
|
+
|
|
197
250
|
/**
|
|
198
|
-
* Every command in `command` that starts, stops or replaces a sandbox container, through `ic sandbox` or `docker
|
|
251
|
+
* Every command in `command` that starts, stops or replaces a sandbox container, through `ic sandbox` or `docker`, or
|
|
252
|
+
* changes what an Intentic OS machine boots, through `ic os` or `bootc`.
|
|
199
253
|
* A scan for the programs by name, not a shell parse: it is meant to over-include, since a caller that mistakes
|
|
200
254
|
* a mention for a command asks the owner once, and one that misses a command cuts a fleet's turns unasked.
|
|
201
255
|
*/
|
|
@@ -210,6 +264,7 @@ export const sandboxPowerCommands = (command: string): SandboxPowerCommand[] =>
|
|
|
210
264
|
found.push({ via: "ic", op, stops: aim.stops, targets: aim.targets, unnamed: aim.targets.length === 0 || aim.all, span, live: isLive(span, regions) });
|
|
211
265
|
}
|
|
212
266
|
}
|
|
267
|
+
found.push(...osPowerCommands(command, "ic", regions), ...osPowerCommands(command, "bootc", regions));
|
|
213
268
|
for (const invocation of command.matchAll(DOCKER_INVOCATION)) {
|
|
214
269
|
const op = DOCKER_VERBS.get((invocation[1] ?? "").toLowerCase());
|
|
215
270
|
if (op !== undefined) {
|
|
@@ -240,8 +295,12 @@ export const mayReachSandbox = (hit: SandboxPowerCommand, own: OwnSandbox): bool
|
|
|
240
295
|
|
|
241
296
|
/**
|
|
242
297
|
* Whether `hit` manages a sandbox that a device's "Manage sandboxes" switch covers, whichever sandbox it is: any
|
|
243
|
-
* `ic sandbox` verb here
|
|
244
|
-
* own, or its tunnel's). A docker target worked out at
|
|
298
|
+
* `ic sandbox` or `ic os` verb here and any bootc one (the OS is every sandbox's ground), and a `docker` verb aimed at a
|
|
299
|
+
* container whose name starts with `containerPrefix` (a sandbox's own, or its tunnel's). A docker target worked out at
|
|
300
|
+
* run time is not read: the device cannot know what it will be.
|
|
245
301
|
*/
|
|
246
302
|
export const managesSandbox = (hit: SandboxPowerCommand, containerPrefix: string): boolean =>
|
|
247
|
-
hit.via
|
|
303
|
+
hit.via !== "docker" || hit.targets.some((target) => target.startsWith(containerPrefix));
|
|
304
|
+
|
|
305
|
+
/** Whether `hit` acts on the machine's OS (`ic os`, `bootc`) rather than on one sandbox. */
|
|
306
|
+
export const isOsPower = (hit: Pick<SandboxPowerCommand, "op">): boolean => hit.op.startsWith("os-");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { managesSandbox, mayReachSandbox, SANDBOX_POWER_DOING, type SandboxPowerCommand, sandboxPowerCommands } from "../sandbox-power.js";
|
|
1
|
+
import { isOsPower, managesSandbox, mayReachSandbox, SANDBOX_POWER_DOING, type SandboxPowerCommand, sandboxPowerCommands } from "../sandbox-power.js";
|
|
2
2
|
|
|
3
3
|
const OWN = { slug: "work", container: "intentic-sandbox-work" };
|
|
4
4
|
const PREFIX = "intentic-sandbox-";
|
|
@@ -128,6 +128,63 @@ describe("docker", () => {
|
|
|
128
128
|
});
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
+
// On Intentic OS the machine's own OS is changed through `ic os` (and bootc under it): what reboots it stops every
|
|
132
|
+
// sandbox on it, and what only stages for the next boot stops none, like a sandbox's prepare.
|
|
133
|
+
describe("ic os and bootc", () => {
|
|
134
|
+
const WHOLE_MACHINE = { targets: [], unnamed: true };
|
|
135
|
+
|
|
136
|
+
test("reads every verb that changes what the machine boots, as the whole machine's", () => {
|
|
137
|
+
expect(first("ic os update")).toEqual({ via: "ic", op: "os-update", stops: false, ...WHOLE_MACHINE });
|
|
138
|
+
expect(first("ic os update --apply")).toEqual({ via: "ic", op: "os-update", stops: true, ...WHOLE_MACHINE });
|
|
139
|
+
expect(first("ic os rollback")).toEqual({ via: "ic", op: "os-rollback", stops: false, ...WHOLE_MACHINE });
|
|
140
|
+
expect(first("ic os rollback --apply")).toEqual({ via: "ic", op: "os-rollback", stops: true, ...WHOLE_MACHINE });
|
|
141
|
+
expect(first("ic os reboot")).toEqual({ via: "ic", op: "os-reboot", stops: true, ...WHOLE_MACHINE });
|
|
142
|
+
// The channel is the verb's operand, not a sandbox it names.
|
|
143
|
+
expect(first("ic os channel beta")).toEqual({ via: "ic", op: "os-channel", stops: false, ...WHOLE_MACHINE });
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("reads bootc's own spelling of the same ops", () => {
|
|
147
|
+
expect(first("sudo bootc upgrade")).toEqual({ via: "bootc", op: "os-update", stops: false, ...WHOLE_MACHINE });
|
|
148
|
+
expect(first("sudo -n /usr/bin/bootc upgrade --apply")).toEqual({ via: "bootc", op: "os-update", stops: true, ...WHOLE_MACHINE });
|
|
149
|
+
expect(first("bootc switch ghcr.io/intentic/os:beta")).toEqual({ via: "bootc", op: "os-channel", stops: false, ...WHOLE_MACHINE });
|
|
150
|
+
expect(first("bootc switch --apply --transport registry ghcr.io/intentic/os:beta")?.stops).toBe(true);
|
|
151
|
+
expect(first("bootc rollback")).toEqual({ via: "bootc", op: "os-rollback", stops: false, ...WHOLE_MACHINE });
|
|
152
|
+
expect(first("bootc rollback --apply")?.stops).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("leaves alone what only reads or sets up", () => {
|
|
156
|
+
for (const command of [
|
|
157
|
+
"ic os status --json",
|
|
158
|
+
"ic os update --check --json",
|
|
159
|
+
"ic os health --wait 600",
|
|
160
|
+
"ic os record",
|
|
161
|
+
"ic os pair",
|
|
162
|
+
"bootc status --json",
|
|
163
|
+
"bootc upgrade --check",
|
|
164
|
+
"magic os reboot",
|
|
165
|
+
"echo cosmic os update",
|
|
166
|
+
]) {
|
|
167
|
+
expect(sandboxPowerCommands(command), command).toEqual([]);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("a reboot may reach this sandbox and is the switch's, wherever this sandbox runs", () => {
|
|
172
|
+
const reboot = sandboxPowerCommands("ic os reboot")[0];
|
|
173
|
+
expect(reboot !== undefined && mayReachSandbox(reboot, OWN)).toBe(true);
|
|
174
|
+
expect(reboot !== undefined && managesSandbox(reboot, PREFIX)).toBe(true);
|
|
175
|
+
expect(reboot !== undefined && isOsPower(reboot)).toBe(true);
|
|
176
|
+
const staged = sandboxPowerCommands("sudo bootc upgrade")[0];
|
|
177
|
+
expect(staged !== undefined && managesSandbox(staged, PREFIX)).toBe(true);
|
|
178
|
+
expect(isOsPower({ op: "restart" })).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("is found beside a sandbox verb in the same line, in the order written, and quoted it is not live", () => {
|
|
182
|
+
expect(sandboxPowerCommands("ic sandbox stop work && ic os reboot").map((hit) => hit.op)).toEqual(["stop", "os-reboot"]);
|
|
183
|
+
expect(sandboxPowerCommands("echo 'ic os reboot'")[0]?.live).toBe(false);
|
|
184
|
+
expect(sandboxPowerCommands("ic os reboot")[0]?.span).toEqual({ start: 0, end: "ic os reboot".length });
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
131
188
|
describe("whether a command may reach this sandbox", () => {
|
|
132
189
|
const reaches = (command: string): boolean => sandboxPowerCommands(command).some((hit) => mayReachSandbox(hit, OWN));
|
|
133
190
|
|
|
@@ -178,4 +235,5 @@ test("every operation has the owner's word for it", () => {
|
|
|
178
235
|
expect(SANDBOX_POWER_DOING.restart).toBe("Restart");
|
|
179
236
|
expect(SANDBOX_POWER_DOING.resize).toBe("Restart with new resources");
|
|
180
237
|
expect(SANDBOX_POWER_DOING.rollback).toBe("Roll back");
|
|
238
|
+
expect(`${SANDBOX_POWER_DOING["os-reboot"]} this sandbox now?`).toBe("Reboot the machine running this sandbox now?");
|
|
181
239
|
});
|
|
@@ -20,6 +20,8 @@ const TURNED_AWAY: ReadonlySet<string> = new Set([
|
|
|
20
20
|
// The privacy shield found personal data in instructions a runtime loads itself, where it could not mask them.
|
|
21
21
|
"privacy-instructions",
|
|
22
22
|
"sandbox-memory-low",
|
|
23
|
+
// The conversation's own view of the workspace could not be set up in time: nothing was started in it.
|
|
24
|
+
"workspace-setup",
|
|
23
25
|
"trial-unavailable",
|
|
24
26
|
"trial-model-unavailable",
|
|
25
27
|
"trial-exhausted",
|