switchroom 0.15.0 → 0.15.2
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/dist/agent-scheduler/index.js +23 -1
- package/dist/auth-broker/index.js +43 -3
- package/dist/cli/drive-write-pretool.mjs +23 -2
- package/dist/cli/notion-write-pretool.mjs +1 -0
- package/dist/cli/switchroom.js +375 -18
- package/dist/cli/ui/index.html +67 -1
- package/dist/host-control/main.js +5 -1
- package/dist/vault/approvals/kernel-server.js +1 -0
- package/dist/vault/broker/server.js +2 -1
- package/package.json +1 -1
- package/profiles/default/CLAUDE.md.hbs +18 -0
- package/telegram-plugin/auth-snapshot-format.ts +9 -0
- package/telegram-plugin/auto-fallback-fleet.ts +59 -0
- package/telegram-plugin/dist/gateway/gateway.js +347 -21
- package/telegram-plugin/gateway/auth-broker-client.ts +2 -0
- package/telegram-plugin/gateway/auth-command.ts +35 -2
- package/telegram-plugin/gateway/gateway.ts +236 -22
- package/telegram-plugin/gateway/model-command.ts +182 -0
- package/telegram-plugin/quota-watch.ts +141 -3
- package/telegram-plugin/tests/auth-quota-util-cell.test.ts +23 -0
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +71 -0
- package/telegram-plugin/tests/model-command.test.ts +205 -0
- package/telegram-plugin/tests/quota-watch.test.ts +266 -0
- package/telegram-plugin/welcome-text.ts +7 -1
|
@@ -11348,6 +11348,7 @@ var AgentSchema = exports_external.object({
|
|
|
11348
11348
|
dangerous_mode: exports_external.boolean().optional().describe("If true, include --dangerously-skip-permissions in start.sh"),
|
|
11349
11349
|
network_isolation: NetworkIsolationSchema,
|
|
11350
11350
|
admin: exports_external.boolean().optional().describe("If true, the agent's Telegram gateway intercepts admin slash commands " + "(/agents, /logs, /restart, /delete, /update, /auth, /reconcile, etc.) " + "locally before forwarding to Claude. Commands are handled silently — " + "Claude never sees them. Requires the agent to use the switchroom-telegram " + "plugin. When false or absent, all messages pass through to Claude unchanged."),
|
|
11351
|
+
root: exports_external.boolean().optional().describe("If true, this is a ROOT-tier debugging agent: a root-privileged " + "container (runs as uid 0, mounts /var/run/docker.sock, the whole " + "~/.switchroom tree, and the host root filesystem at /host) so you " + "can DM it to debug the whole fleet — read any agent's logs, " + "docker exec into peers, edit host files — instead of SSHing into " + "the host as root. Implies admin: true (all admin slash commands). " + "Standing root power, audited via the agent's own session transcript " + "and shell history; there is no per-action approval tap. Per-agent " + "only (never set at defaults/profile layers). Grant to exactly one " + "trusted operator-private agent — it ingests other agents' output, " + "which is attacker-influenced text. See docs/root-agent.md."),
|
|
11351
11352
|
settings_raw: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Escape hatch: raw object deep-merged into the generated " + "settings.json as the final step. Use for Claude Code settings " + "keys switchroom doesn't wrap directly (e.g. effort, apiKeyHelper). " + "Power-user-only — prefer the typed fields when they exist."),
|
|
11352
11353
|
claude_md_raw: exports_external.string().optional().describe("Escape hatch: markdown text appended verbatim to CLAUDE.md on " + "initial scaffold. Not re-applied on reconcile (CLAUDE.md is " + "user-protected). Use for one-off persona tuning that isn't " + "worth a template."),
|
|
11353
11354
|
cli_args: exports_external.array(exports_external.string()).optional().describe("Escape hatch: extra arguments appended to the `exec claude` " + "invocation in start.sh. Use for Claude Code CLI flags switchroom " + "doesn't expose directly (e.g. --effort high, " + "--exclude-dynamic-system-prompt-sections)."),
|
|
@@ -13283,6 +13284,13 @@ var ProbeQuotaRequestSchema = exports_external.object({
|
|
|
13283
13284
|
accounts: exports_external.array(exports_external.string().min(1)).min(1).max(32),
|
|
13284
13285
|
timeoutMs: exports_external.number().int().positive().max(60000).optional()
|
|
13285
13286
|
});
|
|
13287
|
+
var ClaimNotificationRequestSchema = exports_external.object({
|
|
13288
|
+
v: exports_external.literal(PROTOCOL_VERSION),
|
|
13289
|
+
op: exports_external.literal("claim-notification"),
|
|
13290
|
+
id: exports_external.string().min(1),
|
|
13291
|
+
key: exports_external.string().min(1).max(512),
|
|
13292
|
+
windowMs: exports_external.number().int().positive().max(86400000)
|
|
13293
|
+
});
|
|
13286
13294
|
var RequestSchema2 = exports_external.discriminatedUnion("op", [
|
|
13287
13295
|
GetCredentialsRequestSchema,
|
|
13288
13296
|
ListStateRequestSchema,
|
|
@@ -13294,7 +13302,8 @@ var RequestSchema2 = exports_external.discriminatedUnion("op", [
|
|
|
13294
13302
|
SetOverrideRequestSchema,
|
|
13295
13303
|
ListGoogleAccountsRequestSchema,
|
|
13296
13304
|
ListMicrosoftAccountsRequestSchema,
|
|
13297
|
-
ProbeQuotaRequestSchema
|
|
13305
|
+
ProbeQuotaRequestSchema,
|
|
13306
|
+
ClaimNotificationRequestSchema
|
|
13298
13307
|
]);
|
|
13299
13308
|
var GetCredentialsDataSchema = exports_external.object({
|
|
13300
13309
|
account: exports_external.string(),
|
|
@@ -13350,6 +13359,9 @@ var SetOverrideDataSchema = exports_external.object({
|
|
|
13350
13359
|
agent: exports_external.string(),
|
|
13351
13360
|
account: exports_external.string().nullable()
|
|
13352
13361
|
});
|
|
13362
|
+
var ClaimNotificationDataSchema = exports_external.object({
|
|
13363
|
+
granted: exports_external.boolean()
|
|
13364
|
+
});
|
|
13353
13365
|
var GoogleAccountStateSchema = exports_external.object({
|
|
13354
13366
|
account: exports_external.string(),
|
|
13355
13367
|
expiresAt: exports_external.number(),
|
|
@@ -13556,6 +13568,16 @@ class AuthBrokerClient {
|
|
|
13556
13568
|
const data = await this.send(req);
|
|
13557
13569
|
return data;
|
|
13558
13570
|
}
|
|
13571
|
+
async claimNotification(key, windowMs) {
|
|
13572
|
+
const data = await this.send({
|
|
13573
|
+
v: PROTOCOL_VERSION,
|
|
13574
|
+
id: randomUUID(),
|
|
13575
|
+
op: "claim-notification",
|
|
13576
|
+
key,
|
|
13577
|
+
windowMs
|
|
13578
|
+
});
|
|
13579
|
+
return data;
|
|
13580
|
+
}
|
|
13559
13581
|
async refreshAccount(account) {
|
|
13560
13582
|
const data = await this.send({
|
|
13561
13583
|
v: PROTOCOL_VERSION,
|
|
@@ -11348,6 +11348,7 @@ var AgentSchema = exports_external.object({
|
|
|
11348
11348
|
dangerous_mode: exports_external.boolean().optional().describe("If true, include --dangerously-skip-permissions in start.sh"),
|
|
11349
11349
|
network_isolation: NetworkIsolationSchema,
|
|
11350
11350
|
admin: exports_external.boolean().optional().describe("If true, the agent's Telegram gateway intercepts admin slash commands " + "(/agents, /logs, /restart, /delete, /update, /auth, /reconcile, etc.) " + "locally before forwarding to Claude. Commands are handled silently — " + "Claude never sees them. Requires the agent to use the switchroom-telegram " + "plugin. When false or absent, all messages pass through to Claude unchanged."),
|
|
11351
|
+
root: exports_external.boolean().optional().describe("If true, this is a ROOT-tier debugging agent: a root-privileged " + "container (runs as uid 0, mounts /var/run/docker.sock, the whole " + "~/.switchroom tree, and the host root filesystem at /host) so you " + "can DM it to debug the whole fleet — read any agent's logs, " + "docker exec into peers, edit host files — instead of SSHing into " + "the host as root. Implies admin: true (all admin slash commands). " + "Standing root power, audited via the agent's own session transcript " + "and shell history; there is no per-action approval tap. Per-agent " + "only (never set at defaults/profile layers). Grant to exactly one " + "trusted operator-private agent — it ingests other agents' output, " + "which is attacker-influenced text. See docs/root-agent.md."),
|
|
11351
11352
|
settings_raw: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Escape hatch: raw object deep-merged into the generated " + "settings.json as the final step. Use for Claude Code settings " + "keys switchroom doesn't wrap directly (e.g. effort, apiKeyHelper). " + "Power-user-only — prefer the typed fields when they exist."),
|
|
11352
11353
|
claude_md_raw: exports_external.string().optional().describe("Escape hatch: markdown text appended verbatim to CLAUDE.md on " + "initial scaffold. Not re-applied on reconcile (CLAUDE.md is " + "user-protected). Use for one-off persona tuning that isn't " + "worth a template."),
|
|
11353
11354
|
cli_args: exports_external.array(exports_external.string()).optional().describe("Escape hatch: extra arguments appended to the `exec claude` " + "invocation in start.sh. Use for Claude Code CLI flags switchroom " + "doesn't expose directly (e.g. --effort high, " + "--exclude-dynamic-system-prompt-sections)."),
|
|
@@ -13367,6 +13368,13 @@ var ProbeQuotaRequestSchema = exports_external.object({
|
|
|
13367
13368
|
accounts: exports_external.array(exports_external.string().min(1)).min(1).max(32),
|
|
13368
13369
|
timeoutMs: exports_external.number().int().positive().max(60000).optional()
|
|
13369
13370
|
});
|
|
13371
|
+
var ClaimNotificationRequestSchema = exports_external.object({
|
|
13372
|
+
v: exports_external.literal(PROTOCOL_VERSION),
|
|
13373
|
+
op: exports_external.literal("claim-notification"),
|
|
13374
|
+
id: exports_external.string().min(1),
|
|
13375
|
+
key: exports_external.string().min(1).max(512),
|
|
13376
|
+
windowMs: exports_external.number().int().positive().max(86400000)
|
|
13377
|
+
});
|
|
13370
13378
|
var RequestSchema = exports_external.discriminatedUnion("op", [
|
|
13371
13379
|
GetCredentialsRequestSchema,
|
|
13372
13380
|
ListStateRequestSchema,
|
|
@@ -13378,7 +13386,8 @@ var RequestSchema = exports_external.discriminatedUnion("op", [
|
|
|
13378
13386
|
SetOverrideRequestSchema,
|
|
13379
13387
|
ListGoogleAccountsRequestSchema,
|
|
13380
13388
|
ListMicrosoftAccountsRequestSchema,
|
|
13381
|
-
ProbeQuotaRequestSchema
|
|
13389
|
+
ProbeQuotaRequestSchema,
|
|
13390
|
+
ClaimNotificationRequestSchema
|
|
13382
13391
|
]);
|
|
13383
13392
|
var GetCredentialsDataSchema = exports_external.object({
|
|
13384
13393
|
account: exports_external.string(),
|
|
@@ -13434,6 +13443,9 @@ var SetOverrideDataSchema = exports_external.object({
|
|
|
13434
13443
|
agent: exports_external.string(),
|
|
13435
13444
|
account: exports_external.string().nullable()
|
|
13436
13445
|
});
|
|
13446
|
+
var ClaimNotificationDataSchema = exports_external.object({
|
|
13447
|
+
granted: exports_external.boolean()
|
|
13448
|
+
});
|
|
13437
13449
|
var GoogleAccountStateSchema = exports_external.object({
|
|
13438
13450
|
account: exports_external.string(),
|
|
13439
13451
|
expiresAt: exports_external.number(),
|
|
@@ -13520,6 +13532,7 @@ var MARK_EXHAUSTED_DEFAULT_MS = 5 * 60 * 60 * 1000;
|
|
|
13520
13532
|
var AUDIT_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
13521
13533
|
var AUDIT_KEEP = 5;
|
|
13522
13534
|
var AUDIT_LINE_MAX = 4000;
|
|
13535
|
+
var NOTIFICATION_CLAIM_MAX_AGE_MS = 86400000;
|
|
13523
13536
|
function sha256Hex(content) {
|
|
13524
13537
|
return createHash2("sha256").update(content).digest("hex");
|
|
13525
13538
|
}
|
|
@@ -13546,7 +13559,10 @@ function enrichMirrorContent(sourceJson) {
|
|
|
13546
13559
|
function configToShape(cfg) {
|
|
13547
13560
|
const auth = cfg.auth ?? {};
|
|
13548
13561
|
const agentsMap = cfg.agents ?? {};
|
|
13549
|
-
const adminAgents = Object.entries(agentsMap).filter(([, a]) =>
|
|
13562
|
+
const adminAgents = Object.entries(agentsMap).filter(([, a]) => {
|
|
13563
|
+
const cfg2 = a;
|
|
13564
|
+
return cfg2.admin === true || cfg2.root === true;
|
|
13565
|
+
}).map(([name]) => name);
|
|
13550
13566
|
return {
|
|
13551
13567
|
agents: Object.keys(agentsMap),
|
|
13552
13568
|
consumers: (auth.consumers ?? []).map((c) => c.name),
|
|
@@ -13573,6 +13589,7 @@ class AuthBroker {
|
|
|
13573
13589
|
lastQuotaCache = {};
|
|
13574
13590
|
shaIndex = {};
|
|
13575
13591
|
thresholdViolations = {};
|
|
13592
|
+
notificationClaims = {};
|
|
13576
13593
|
lastWrittenExpiresAt = new Map;
|
|
13577
13594
|
refreshInFlight = new Set;
|
|
13578
13595
|
consumerLastSeen = {};
|
|
@@ -13761,7 +13778,8 @@ class AuthBroker {
|
|
|
13761
13778
|
}
|
|
13762
13779
|
const sockPath = this.agentSocketPath(agentName);
|
|
13763
13780
|
const uid = allocateAgentUid(agentName);
|
|
13764
|
-
const
|
|
13781
|
+
const agentCfg = this.config.agents?.[agentName];
|
|
13782
|
+
const adminFlag = agentCfg?.admin === true || agentCfg?.root === true;
|
|
13765
13783
|
await this.bindListener(sockPath, uid, 432, {
|
|
13766
13784
|
kind: "agent",
|
|
13767
13785
|
name: agentName,
|
|
@@ -13971,6 +13989,9 @@ class AuthBroker {
|
|
|
13971
13989
|
case "probe-quota":
|
|
13972
13990
|
await this.opProbeQuota(socket, reqId, identity2, req.accounts, req.timeoutMs);
|
|
13973
13991
|
break;
|
|
13992
|
+
case "claim-notification":
|
|
13993
|
+
this.opClaimNotification(socket, reqId, identity2, req.key, req.windowMs);
|
|
13994
|
+
break;
|
|
13974
13995
|
}
|
|
13975
13996
|
} catch (err) {
|
|
13976
13997
|
socket.write(encodeError(reqId, "INTERNAL", err.message));
|
|
@@ -14211,6 +14232,21 @@ class AuthBroker {
|
|
|
14211
14232
|
this.audit({ op: "mark-exhausted", identity: identity2, account, ok: true });
|
|
14212
14233
|
socket.write(encodeSuccess(id, { account, rolled, rolledTo }));
|
|
14213
14234
|
}
|
|
14235
|
+
opClaimNotification(socket, id, identity2, key, windowMs) {
|
|
14236
|
+
const now = this.now();
|
|
14237
|
+
const prev = this.notificationClaims[key];
|
|
14238
|
+
const granted = prev === undefined || now - prev >= windowMs;
|
|
14239
|
+
if (granted) {
|
|
14240
|
+
this.notificationClaims[key] = now;
|
|
14241
|
+
for (const [k, ts] of Object.entries(this.notificationClaims)) {
|
|
14242
|
+
if (now - ts > NOTIFICATION_CLAIM_MAX_AGE_MS)
|
|
14243
|
+
delete this.notificationClaims[k];
|
|
14244
|
+
}
|
|
14245
|
+
this.persistNotificationClaims();
|
|
14246
|
+
this.audit({ op: "claim-notification", identity: identity2, account: key, ok: true });
|
|
14247
|
+
}
|
|
14248
|
+
socket.write(encodeSuccess(id, { granted }));
|
|
14249
|
+
}
|
|
14214
14250
|
async opRefreshAccount(socket, id, identity2, account) {
|
|
14215
14251
|
if (!this.isAdmin(identity2)) {
|
|
14216
14252
|
this.audit({ op: "refresh-account", identity: identity2, account, ok: false, error: "FORBIDDEN" });
|
|
@@ -14813,6 +14849,7 @@ class AuthBroker {
|
|
|
14813
14849
|
this.quota = this.readJson("quota.json") ?? {};
|
|
14814
14850
|
this.shaIndex = this.readJson("sha-index.json") ?? {};
|
|
14815
14851
|
this.thresholdViolations = this.readJson("threshold-violations.json") ?? {};
|
|
14852
|
+
this.notificationClaims = this.readJson("notification-claims.json") ?? {};
|
|
14816
14853
|
}
|
|
14817
14854
|
readJson(name) {
|
|
14818
14855
|
const p = join4(this.stateDir, name);
|
|
@@ -14827,6 +14864,9 @@ class AuthBroker {
|
|
|
14827
14864
|
persistQuota() {
|
|
14828
14865
|
atomicWriteJsonSync(join4(this.stateDir, "quota.json"), this.quota, 384);
|
|
14829
14866
|
}
|
|
14867
|
+
persistNotificationClaims() {
|
|
14868
|
+
atomicWriteJsonSync(join4(this.stateDir, "notification-claims.json"), this.notificationClaims, 384);
|
|
14869
|
+
}
|
|
14830
14870
|
persistShaIndex() {
|
|
14831
14871
|
atomicWriteJsonSync(join4(this.stateDir, "sha-index.json"), this.shaIndex, 384);
|
|
14832
14872
|
}
|
|
@@ -4000,7 +4000,7 @@ function decodeResponse(line) {
|
|
|
4000
4000
|
}
|
|
4001
4001
|
return ResponseSchema.parse(parsed);
|
|
4002
4002
|
}
|
|
4003
|
-
var MAX_FRAME_BYTES, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, RequestSchema, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema, ResponseSchema;
|
|
4003
|
+
var MAX_FRAME_BYTES, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, ClaimNotificationRequestSchema, RequestSchema, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, ClaimNotificationDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema, ResponseSchema;
|
|
4004
4004
|
var init_protocol = __esm(() => {
|
|
4005
4005
|
init_zod();
|
|
4006
4006
|
MAX_FRAME_BYTES = 64 * 1024;
|
|
@@ -4116,6 +4116,13 @@ var init_protocol = __esm(() => {
|
|
|
4116
4116
|
accounts: exports_external.array(exports_external.string().min(1)).min(1).max(32),
|
|
4117
4117
|
timeoutMs: exports_external.number().int().positive().max(60000).optional()
|
|
4118
4118
|
});
|
|
4119
|
+
ClaimNotificationRequestSchema = exports_external.object({
|
|
4120
|
+
v: exports_external.literal(PROTOCOL_VERSION),
|
|
4121
|
+
op: exports_external.literal("claim-notification"),
|
|
4122
|
+
id: exports_external.string().min(1),
|
|
4123
|
+
key: exports_external.string().min(1).max(512),
|
|
4124
|
+
windowMs: exports_external.number().int().positive().max(86400000)
|
|
4125
|
+
});
|
|
4119
4126
|
RequestSchema = exports_external.discriminatedUnion("op", [
|
|
4120
4127
|
GetCredentialsRequestSchema,
|
|
4121
4128
|
ListStateRequestSchema,
|
|
@@ -4127,7 +4134,8 @@ var init_protocol = __esm(() => {
|
|
|
4127
4134
|
SetOverrideRequestSchema,
|
|
4128
4135
|
ListGoogleAccountsRequestSchema,
|
|
4129
4136
|
ListMicrosoftAccountsRequestSchema,
|
|
4130
|
-
ProbeQuotaRequestSchema
|
|
4137
|
+
ProbeQuotaRequestSchema,
|
|
4138
|
+
ClaimNotificationRequestSchema
|
|
4131
4139
|
]);
|
|
4132
4140
|
GetCredentialsDataSchema = exports_external.object({
|
|
4133
4141
|
account: exports_external.string(),
|
|
@@ -4183,6 +4191,9 @@ var init_protocol = __esm(() => {
|
|
|
4183
4191
|
agent: exports_external.string(),
|
|
4184
4192
|
account: exports_external.string().nullable()
|
|
4185
4193
|
});
|
|
4194
|
+
ClaimNotificationDataSchema = exports_external.object({
|
|
4195
|
+
granted: exports_external.boolean()
|
|
4196
|
+
});
|
|
4186
4197
|
GoogleAccountStateSchema = exports_external.object({
|
|
4187
4198
|
account: exports_external.string(),
|
|
4188
4199
|
expiresAt: exports_external.number(),
|
|
@@ -4364,6 +4375,16 @@ class AuthBrokerClient {
|
|
|
4364
4375
|
const data = await this.send(req);
|
|
4365
4376
|
return data;
|
|
4366
4377
|
}
|
|
4378
|
+
async claimNotification(key, windowMs) {
|
|
4379
|
+
const data = await this.send({
|
|
4380
|
+
v: PROTOCOL_VERSION,
|
|
4381
|
+
id: randomUUID(),
|
|
4382
|
+
op: "claim-notification",
|
|
4383
|
+
key,
|
|
4384
|
+
windowMs
|
|
4385
|
+
});
|
|
4386
|
+
return data;
|
|
4387
|
+
}
|
|
4367
4388
|
async refreshAccount(account) {
|
|
4368
4389
|
const data = await this.send({
|
|
4369
4390
|
v: PROTOCOL_VERSION,
|
|
@@ -12096,6 +12096,7 @@ var AgentSchema = exports_external.object({
|
|
|
12096
12096
|
dangerous_mode: exports_external.boolean().optional().describe("If true, include --dangerously-skip-permissions in start.sh"),
|
|
12097
12097
|
network_isolation: NetworkIsolationSchema,
|
|
12098
12098
|
admin: exports_external.boolean().optional().describe("If true, the agent's Telegram gateway intercepts admin slash commands " + "(/agents, /logs, /restart, /delete, /update, /auth, /reconcile, etc.) " + "locally before forwarding to Claude. Commands are handled silently \u2014 " + "Claude never sees them. Requires the agent to use the switchroom-telegram " + "plugin. When false or absent, all messages pass through to Claude unchanged."),
|
|
12099
|
+
root: exports_external.boolean().optional().describe("If true, this is a ROOT-tier debugging agent: a root-privileged " + "container (runs as uid 0, mounts /var/run/docker.sock, the whole " + "~/.switchroom tree, and the host root filesystem at /host) so you " + "can DM it to debug the whole fleet \u2014 read any agent's logs, " + "docker exec into peers, edit host files \u2014 instead of SSHing into " + "the host as root. Implies admin: true (all admin slash commands). " + "Standing root power, audited via the agent's own session transcript " + "and shell history; there is no per-action approval tap. Per-agent " + "only (never set at defaults/profile layers). Grant to exactly one " + "trusted operator-private agent \u2014 it ingests other agents' output, " + "which is attacker-influenced text. See docs/root-agent.md."),
|
|
12099
12100
|
settings_raw: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Escape hatch: raw object deep-merged into the generated " + "settings.json as the final step. Use for Claude Code settings " + "keys switchroom doesn't wrap directly (e.g. effort, apiKeyHelper). " + "Power-user-only \u2014 prefer the typed fields when they exist."),
|
|
12100
12101
|
claude_md_raw: exports_external.string().optional().describe("Escape hatch: markdown text appended verbatim to CLAUDE.md on " + "initial scaffold. Not re-applied on reconcile (CLAUDE.md is " + "user-protected). Use for one-off persona tuning that isn't " + "worth a template."),
|
|
12101
12102
|
cli_args: exports_external.array(exports_external.string()).optional().describe("Escape hatch: extra arguments appended to the `exec claude` " + "invocation in start.sh. Use for Claude Code CLI flags switchroom " + "doesn't expose directly (e.g. --effort high, " + "--exclude-dynamic-system-prompt-sections)."),
|