switchroom 0.14.11 → 0.14.12
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 +4 -0
- package/dist/auth-broker/index.js +4 -0
- package/dist/cli/notion-write-pretool.mjs +4 -0
- package/dist/cli/switchroom.js +244 -3
- package/dist/host-control/main.js +4 -0
- package/dist/vault/approvals/kernel-server.js +5 -1
- package/dist/vault/broker/server.js +5 -1
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +10 -6
|
@@ -11406,6 +11406,9 @@ var HostControlConfigSchema = exports_external.object({
|
|
|
11406
11406
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
11407
11407
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
11408
11408
|
});
|
|
11409
|
+
var WebServiceConfigSchema = exports_external.object({
|
|
11410
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false — existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
11411
|
+
});
|
|
11409
11412
|
var HostdConfigSchema = exports_external.object({
|
|
11410
11413
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11411
11414
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -11439,6 +11442,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
11439
11442
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11440
11443
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11441
11444
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11445
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container — then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
11442
11446
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11443
11447
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11444
11448
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -11406,6 +11406,9 @@ var HostControlConfigSchema = exports_external.object({
|
|
|
11406
11406
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
11407
11407
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
11408
11408
|
});
|
|
11409
|
+
var WebServiceConfigSchema = exports_external.object({
|
|
11410
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false — existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
11411
|
+
});
|
|
11409
11412
|
var HostdConfigSchema = exports_external.object({
|
|
11410
11413
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11411
11414
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -11439,6 +11442,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
11439
11442
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11440
11443
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11441
11444
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11445
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container — then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
11442
11446
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11443
11447
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11444
11448
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -12153,6 +12153,9 @@ var HostControlConfigSchema = exports_external.object({
|
|
|
12153
12153
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip \u2014 the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` \u2014 " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C \u00a75.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
12154
12154
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
12155
12155
|
});
|
|
12156
|
+
var WebServiceConfigSchema = exports_external.object({
|
|
12157
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false \u2014 existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
12158
|
+
});
|
|
12156
12159
|
var HostdConfigSchema = exports_external.object({
|
|
12157
12160
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit \u00a73). Default false \u2014 the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
12158
12161
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit \u00a75). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -12186,6 +12189,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
12186
12189
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
12187
12190
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
12188
12191
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a \u2014 disabled by default)."),
|
|
12192
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container \u2014 then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
12189
12193
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
12190
12194
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
12191
12195
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13520,7 +13520,7 @@ var init_zod = __esm(() => {
|
|
|
13520
13520
|
});
|
|
13521
13521
|
|
|
13522
13522
|
// src/config/schema.ts
|
|
13523
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
13523
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
13524
13524
|
var init_schema = __esm(() => {
|
|
13525
13525
|
init_zod();
|
|
13526
13526
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -13970,6 +13970,9 @@ var init_schema = __esm(() => {
|
|
|
13970
13970
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip \u2014 the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` \u2014 " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C \u00a75.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
13971
13971
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
13972
13972
|
});
|
|
13973
|
+
WebServiceConfigSchema = exports_external.object({
|
|
13974
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false \u2014 existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
13975
|
+
});
|
|
13973
13976
|
HostdConfigSchema = exports_external.object({
|
|
13974
13977
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit \u00a73). Default false \u2014 the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
13975
13978
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit \u00a75). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -14003,6 +14006,7 @@ var init_schema = __esm(() => {
|
|
|
14003
14006
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
14004
14007
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
14005
14008
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a \u2014 disabled by default)."),
|
|
14009
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container \u2014 then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
14006
14010
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
14007
14011
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
14008
14012
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -49409,8 +49413,8 @@ var {
|
|
|
49409
49413
|
} = import__.default;
|
|
49410
49414
|
|
|
49411
49415
|
// src/build-info.ts
|
|
49412
|
-
var VERSION = "0.14.
|
|
49413
|
-
var COMMIT_SHA = "
|
|
49416
|
+
var VERSION = "0.14.12";
|
|
49417
|
+
var COMMIT_SHA = "a6cc0835";
|
|
49414
49418
|
|
|
49415
49419
|
// src/cli/agent.ts
|
|
49416
49420
|
init_source();
|
|
@@ -73207,6 +73211,26 @@ function planUpdate(opts) {
|
|
|
73207
73211
|
throw new Error("switchroom hostd install failed");
|
|
73208
73212
|
}
|
|
73209
73213
|
});
|
|
73214
|
+
let webServiceManaged;
|
|
73215
|
+
if (typeof opts.webServiceManaged === "boolean") {
|
|
73216
|
+
webServiceManaged = opts.webServiceManaged;
|
|
73217
|
+
} else {
|
|
73218
|
+
try {
|
|
73219
|
+
webServiceManaged = loadConfig().web_service?.managed === true;
|
|
73220
|
+
} catch {
|
|
73221
|
+
webServiceManaged = false;
|
|
73222
|
+
}
|
|
73223
|
+
}
|
|
73224
|
+
steps.push({
|
|
73225
|
+
name: "refresh-web",
|
|
73226
|
+
description: "switchroom webd install \u2014 pull latest web-service image + recreate the dashboard/webhook container (separate compose project)",
|
|
73227
|
+
skipReason: !webServiceManaged ? "web_service.managed is not true \u2014 web container not in use (legacy systemd unit)" : opts.skipImages ? "--skip-images flag set" : undefined,
|
|
73228
|
+
run: () => {
|
|
73229
|
+
const r = runner(process.execPath, [scriptPath, "webd", "install"]);
|
|
73230
|
+
if (r.status !== 0)
|
|
73231
|
+
throw new Error("switchroom webd install failed");
|
|
73232
|
+
}
|
|
73233
|
+
});
|
|
73210
73234
|
steps.push({
|
|
73211
73235
|
name: "sync-bundled-skills",
|
|
73212
73236
|
description: "Sync shipped skills/ to ~/.switchroom/skills/_bundled/ (host-stable pool dir).",
|
|
@@ -82285,6 +82309,222 @@ The log is created when hostd handles its first privileged-verb request.`));
|
|
|
82285
82309
|
});
|
|
82286
82310
|
}
|
|
82287
82311
|
|
|
82312
|
+
// src/cli/webd.ts
|
|
82313
|
+
init_source();
|
|
82314
|
+
init_helpers();
|
|
82315
|
+
import { existsSync as existsSync84, mkdirSync as mkdirSync47, writeFileSync as writeFileSync40, copyFileSync as copyFileSync13 } from "node:fs";
|
|
82316
|
+
import { homedir as homedir47 } from "node:os";
|
|
82317
|
+
import { join as join80 } from "node:path";
|
|
82318
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
82319
|
+
var DEFAULT_IMAGE_TAG2 = "latest";
|
|
82320
|
+
var WEB_COMPOSE_PROJECT = "switchroom-web";
|
|
82321
|
+
function renderWebComposeFile(opts) {
|
|
82322
|
+
const { hostHome, imageTag, operatorUid } = opts;
|
|
82323
|
+
return `# AUTO-GENERATED by \`switchroom webd install\` \u2014 do not hand-edit.
|
|
82324
|
+
# Edits land at \`switchroom webd install\` time; backed up to
|
|
82325
|
+
# docker-compose.yml.bak-<ts> on overwrite.
|
|
82326
|
+
#
|
|
82327
|
+
# Separate compose project (\`switchroom-web\`) from the agent fleet
|
|
82328
|
+
# (\`switchroom\`) so \`compose up -d --remove-orphans\` against the fleet
|
|
82329
|
+
# cannot recreate this container mid-request. Same isolation contract
|
|
82330
|
+
# as switchroom-hostd.
|
|
82331
|
+
|
|
82332
|
+
services:
|
|
82333
|
+
web:
|
|
82334
|
+
image: ghcr.io/switchroom/switchroom-web:${imageTag}
|
|
82335
|
+
container_name: switchroom-web
|
|
82336
|
+
restart: unless-stopped
|
|
82337
|
+
# The server MUST own host loopback 127.0.0.1:8080 \u2014 the cloudflared
|
|
82338
|
+
# tunnel (GitHub webhooks) and \`tailscale serve\` (dashboard) both
|
|
82339
|
+
# reach it there, and the dashboard CSRF gate trusts the
|
|
82340
|
+
# Tailscale-User-Login header only when the request arrives on
|
|
82341
|
+
# loopback (PR #1380). Host networking makes the container's
|
|
82342
|
+
# 127.0.0.1 the host loopback, so both keep working unchanged.
|
|
82343
|
+
network_mode: host
|
|
82344
|
+
# The webhook.sock forward is peercred-gated by each agent's gateway
|
|
82345
|
+
# to {agent uid, SWITCHROOM_WEBHOOK_RECEIVER_UID = operator uid}.
|
|
82346
|
+
# Run as any other uid \u2192 every forward is 503'd. Operator uid also
|
|
82347
|
+
# owns ~/.switchroom so config/secret reads work.
|
|
82348
|
+
user: "${operatorUid}:${operatorUid}"
|
|
82349
|
+
# tini (image ENTRYPOINT) forwards SIGTERM to the bun process on
|
|
82350
|
+
# \`docker stop\`; Bun.serve shuts its listener within the grace
|
|
82351
|
+
# window. 15s mirrors hostd.
|
|
82352
|
+
stop_grace_period: 15s
|
|
82353
|
+
cap_drop:
|
|
82354
|
+
- ALL
|
|
82355
|
+
# Deliberately NO cap_add \u2014 the web server never chowns sockets or
|
|
82356
|
+
# shells out to docker. Minimal surface for the one internet-facing
|
|
82357
|
+
# component.
|
|
82358
|
+
security_opt:
|
|
82359
|
+
- no-new-privileges:true
|
|
82360
|
+
volumes:
|
|
82361
|
+
# The receiver reads operator-owned files under ~/.switchroom:
|
|
82362
|
+
# - webhook-secrets.json (per-source HMAC secrets)
|
|
82363
|
+
# - webhook-edge-secret (Cloudflare edge lock, Phase 2)
|
|
82364
|
+
# - web-token (dashboard auth)
|
|
82365
|
+
# and forwards verified events to per-agent webhook.sock at
|
|
82366
|
+
# ~/.switchroom/agents/<agent>/telegram/webhook.sock
|
|
82367
|
+
# so it needs the whole tree read-write (the sock connect is a
|
|
82368
|
+
# write-side operation on the agent dir).
|
|
82369
|
+
- ${hostHome}/.switchroom:/host-home/.switchroom:rw
|
|
82370
|
+
# ~/.switchroom/switchroom.yaml is a symlink on many operator
|
|
82371
|
+
# setups (into a separate config repo). Mounting the file directly
|
|
82372
|
+
# forces docker to follow the symlink at mount time and bind the
|
|
82373
|
+
# underlying file. The dashboard only READS the config, so :ro.
|
|
82374
|
+
# Mirrors how the agent + hostd containers expose the config at
|
|
82375
|
+
# /state/config/switchroom.yaml.
|
|
82376
|
+
- ${hostHome}/.switchroom/switchroom.yaml:/state/config/switchroom.yaml:ro
|
|
82377
|
+
# No docker socket is mounted \u2014 the web server never touches docker.
|
|
82378
|
+
environment:
|
|
82379
|
+
# The CLI resolves homedir() for ~/.switchroom paths; pin it to
|
|
82380
|
+
# /host-home (bind-mounted to the operator's home) so the paths
|
|
82381
|
+
# the server reads/writes match the host paths the agent fleet
|
|
82382
|
+
# binds (~/.switchroom/agents/<agent>/telegram/webhook.sock, \u2026).
|
|
82383
|
+
HOME: /host-home
|
|
82384
|
+
# Read the same config the agent fleet's compose generator did.
|
|
82385
|
+
SWITCHROOM_CONFIG: /state/config/switchroom.yaml
|
|
82386
|
+
# PATH must include /usr/local/bin for the switchroom shim.
|
|
82387
|
+
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
82388
|
+
# network_mode: host means no custom network is attached; the
|
|
82389
|
+
# container shares the host network namespace directly.
|
|
82390
|
+
|
|
82391
|
+
# Healthcheck deferred \u2014 the server has no /healthz endpoint yet and a
|
|
82392
|
+
# probe that hits the dashboard route would need the web-token. For now,
|
|
82393
|
+
# \`switchroom webd status\` is the operator surface and the server's
|
|
82394
|
+
# stderr lands in \`docker logs switchroom-web\`.
|
|
82395
|
+
`;
|
|
82396
|
+
}
|
|
82397
|
+
function webdDir() {
|
|
82398
|
+
return join80(homedir47(), ".switchroom", "web");
|
|
82399
|
+
}
|
|
82400
|
+
function webdComposePath() {
|
|
82401
|
+
return join80(webdDir(), "docker-compose.yml");
|
|
82402
|
+
}
|
|
82403
|
+
function backupExistingCompose2() {
|
|
82404
|
+
const p = webdComposePath();
|
|
82405
|
+
if (!existsSync84(p))
|
|
82406
|
+
return null;
|
|
82407
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
82408
|
+
const bak = `${p}.bak-${ts}`;
|
|
82409
|
+
copyFileSync13(p, bak);
|
|
82410
|
+
return bak;
|
|
82411
|
+
}
|
|
82412
|
+
function runDocker2(args) {
|
|
82413
|
+
const r = spawnSync14("docker", args, { encoding: "utf8" });
|
|
82414
|
+
return {
|
|
82415
|
+
ok: r.status === 0,
|
|
82416
|
+
stdout: r.stdout ?? "",
|
|
82417
|
+
stderr: r.stderr ?? ""
|
|
82418
|
+
};
|
|
82419
|
+
}
|
|
82420
|
+
async function doInstall2(opts) {
|
|
82421
|
+
const operatorUid = resolveOperatorUid();
|
|
82422
|
+
if (operatorUid === undefined) {
|
|
82423
|
+
console.error(source_default.red(`Could not resolve the operator uid (no SUDO_UID and getuid() is 0 or unavailable).
|
|
82424
|
+
` + `The web container must run as the operator uid so its webhook forwards pass
|
|
82425
|
+
` + "each agent gateway's peercred ACL. Run `switchroom webd install` as the\n" + "operator user (not root), or under `sudo` from the operator's shell."));
|
|
82426
|
+
process.exit(1);
|
|
82427
|
+
}
|
|
82428
|
+
const dir = webdDir();
|
|
82429
|
+
const composePath = webdComposePath();
|
|
82430
|
+
mkdirSync47(dir, { recursive: true });
|
|
82431
|
+
const yaml = renderWebComposeFile({
|
|
82432
|
+
hostHome: homedir47(),
|
|
82433
|
+
imageTag: opts.tag ?? DEFAULT_IMAGE_TAG2,
|
|
82434
|
+
operatorUid
|
|
82435
|
+
});
|
|
82436
|
+
if (opts.dryRun) {
|
|
82437
|
+
console.log(source_default.dim(`# Would write: ${composePath}`));
|
|
82438
|
+
console.log(yaml);
|
|
82439
|
+
console.log(source_default.dim(`# Would run: docker compose -p ${WEB_COMPOSE_PROJECT} -f ${composePath} up -d`));
|
|
82440
|
+
return;
|
|
82441
|
+
}
|
|
82442
|
+
const bak = backupExistingCompose2();
|
|
82443
|
+
if (bak)
|
|
82444
|
+
console.log(source_default.dim(` Backed up existing compose to ${bak}`));
|
|
82445
|
+
writeFileSync40(composePath, yaml, "utf8");
|
|
82446
|
+
console.log(source_default.green(` \u2713 Wrote ${composePath}`));
|
|
82447
|
+
console.log(source_default.dim(` running as uid ${operatorUid} (operator), network_mode: host`));
|
|
82448
|
+
console.log(source_default.dim(` Pulling ghcr.io/switchroom/switchroom-web:${opts.tag ?? DEFAULT_IMAGE_TAG2}\u2026`));
|
|
82449
|
+
const pull = runDocker2(["compose", "-p", WEB_COMPOSE_PROJECT, "-f", composePath, "pull"]);
|
|
82450
|
+
if (!pull.ok) {
|
|
82451
|
+
console.error(source_default.red(` pull failed:
|
|
82452
|
+
${pull.stderr}`));
|
|
82453
|
+
console.error(source_default.yellow(` Hint: \`ghcr.io/switchroom/switchroom-web:${opts.tag ?? DEFAULT_IMAGE_TAG2}\` may not be published yet.
|
|
82454
|
+
` + ` Check the docker-images workflow run and verify the tag at:
|
|
82455
|
+
` + ` https://github.com/switchroom/switchroom/pkgs/container/switchroom-web`));
|
|
82456
|
+
process.exit(1);
|
|
82457
|
+
}
|
|
82458
|
+
console.log(source_default.dim(` Bringing up web service\u2026`));
|
|
82459
|
+
const up = runDocker2(["compose", "-p", WEB_COMPOSE_PROJECT, "-f", composePath, "up", "-d"]);
|
|
82460
|
+
if (!up.ok) {
|
|
82461
|
+
console.error(source_default.red(` up failed:
|
|
82462
|
+
${up.stderr}`));
|
|
82463
|
+
process.exit(1);
|
|
82464
|
+
}
|
|
82465
|
+
console.log(source_default.green(` \u2713 Web service running (project: ${WEB_COMPOSE_PROJECT})`));
|
|
82466
|
+
console.log(source_default.dim(` Logs: docker logs switchroom-web --tail 50`));
|
|
82467
|
+
console.log(source_default.dim(` Verify: switchroom webd status`));
|
|
82468
|
+
console.log(source_default.yellow(` NOTE: the switchroom-web.service systemd unit (if still installed) also
|
|
82469
|
+
` + ` binds 127.0.0.1:8080. Stop it before this container can claim the port:
|
|
82470
|
+
` + ` systemctl --user stop switchroom-web.service
|
|
82471
|
+
` + ` systemctl --user disable switchroom-web.service`));
|
|
82472
|
+
}
|
|
82473
|
+
function doStatus2() {
|
|
82474
|
+
const composeYml = webdComposePath();
|
|
82475
|
+
console.log(source_default.bold("switchroom-web"));
|
|
82476
|
+
console.log("");
|
|
82477
|
+
if (!existsSync84(composeYml)) {
|
|
82478
|
+
console.log(source_default.yellow(" compose: not installed"));
|
|
82479
|
+
console.log(source_default.dim(" run `switchroom webd install` to set up."));
|
|
82480
|
+
return;
|
|
82481
|
+
}
|
|
82482
|
+
console.log(source_default.green(` compose: ${composeYml}`));
|
|
82483
|
+
const ps = runDocker2([
|
|
82484
|
+
"compose",
|
|
82485
|
+
"-p",
|
|
82486
|
+
WEB_COMPOSE_PROJECT,
|
|
82487
|
+
"-f",
|
|
82488
|
+
composeYml,
|
|
82489
|
+
"ps",
|
|
82490
|
+
"--format",
|
|
82491
|
+
"{{.Name}} {{.Status}} {{.Image}}"
|
|
82492
|
+
]);
|
|
82493
|
+
if (!ps.ok || !ps.stdout.trim()) {
|
|
82494
|
+
console.log(source_default.yellow(" container: not running"));
|
|
82495
|
+
} else {
|
|
82496
|
+
console.log(source_default.green(` container: ${ps.stdout.trim()}`));
|
|
82497
|
+
}
|
|
82498
|
+
}
|
|
82499
|
+
function doUninstall2() {
|
|
82500
|
+
const composeYml = webdComposePath();
|
|
82501
|
+
if (!existsSync84(composeYml)) {
|
|
82502
|
+
console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
|
|
82503
|
+
return;
|
|
82504
|
+
}
|
|
82505
|
+
console.log(source_default.dim(` Stopping ${WEB_COMPOSE_PROJECT}\u2026`));
|
|
82506
|
+
const down = runDocker2(["compose", "-p", WEB_COMPOSE_PROJECT, "-f", composeYml, "down"]);
|
|
82507
|
+
if (!down.ok) {
|
|
82508
|
+
console.error(source_default.red(` down failed:
|
|
82509
|
+
${down.stderr}`));
|
|
82510
|
+
process.exit(1);
|
|
82511
|
+
}
|
|
82512
|
+
console.log(source_default.green(" \u2713 Web service stopped"));
|
|
82513
|
+
console.log(source_default.dim(` Compose file left in place at ${composeYml}`));
|
|
82514
|
+
console.log(source_default.dim(` To re-enable: switchroom webd install`));
|
|
82515
|
+
console.log(source_default.yellow(` If you cut over from the systemd unit, re-enable it to restore the
|
|
82516
|
+
` + ` dashboard + webhook receiver:
|
|
82517
|
+
` + ` systemctl --user enable --now switchroom-web.service`));
|
|
82518
|
+
}
|
|
82519
|
+
function registerWebdCommand(program3) {
|
|
82520
|
+
const webd = program3.command("webd").description("Manage switchroom-web, the dashboard + GitHub-webhook receiver container");
|
|
82521
|
+
webd.command("install").description("Install or refresh the web container (writes ~/.switchroom/web/docker-compose.yml + docker compose up -d)").option("--tag <tag>", "Image tag (default: latest)", DEFAULT_IMAGE_TAG2).option("--dry-run", "Print the compose file and the docker commands without writing or running anything").action(withConfigError(async (opts) => {
|
|
82522
|
+
await doInstall2(opts);
|
|
82523
|
+
}));
|
|
82524
|
+
webd.command("status").description("Show web-service container state").action(() => doStatus2());
|
|
82525
|
+
webd.command("uninstall").description("Stop the web container. Leaves the compose file in place for re-install.").action(() => doUninstall2());
|
|
82526
|
+
}
|
|
82527
|
+
|
|
82288
82528
|
// src/cli/index.ts
|
|
82289
82529
|
installGlobalErrorHandlers();
|
|
82290
82530
|
var program3 = new Command().name("switchroom").description("Multi-agent orchestrator for Claude Code. One Telegram group, many specialized agents.").version(VERSION).option("-c, --config <path>", "Path to switchroom.yaml config file").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -82333,6 +82573,7 @@ registerSkillSearchCommand(program3);
|
|
|
82333
82573
|
registerAgentConfigMcpCommand(program3);
|
|
82334
82574
|
registerHostdMcpCommand(program3);
|
|
82335
82575
|
registerHostdCommand(program3);
|
|
82576
|
+
registerWebdCommand(program3);
|
|
82336
82577
|
|
|
82337
82578
|
// bin/switchroom.ts
|
|
82338
82579
|
program3.parse();
|
|
@@ -14141,6 +14141,9 @@ var HostControlConfigSchema = exports_external.object({
|
|
|
14141
14141
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
14142
14142
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
14143
14143
|
});
|
|
14144
|
+
var WebServiceConfigSchema = exports_external.object({
|
|
14145
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false — existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
14146
|
+
});
|
|
14144
14147
|
var HostdConfigSchema = exports_external.object({
|
|
14145
14148
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
14146
14149
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -14174,6 +14177,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
14174
14177
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
14175
14178
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
14176
14179
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
14180
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container — then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
14177
14181
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
14178
14182
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
14179
14183
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -11271,7 +11271,7 @@ var init_dist = __esm(() => {
|
|
|
11271
11271
|
});
|
|
11272
11272
|
|
|
11273
11273
|
// src/config/schema.ts
|
|
11274
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
11274
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
11275
11275
|
var init_schema = __esm(() => {
|
|
11276
11276
|
init_zod();
|
|
11277
11277
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -11721,6 +11721,9 @@ var init_schema = __esm(() => {
|
|
|
11721
11721
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
11722
11722
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
11723
11723
|
});
|
|
11724
|
+
WebServiceConfigSchema = exports_external.object({
|
|
11725
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false — existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
11726
|
+
});
|
|
11724
11727
|
HostdConfigSchema = exports_external.object({
|
|
11725
11728
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11726
11729
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -11754,6 +11757,7 @@ var init_schema = __esm(() => {
|
|
|
11754
11757
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11755
11758
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11756
11759
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11760
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container — then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
11757
11761
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11758
11762
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11759
11763
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -11271,7 +11271,7 @@ var init_zod = __esm(() => {
|
|
|
11271
11271
|
});
|
|
11272
11272
|
|
|
11273
11273
|
// src/config/schema.ts
|
|
11274
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
11274
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
11275
11275
|
var init_schema = __esm(() => {
|
|
11276
11276
|
init_zod();
|
|
11277
11277
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -11721,6 +11721,9 @@ var init_schema = __esm(() => {
|
|
|
11721
11721
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
11722
11722
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
11723
11723
|
});
|
|
11724
|
+
WebServiceConfigSchema = exports_external.object({
|
|
11725
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false — existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
11726
|
+
});
|
|
11724
11727
|
HostdConfigSchema = exports_external.object({
|
|
11725
11728
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11726
11729
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -11754,6 +11757,7 @@ var init_schema = __esm(() => {
|
|
|
11754
11757
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11755
11758
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11756
11759
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11760
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container — then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
11757
11761
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11758
11762
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11759
11763
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
package/package.json
CHANGED
|
@@ -23607,7 +23607,7 @@ var init_dist = __esm(() => {
|
|
|
23607
23607
|
});
|
|
23608
23608
|
|
|
23609
23609
|
// ../src/config/schema.ts
|
|
23610
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
23610
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
23611
23611
|
var init_schema = __esm(() => {
|
|
23612
23612
|
init_zod();
|
|
23613
23613
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -24057,6 +24057,9 @@ var init_schema = __esm(() => {
|
|
|
24057
24057
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip \u2014 the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` \u2014 " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C \u00a75.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3)."),
|
|
24058
24058
|
auto_release_check: AutoReleaseCheckSchema.default({}).describe("Pull-based release-triggered fleet restart (#1743). hostd polls " + "the remote release tag on a fixed interval and applies + " + "restarts the fleet (graceful) when a new release is detected. " + "Opt-in: default enabled=false.")
|
|
24059
24059
|
});
|
|
24060
|
+
WebServiceConfigSchema = exports_external.object({
|
|
24061
|
+
managed: exports_external.boolean().default(false).describe("Whether `switchroom update` refreshes the web-service container " + "(dashboard + GitHub-webhook receiver) via `switchroom webd " + "install`. Default: false \u2014 existing installs run the web server " + "as the legacy `switchroom-web.service` systemd unit and must not " + "be surprised by a container takeover of host loopback 127.0.0.1:" + "8080 mid-update. Set true ONLY after cutting over to the " + "container (stop+disable the systemd unit, `switchroom webd " + "install`). The container runs in its own compose project " + "(`switchroom-web`), separate from the agent fleet, with " + "network_mode: host so it keeps owning loopback:8080 for the " + "cloudflared tunnel + tailscale serve consumers.")
|
|
24062
|
+
});
|
|
24060
24063
|
HostdConfigSchema = exports_external.object({
|
|
24061
24064
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit \u00a73). Default false \u2014 the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
24062
24065
|
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit \u00a75). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
@@ -24090,6 +24093,7 @@ var init_schema = __esm(() => {
|
|
|
24090
24093
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
24091
24094
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
24092
24095
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a \u2014 disabled by default)."),
|
|
24096
|
+
web_service: WebServiceConfigSchema.default({}).describe("Web-service container (dashboard + GitHub-webhook receiver) config. " + "Defaults to managed=false so existing systemd-mode installs are " + "untouched. Set managed: true after cutting over to the " + "`switchroom-web` container \u2014 then `switchroom update` keeps it " + "refreshed. See `switchroom webd install`."),
|
|
24093
24097
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
24094
24098
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
24095
24099
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -50788,11 +50792,11 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
50788
50792
|
}
|
|
50789
50793
|
|
|
50790
50794
|
// ../src/build-info.ts
|
|
50791
|
-
var VERSION = "0.14.
|
|
50792
|
-
var COMMIT_SHA = "
|
|
50793
|
-
var COMMIT_DATE = "2026-05-
|
|
50794
|
-
var LATEST_PR =
|
|
50795
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
50795
|
+
var VERSION = "0.14.12";
|
|
50796
|
+
var COMMIT_SHA = "a6cc0835";
|
|
50797
|
+
var COMMIT_DATE = "2026-05-29T20:52:05+10:00";
|
|
50798
|
+
var LATEST_PR = null;
|
|
50799
|
+
var COMMITS_AHEAD_OF_TAG = 2;
|
|
50796
50800
|
|
|
50797
50801
|
// gateway/boot-version.ts
|
|
50798
50802
|
function formatRelativeAgo(iso) {
|