switchroom 0.13.5 → 0.13.7

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.
@@ -11307,6 +11307,10 @@ var QuotaConfigSchema = exports_external.object({
11307
11307
  var HostControlConfigSchema = exports_external.object({
11308
11308
  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).")
11309
11309
  });
11310
+ var HostdConfigSchema = exports_external.object({
11311
+ 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."),
11312
+ 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.")
11313
+ });
11310
11314
  var SwitchroomConfigSchema = exports_external.object({
11311
11315
  switchroom: exports_external.object({
11312
11316
  version: exports_external.literal(1).describe("Config schema version"),
@@ -11333,6 +11337,7 @@ var SwitchroomConfigSchema = exports_external.object({
11333
11337
  google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
11334
11338
  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."),
11335
11339
  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)."),
11340
+ 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)."),
11336
11341
  google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
11337
11342
  message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
11338
11343
  }).transform((v) => v.trim().toLowerCase()), exports_external.object({
@@ -11307,6 +11307,10 @@ var QuotaConfigSchema = exports_external.object({
11307
11307
  var HostControlConfigSchema = exports_external.object({
11308
11308
  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).")
11309
11309
  });
11310
+ var HostdConfigSchema = exports_external.object({
11311
+ 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."),
11312
+ 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.")
11313
+ });
11310
11314
  var SwitchroomConfigSchema = exports_external.object({
11311
11315
  switchroom: exports_external.object({
11312
11316
  version: exports_external.literal(1).describe("Config schema version"),
@@ -11333,6 +11337,7 @@ var SwitchroomConfigSchema = exports_external.object({
11333
11337
  google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
11334
11338
  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."),
11335
11339
  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)."),
11340
+ 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)."),
11336
11341
  google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
11337
11342
  message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
11338
11343
  }).transform((v) => v.trim().toLowerCase()), exports_external.object({
@@ -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, AgentGoogleWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, HostControlConfigSchema, SwitchroomConfigSchema;
13523
+ var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
13524
13524
  var init_schema = __esm(() => {
13525
13525
  init_zod();
13526
13526
  CodeRepoEntrySchema = exports_external.object({
@@ -13871,6 +13871,10 @@ var init_schema = __esm(() => {
13871
13871
  HostControlConfigSchema = exports_external.object({
13872
13872
  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).")
13873
13873
  });
13874
+ HostdConfigSchema = exports_external.object({
13875
+ 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."),
13876
+ 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.")
13877
+ });
13874
13878
  SwitchroomConfigSchema = exports_external.object({
13875
13879
  switchroom: exports_external.object({
13876
13880
  version: exports_external.literal(1).describe("Config schema version"),
@@ -13897,6 +13901,7 @@ var init_schema = __esm(() => {
13897
13901
  google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration \u2014 " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
13898
13902
  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."),
13899
13903
  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)."),
13904
+ 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)."),
13900
13905
  google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
13901
13906
  message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
13902
13907
  }).transform((v) => v.trim().toLowerCase()), exports_external.object({
@@ -29067,7 +29072,7 @@ function decodeResponse3(line) {
29067
29072
  const obj = JSON.parse(line);
29068
29073
  return ResponseSchema3.parse(obj);
29069
29074
  }
29070
- var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, RequestSchema3, ResultSchema, ResponseEnvelope, ResponseSchema3;
29075
+ var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, ConfigProposeEditRequestSchema, RequestSchema3, ResultSchema, ResponseEnvelope, ResponseSchema3;
29071
29076
  var init_protocol3 = __esm(() => {
29072
29077
  init_zod();
29073
29078
  MAX_FRAME_BYTES3 = 64 * 1024;
@@ -29161,6 +29166,15 @@ var init_protocol3 = __esm(() => {
29161
29166
  deep: exports_external.boolean().optional()
29162
29167
  })
29163
29168
  });
29169
+ ConfigProposeEditRequestSchema = exports_external.object({
29170
+ ...RequestEnvelope,
29171
+ op: exports_external.literal("config_propose_edit"),
29172
+ args: exports_external.object({
29173
+ unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
29174
+ reason: exports_external.string().min(1).max(500),
29175
+ target_path: exports_external.literal("/state/config/switchroom.yaml")
29176
+ })
29177
+ });
29164
29178
  RequestSchema3 = exports_external.discriminatedUnion("op", [
29165
29179
  AgentRestartRequestSchema,
29166
29180
  UpgradeStatusRequestSchema,
@@ -29173,7 +29187,8 @@ var init_protocol3 = __esm(() => {
29173
29187
  AgentLogsRequestSchema,
29174
29188
  AgentExecRequestSchema,
29175
29189
  DoctorRequestSchema,
29176
- AgentSmokeRequestSchema
29190
+ AgentSmokeRequestSchema,
29191
+ ConfigProposeEditRequestSchema
29177
29192
  ]);
29178
29193
  ResultSchema = exports_external.enum(["started", "completed", "denied", "error"]);
29179
29194
  ResponseEnvelope = {
@@ -47009,6 +47024,31 @@ async function dispatchTool2(name, args) {
47009
47024
  };
47010
47025
  break;
47011
47026
  }
47027
+ case "config_propose_edit": {
47028
+ if (!args.unified_diff || typeof args.unified_diff !== "string") {
47029
+ return errorText2("config_propose_edit: unified_diff is required (non-empty string).");
47030
+ }
47031
+ if (!args.reason || typeof args.reason !== "string") {
47032
+ return errorText2("config_propose_edit: reason is required (non-empty string, \u2264500 chars).");
47033
+ }
47034
+ if (args.reason.length > 500) {
47035
+ return errorText2("config_propose_edit: reason is capped at 500 chars (RFC \u00a73.3).");
47036
+ }
47037
+ if (args.target_path !== "/state/config/switchroom.yaml") {
47038
+ return errorText2("config_propose_edit: target_path must be '/state/config/switchroom.yaml'.");
47039
+ }
47040
+ req = {
47041
+ v: 1,
47042
+ op: "config_propose_edit",
47043
+ request_id: makeRequestId("mcp-config-propose-edit"),
47044
+ args: {
47045
+ unified_diff: args.unified_diff,
47046
+ reason: args.reason,
47047
+ target_path: "/state/config/switchroom.yaml"
47048
+ }
47049
+ };
47050
+ break;
47051
+ }
47012
47052
  default:
47013
47053
  return errorText2(`unknown tool: ${name}`);
47014
47054
  }
@@ -47219,6 +47259,32 @@ var init_server4 = __esm(() => {
47219
47259
  }
47220
47260
  }
47221
47261
  },
47262
+ {
47263
+ name: "config_propose_edit",
47264
+ description: "Propose a unified-diff patch against /state/config/switchroom.yaml " + "(RFC admin-agent-config-edit). When fully shipped the host validates " + "the patch (applies cleanly + post-patch yaml parses against the " + "config schema) and raises a Telegram approval card in the OPERATOR's " + "primary chat \u2014 NOT yours; the requesting agent's chat is not the " + "approval surface. Admin-only at the wire layer. " + "Current status (PR 1a \u2014 skeleton): the tool is registered but the " + "feature is OFF by default; calling it returns " + "E_CONFIG_EDIT_DISABLED until the operator sets " + "hostd.config_edit_enabled=true in switchroom.yaml. Even when enabled " + "in this PR, the call returns E_NOT_IMPLEMENTED \u2014 the validation " + "pipeline (PR 1b) and apply path (PR 1c) ship in follow-up PRs.",
47265
+ inputSchema: {
47266
+ type: "object",
47267
+ required: ["unified_diff", "reason", "target_path"],
47268
+ properties: {
47269
+ unified_diff: {
47270
+ type: "string",
47271
+ minLength: 1,
47272
+ description: "Unified diff against switchroom.yaml. Must have \u22653 lines " + "context (enforced in PR 1b); no path-traversal or multi-file " + "diffs. LF-only, \u22641 MB."
47273
+ },
47274
+ reason: {
47275
+ type: "string",
47276
+ minLength: 1,
47277
+ maxLength: 500,
47278
+ description: "Human-readable rationale shown to the operator on the " + "approval card. Capped at 500 chars (RFC \u00a73.3)."
47279
+ },
47280
+ target_path: {
47281
+ type: "string",
47282
+ enum: ["/state/config/switchroom.yaml"],
47283
+ description: "Must be the literal string '/state/config/switchroom.yaml'. " + "Future-proofs against multi-file diffs and gives the validator " + "a single canonical path to anchor on."
47284
+ }
47285
+ }
47286
+ }
47287
+ },
47222
47288
  {
47223
47289
  name: "get_status",
47224
47290
  description: "Read the most recent terminal `update_apply` audit row " + "(channel, pin, resolved_sha, install_context, result, " + "exit_code, stderr_tail). Use this after issuing an " + "`update_apply` to confirm what actually rolled out, or to " + "report the last update on demand. Returns the parsed audit " + "entry as JSON.",
@@ -47248,8 +47314,8 @@ var {
47248
47314
  } = import__.default;
47249
47315
 
47250
47316
  // src/build-info.ts
47251
- var VERSION = "0.13.5";
47252
- var COMMIT_SHA = "cb688641";
47317
+ var VERSION = "0.13.7";
47318
+ var COMMIT_SHA = "84d28022";
47253
47319
 
47254
47320
  // src/cli/agent.ts
47255
47321
  init_source();