switchroom 0.13.46 → 0.13.48

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.
@@ -27507,6 +27507,206 @@ function verifyAuditLog(fullText) {
27507
27507
  var CHAIN_GENESIS = "GENESIS", SEP = "\x00";
27508
27508
  var init_audit_hashchain = () => {};
27509
27509
 
27510
+ // src/host-control/protocol.ts
27511
+ function buildEnvelope(code, human, fix, opts = {}) {
27512
+ return {
27513
+ v: 1,
27514
+ code,
27515
+ human,
27516
+ ...opts.why !== undefined ? { why: opts.why } : {},
27517
+ ...fix !== undefined ? { fix } : {},
27518
+ ...opts.docs !== undefined ? { docs: opts.docs } : {},
27519
+ ...opts.request_id !== undefined ? { request_id: opts.request_id } : {}
27520
+ };
27521
+ }
27522
+ function encodeRequest3(req) {
27523
+ const json = JSON.stringify(req);
27524
+ if (Buffer.byteLength(json, "utf8") > MAX_FRAME_BYTES3) {
27525
+ throw new Error(`hostd: request frame too large (${Buffer.byteLength(json, "utf8")} bytes; max ${MAX_FRAME_BYTES3})`);
27526
+ }
27527
+ return json + `
27528
+ `;
27529
+ }
27530
+ function decodeResponse3(line) {
27531
+ if (Buffer.byteLength(line, "utf8") > MAX_FRAME_BYTES3) {
27532
+ throw new RangeError(`hostd: response frame too large (${Buffer.byteLength(line, "utf8")} bytes; max ${MAX_FRAME_BYTES3})`);
27533
+ }
27534
+ const obj = JSON.parse(line);
27535
+ return ResponseSchema3.parse(obj);
27536
+ }
27537
+ var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema2, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, ConfigProposeEditRequestSchema, RequestSchema3, ResultSchema, ErrorFixSchema, ErrorEnvelopeSchema, ResponseEnvelope, ResponseSchema3;
27538
+ var init_protocol3 = __esm(() => {
27539
+ init_zod();
27540
+ MAX_FRAME_BYTES3 = 64 * 1024;
27541
+ RequestEnvelope = {
27542
+ v: exports_external.literal(1),
27543
+ request_id: exports_external.string().min(1).max(128),
27544
+ idempotency_key: exports_external.string().min(1).max(128).optional()
27545
+ };
27546
+ AgentRestartRequestSchema = exports_external.object({
27547
+ ...RequestEnvelope,
27548
+ op: exports_external.literal("agent_restart"),
27549
+ args: exports_external.object({
27550
+ name: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII"),
27551
+ reason: exports_external.string().max(512).optional(),
27552
+ force: exports_external.boolean().optional()
27553
+ })
27554
+ });
27555
+ UpgradeStatusRequestSchema = exports_external.object({
27556
+ ...RequestEnvelope,
27557
+ op: exports_external.literal("upgrade_status"),
27558
+ args: exports_external.object({}).optional()
27559
+ });
27560
+ GetStatusRequestSchema = exports_external.object({
27561
+ ...RequestEnvelope,
27562
+ op: exports_external.literal("get_status"),
27563
+ args: exports_external.object({
27564
+ target_request_id: exports_external.string().min(1).max(128)
27565
+ })
27566
+ });
27567
+ AgentNameSchema2 = exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII");
27568
+ UpdateCheckRequestSchema = exports_external.object({
27569
+ ...RequestEnvelope,
27570
+ op: exports_external.literal("update_check"),
27571
+ args: exports_external.object({}).optional()
27572
+ });
27573
+ UpdateApplyRequestSchema = exports_external.object({
27574
+ ...RequestEnvelope,
27575
+ op: exports_external.literal("update_apply"),
27576
+ args: exports_external.object({
27577
+ skip_images: exports_external.boolean().optional(),
27578
+ rebuild: exports_external.boolean().optional(),
27579
+ channel: exports_external.enum(["dev", "rc", "latest"]).nullable().optional(),
27580
+ pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).nullable().optional()
27581
+ }).optional()
27582
+ });
27583
+ ApplyRequestSchema = exports_external.object({
27584
+ ...RequestEnvelope,
27585
+ op: exports_external.literal("apply"),
27586
+ args: exports_external.object({}).optional()
27587
+ });
27588
+ AgentStartRequestSchema = exports_external.object({
27589
+ ...RequestEnvelope,
27590
+ op: exports_external.literal("agent_start"),
27591
+ args: exports_external.object({
27592
+ name: AgentNameSchema2
27593
+ })
27594
+ });
27595
+ AgentStopRequestSchema = exports_external.object({
27596
+ ...RequestEnvelope,
27597
+ op: exports_external.literal("agent_stop"),
27598
+ args: exports_external.object({
27599
+ name: AgentNameSchema2
27600
+ })
27601
+ });
27602
+ AgentLogsRequestSchema = exports_external.object({
27603
+ ...RequestEnvelope,
27604
+ op: exports_external.literal("agent_logs"),
27605
+ args: exports_external.object({
27606
+ name: AgentNameSchema2,
27607
+ tail: exports_external.number().int().positive().max(2000).optional()
27608
+ })
27609
+ });
27610
+ AgentExecRequestSchema = exports_external.object({
27611
+ ...RequestEnvelope,
27612
+ op: exports_external.literal("agent_exec"),
27613
+ args: exports_external.object({
27614
+ name: AgentNameSchema2,
27615
+ argv: exports_external.array(exports_external.string().min(1)).min(1).max(32)
27616
+ })
27617
+ });
27618
+ DoctorRequestSchema = exports_external.object({
27619
+ ...RequestEnvelope,
27620
+ op: exports_external.literal("doctor"),
27621
+ args: exports_external.object({}).optional()
27622
+ });
27623
+ AgentSmokeRequestSchema = exports_external.object({
27624
+ ...RequestEnvelope,
27625
+ op: exports_external.literal("agent_smoke"),
27626
+ args: exports_external.object({
27627
+ name: AgentNameSchema2,
27628
+ deep: exports_external.boolean().optional()
27629
+ })
27630
+ });
27631
+ ConfigProposeEditRequestSchema = exports_external.object({
27632
+ ...RequestEnvelope,
27633
+ op: exports_external.literal("config_propose_edit"),
27634
+ args: exports_external.object({
27635
+ unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
27636
+ reason: exports_external.string().min(1).max(500),
27637
+ target_path: exports_external.literal("/state/config/switchroom.yaml")
27638
+ })
27639
+ });
27640
+ RequestSchema3 = exports_external.discriminatedUnion("op", [
27641
+ AgentRestartRequestSchema,
27642
+ UpgradeStatusRequestSchema,
27643
+ GetStatusRequestSchema,
27644
+ UpdateCheckRequestSchema,
27645
+ UpdateApplyRequestSchema,
27646
+ ApplyRequestSchema,
27647
+ AgentStartRequestSchema,
27648
+ AgentStopRequestSchema,
27649
+ AgentLogsRequestSchema,
27650
+ AgentExecRequestSchema,
27651
+ DoctorRequestSchema,
27652
+ AgentSmokeRequestSchema,
27653
+ ConfigProposeEditRequestSchema
27654
+ ]);
27655
+ ResultSchema = exports_external.enum(["started", "completed", "denied", "error"]);
27656
+ ErrorFixSchema = exports_external.discriminatedUnion("kind", [
27657
+ exports_external.object({
27658
+ kind: exports_external.literal("flip_yaml_flag"),
27659
+ yaml_path: exports_external.string(),
27660
+ to: exports_external.unknown()
27661
+ }),
27662
+ exports_external.object({
27663
+ kind: exports_external.literal("request_vault_grant"),
27664
+ vault_key: exports_external.string()
27665
+ }),
27666
+ exports_external.object({
27667
+ kind: exports_external.literal("operator_action"),
27668
+ subkind: exports_external.enum(["policy_denied", "infra", "out_of_scope"]),
27669
+ operator_steps: exports_external.array(exports_external.string()).min(1).optional()
27670
+ }),
27671
+ exports_external.object({
27672
+ kind: exports_external.literal("retry_after"),
27673
+ retry_at: exports_external.string()
27674
+ }),
27675
+ exports_external.object({
27676
+ kind: exports_external.literal("quota_exceeded"),
27677
+ quota: exports_external.string(),
27678
+ current: exports_external.number(),
27679
+ limit: exports_external.number()
27680
+ }),
27681
+ exports_external.object({
27682
+ kind: exports_external.literal("bad_input"),
27683
+ field: exports_external.string().optional()
27684
+ })
27685
+ ]);
27686
+ ErrorEnvelopeSchema = exports_external.object({
27687
+ v: exports_external.literal(1),
27688
+ code: exports_external.string().regex(/^(E_[A-Z0-9_]+|VAULT-[A-Z-]+)$/),
27689
+ human: exports_external.string().min(1),
27690
+ why: exports_external.string().optional(),
27691
+ fix: ErrorFixSchema.optional(),
27692
+ docs: exports_external.string().url().optional(),
27693
+ request_id: exports_external.string().min(1).optional()
27694
+ });
27695
+ ResponseEnvelope = {
27696
+ v: exports_external.literal(1),
27697
+ request_id: exports_external.string().min(1).max(128),
27698
+ result: ResultSchema,
27699
+ exit_code: exports_external.number().int().nullable(),
27700
+ duration_ms: exports_external.number().int().nonnegative(),
27701
+ audit_id: exports_external.string().min(1).optional(),
27702
+ stdout_tail: exports_external.string().optional(),
27703
+ stderr_tail: exports_external.string().optional(),
27704
+ error: exports_external.string().optional(),
27705
+ error_envelope: ErrorEnvelopeSchema.optional()
27706
+ };
27707
+ ResponseSchema3 = exports_external.object(ResponseEnvelope);
27708
+ });
27709
+
27510
27710
  // src/host-control/audit-reader.ts
27511
27711
  import { homedir as homedir18 } from "node:os";
27512
27712
  import { join as join35 } from "node:path";
@@ -29114,195 +29314,6 @@ var init_doctor_audit_integrity = __esm(() => {
29114
29314
  init_audit_hashchain();
29115
29315
  });
29116
29316
 
29117
- // src/host-control/protocol.ts
29118
- function encodeRequest3(req) {
29119
- const json = JSON.stringify(req);
29120
- if (Buffer.byteLength(json, "utf8") > MAX_FRAME_BYTES3) {
29121
- throw new Error(`hostd: request frame too large (${Buffer.byteLength(json, "utf8")} bytes; max ${MAX_FRAME_BYTES3})`);
29122
- }
29123
- return json + `
29124
- `;
29125
- }
29126
- function decodeResponse3(line) {
29127
- if (Buffer.byteLength(line, "utf8") > MAX_FRAME_BYTES3) {
29128
- throw new RangeError(`hostd: response frame too large (${Buffer.byteLength(line, "utf8")} bytes; max ${MAX_FRAME_BYTES3})`);
29129
- }
29130
- const obj = JSON.parse(line);
29131
- return ResponseSchema3.parse(obj);
29132
- }
29133
- var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema2, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, ConfigProposeEditRequestSchema, RequestSchema3, ResultSchema, ErrorFixSchema, ErrorEnvelopeSchema, ResponseEnvelope, ResponseSchema3;
29134
- var init_protocol3 = __esm(() => {
29135
- init_zod();
29136
- MAX_FRAME_BYTES3 = 64 * 1024;
29137
- RequestEnvelope = {
29138
- v: exports_external.literal(1),
29139
- request_id: exports_external.string().min(1).max(128),
29140
- idempotency_key: exports_external.string().min(1).max(128).optional()
29141
- };
29142
- AgentRestartRequestSchema = exports_external.object({
29143
- ...RequestEnvelope,
29144
- op: exports_external.literal("agent_restart"),
29145
- args: exports_external.object({
29146
- name: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII"),
29147
- reason: exports_external.string().max(512).optional(),
29148
- force: exports_external.boolean().optional()
29149
- })
29150
- });
29151
- UpgradeStatusRequestSchema = exports_external.object({
29152
- ...RequestEnvelope,
29153
- op: exports_external.literal("upgrade_status"),
29154
- args: exports_external.object({}).optional()
29155
- });
29156
- GetStatusRequestSchema = exports_external.object({
29157
- ...RequestEnvelope,
29158
- op: exports_external.literal("get_status"),
29159
- args: exports_external.object({
29160
- target_request_id: exports_external.string().min(1).max(128)
29161
- })
29162
- });
29163
- AgentNameSchema2 = exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII");
29164
- UpdateCheckRequestSchema = exports_external.object({
29165
- ...RequestEnvelope,
29166
- op: exports_external.literal("update_check"),
29167
- args: exports_external.object({}).optional()
29168
- });
29169
- UpdateApplyRequestSchema = exports_external.object({
29170
- ...RequestEnvelope,
29171
- op: exports_external.literal("update_apply"),
29172
- args: exports_external.object({
29173
- skip_images: exports_external.boolean().optional(),
29174
- rebuild: exports_external.boolean().optional(),
29175
- channel: exports_external.enum(["dev", "rc", "latest"]).nullable().optional(),
29176
- pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).nullable().optional()
29177
- }).optional()
29178
- });
29179
- ApplyRequestSchema = exports_external.object({
29180
- ...RequestEnvelope,
29181
- op: exports_external.literal("apply"),
29182
- args: exports_external.object({}).optional()
29183
- });
29184
- AgentStartRequestSchema = exports_external.object({
29185
- ...RequestEnvelope,
29186
- op: exports_external.literal("agent_start"),
29187
- args: exports_external.object({
29188
- name: AgentNameSchema2
29189
- })
29190
- });
29191
- AgentStopRequestSchema = exports_external.object({
29192
- ...RequestEnvelope,
29193
- op: exports_external.literal("agent_stop"),
29194
- args: exports_external.object({
29195
- name: AgentNameSchema2
29196
- })
29197
- });
29198
- AgentLogsRequestSchema = exports_external.object({
29199
- ...RequestEnvelope,
29200
- op: exports_external.literal("agent_logs"),
29201
- args: exports_external.object({
29202
- name: AgentNameSchema2,
29203
- tail: exports_external.number().int().positive().max(2000).optional()
29204
- })
29205
- });
29206
- AgentExecRequestSchema = exports_external.object({
29207
- ...RequestEnvelope,
29208
- op: exports_external.literal("agent_exec"),
29209
- args: exports_external.object({
29210
- name: AgentNameSchema2,
29211
- argv: exports_external.array(exports_external.string().min(1)).min(1).max(32)
29212
- })
29213
- });
29214
- DoctorRequestSchema = exports_external.object({
29215
- ...RequestEnvelope,
29216
- op: exports_external.literal("doctor"),
29217
- args: exports_external.object({}).optional()
29218
- });
29219
- AgentSmokeRequestSchema = exports_external.object({
29220
- ...RequestEnvelope,
29221
- op: exports_external.literal("agent_smoke"),
29222
- args: exports_external.object({
29223
- name: AgentNameSchema2,
29224
- deep: exports_external.boolean().optional()
29225
- })
29226
- });
29227
- ConfigProposeEditRequestSchema = exports_external.object({
29228
- ...RequestEnvelope,
29229
- op: exports_external.literal("config_propose_edit"),
29230
- args: exports_external.object({
29231
- unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
29232
- reason: exports_external.string().min(1).max(500),
29233
- target_path: exports_external.literal("/state/config/switchroom.yaml")
29234
- })
29235
- });
29236
- RequestSchema3 = exports_external.discriminatedUnion("op", [
29237
- AgentRestartRequestSchema,
29238
- UpgradeStatusRequestSchema,
29239
- GetStatusRequestSchema,
29240
- UpdateCheckRequestSchema,
29241
- UpdateApplyRequestSchema,
29242
- ApplyRequestSchema,
29243
- AgentStartRequestSchema,
29244
- AgentStopRequestSchema,
29245
- AgentLogsRequestSchema,
29246
- AgentExecRequestSchema,
29247
- DoctorRequestSchema,
29248
- AgentSmokeRequestSchema,
29249
- ConfigProposeEditRequestSchema
29250
- ]);
29251
- ResultSchema = exports_external.enum(["started", "completed", "denied", "error"]);
29252
- ErrorFixSchema = exports_external.discriminatedUnion("kind", [
29253
- exports_external.object({
29254
- kind: exports_external.literal("flip_yaml_flag"),
29255
- yaml_path: exports_external.string(),
29256
- to: exports_external.unknown()
29257
- }),
29258
- exports_external.object({
29259
- kind: exports_external.literal("request_vault_grant"),
29260
- vault_key: exports_external.string()
29261
- }),
29262
- exports_external.object({
29263
- kind: exports_external.literal("operator_action"),
29264
- subkind: exports_external.enum(["policy_denied", "infra", "out_of_scope"]),
29265
- operator_steps: exports_external.array(exports_external.string()).min(1).optional()
29266
- }),
29267
- exports_external.object({
29268
- kind: exports_external.literal("retry_after"),
29269
- retry_at: exports_external.string()
29270
- }),
29271
- exports_external.object({
29272
- kind: exports_external.literal("quota_exceeded"),
29273
- quota: exports_external.string(),
29274
- current: exports_external.number(),
29275
- limit: exports_external.number()
29276
- }),
29277
- exports_external.object({
29278
- kind: exports_external.literal("bad_input"),
29279
- field: exports_external.string().optional()
29280
- })
29281
- ]);
29282
- ErrorEnvelopeSchema = exports_external.object({
29283
- v: exports_external.literal(1),
29284
- code: exports_external.string().regex(/^(E_[A-Z0-9_]+|VAULT-[A-Z-]+)$/),
29285
- human: exports_external.string().min(1),
29286
- why: exports_external.string().optional(),
29287
- fix: ErrorFixSchema.optional(),
29288
- docs: exports_external.string().url().optional(),
29289
- request_id: exports_external.string().min(1)
29290
- });
29291
- ResponseEnvelope = {
29292
- v: exports_external.literal(1),
29293
- request_id: exports_external.string().min(1).max(128),
29294
- result: ResultSchema,
29295
- exit_code: exports_external.number().int().nullable(),
29296
- duration_ms: exports_external.number().int().nonnegative(),
29297
- audit_id: exports_external.string().min(1).optional(),
29298
- stdout_tail: exports_external.string().optional(),
29299
- stderr_tail: exports_external.string().optional(),
29300
- error: exports_external.string().optional(),
29301
- error_envelope: ErrorEnvelopeSchema.optional()
29302
- };
29303
- ResponseSchema3 = exports_external.object(ResponseEnvelope);
29304
- });
29305
-
29306
29317
  // src/host-control/client.ts
29307
29318
  import { connect as connect2 } from "node:net";
29308
29319
  async function hostdRequest(opts, req) {
@@ -47902,8 +47913,8 @@ var {
47902
47913
  } = import__.default;
47903
47914
 
47904
47915
  // src/build-info.ts
47905
- var VERSION = "0.13.46";
47906
- var COMMIT_SHA = "dbee5c3d";
47916
+ var VERSION = "0.13.48";
47917
+ var COMMIT_SHA = "576a7cef";
47907
47918
 
47908
47919
  // src/cli/agent.ts
47909
47920
  init_source();
@@ -48474,11 +48485,14 @@ Example response shapes:
48474
48485
  function alignAgentUid(name, agentDir, uid, opts = {}) {
48475
48486
  const writeOut = opts.writeOut ?? ((s) => process.stdout.write(s));
48476
48487
  const logsDir = join8(homedir4(), ".switchroom", "logs", name);
48488
+ const auditDir = join8(homedir4(), ".switchroom", "audit", name);
48477
48489
  const paths = [];
48478
48490
  if (existsSync11(agentDir))
48479
48491
  paths.push(agentDir);
48480
48492
  if (existsSync11(logsDir))
48481
48493
  paths.push(logsDir);
48494
+ if (existsSync11(auditDir))
48495
+ paths.push(auditDir);
48482
48496
  if (paths.length === 0)
48483
48497
  return { chowned: false, paths: [] };
48484
48498
  const priors = [];
@@ -61648,18 +61662,10 @@ function registerVaultBackupCommand(vault, program3) {
61648
61662
  }
61649
61663
 
61650
61664
  // src/cli/vault-denied-envelope.ts
61665
+ init_protocol3();
61651
61666
  var ENVELOPE_SENTINEL = "ERROR-ENVELOPE:";
61652
61667
  function writeVaultDeniedEnvelope(vaultKey, brokerCode, human) {
61653
- const envelope = {
61654
- v: 1,
61655
- code: "VAULT-BROKER-DENIED",
61656
- human: `${brokerCode}: ${human}`,
61657
- fix: {
61658
- kind: "request_vault_grant",
61659
- vault_key: vaultKey
61660
- },
61661
- request_id: `vault-cli-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`
61662
- };
61668
+ const envelope = buildEnvelope("VAULT-BROKER-DENIED", `${brokerCode}: ${human}`, { kind: "request_vault_grant", vault_key: vaultKey });
61663
61669
  process.stderr.write(`${ENVELOPE_SENTINEL} ${JSON.stringify(envelope)}
61664
61670
  `);
61665
61671
  }
@@ -74711,6 +74717,7 @@ async function ensureHostMountSources(config) {
74711
74717
  dirs.push(join62(home2, ".switchroom", "agents", name));
74712
74718
  dirs.push(join62(home2, ".switchroom", "logs", name));
74713
74719
  dirs.push(join62(home2, ".claude", "projects", name));
74720
+ dirs.push(join62(home2, ".switchroom", "audit", name));
74714
74721
  }
74715
74722
  for (const dir of dirs) {
74716
74723
  await mkdir(dir, { recursive: true });
@@ -76293,8 +76300,8 @@ function denyPendingScheduleEntry(opts) {
76293
76300
  }
76294
76301
 
76295
76302
  // src/cli/agent-config-write.ts
76303
+ init_protocol3();
76296
76304
  import { existsSync as existsSync73, readFileSync as readFileSync59 } from "node:fs";
76297
- import { randomUUID as randomUUID5 } from "node:crypto";
76298
76305
  var MAX_ENTRIES_PER_AGENT = 20;
76299
76306
  var MIN_CRON_INTERVAL_MIN = 5;
76300
76307
  function extractCronSmallestGapMin(expr) {
@@ -76335,35 +76342,22 @@ function checkOperatorContext(verb, env2 = process.env) {
76335
76342
  return { ok: true };
76336
76343
  }
76337
76344
  function buildEnvelopeForCode(code, message, extra) {
76338
- const request_id = `agent-config-${randomUUID5()}`;
76339
76345
  if (code === "E_CRON_TOO_FREQUENT") {
76340
- return {
76341
- v: 1,
76342
- code,
76343
- human: message,
76344
- fix: {
76345
- kind: "quota_exceeded",
76346
- quota: "cron_min_interval_minutes",
76347
- current: typeof extra.requested_interval_min === "number" ? extra.requested_interval_min : 0,
76348
- limit: MIN_CRON_INTERVAL_MIN
76349
- },
76350
- request_id
76351
- };
76346
+ return buildEnvelope(code, message, {
76347
+ kind: "quota_exceeded",
76348
+ quota: "cron_min_interval_minutes",
76349
+ current: typeof extra.requested_interval_min === "number" ? extra.requested_interval_min : 0,
76350
+ limit: MIN_CRON_INTERVAL_MIN
76351
+ });
76352
76352
  }
76353
76353
  if (code === "E_QUOTA_EXCEEDED") {
76354
76354
  const current = typeof extra.current === "number" ? extra.current : MAX_ENTRIES_PER_AGENT;
76355
- return {
76356
- v: 1,
76357
- code,
76358
- human: message,
76359
- fix: {
76360
- kind: "quota_exceeded",
76361
- quota: "schedule_entries_per_agent",
76362
- current,
76363
- limit: MAX_ENTRIES_PER_AGENT
76364
- },
76365
- request_id
76366
- };
76355
+ return buildEnvelope(code, message, {
76356
+ kind: "quota_exceeded",
76357
+ quota: "schedule_entries_per_agent",
76358
+ current,
76359
+ limit: MAX_ENTRIES_PER_AGENT
76360
+ });
76367
76361
  }
76368
76362
  return;
76369
76363
  }
@@ -14880,8 +14880,19 @@ var ErrorEnvelopeSchema = exports_external.object({
14880
14880
  why: exports_external.string().optional(),
14881
14881
  fix: ErrorFixSchema.optional(),
14882
14882
  docs: exports_external.string().url().optional(),
14883
- request_id: exports_external.string().min(1)
14883
+ request_id: exports_external.string().min(1).optional()
14884
14884
  });
14885
+ function buildEnvelope(code, human, fix, opts = {}) {
14886
+ return {
14887
+ v: 1,
14888
+ code,
14889
+ human,
14890
+ ...opts.why !== undefined ? { why: opts.why } : {},
14891
+ ...fix !== undefined ? { fix } : {},
14892
+ ...opts.docs !== undefined ? { docs: opts.docs } : {},
14893
+ ...opts.request_id !== undefined ? { request_id: opts.request_id } : {}
14894
+ };
14895
+ }
14885
14896
  var ResponseEnvelope = {
14886
14897
  v: exports_external.literal(1),
14887
14898
  request_id: exports_external.string().min(1).max(128),
@@ -19530,15 +19541,11 @@ class ErrorBuilder {
19530
19541
  return this;
19531
19542
  }
19532
19543
  build(requestId, durationMs) {
19533
- const envelope = {
19534
- v: 1,
19535
- code: this._code,
19536
- human: this._human,
19537
- ...this._why !== undefined ? { why: this._why } : {},
19538
- ...this._fix !== undefined ? { fix: this._fix } : {},
19539
- ...this._docs !== undefined ? { docs: this._docs } : {},
19544
+ const envelope = buildEnvelope(this._code, this._human, this._fix, {
19545
+ why: this._why,
19546
+ docs: this._docs,
19540
19547
  request_id: requestId
19541
- };
19548
+ });
19542
19549
  const legacy = `${this._code}: ${this._human}` + (this._why ? ` — ${this._why}` : "");
19543
19550
  const ctx = {
19544
19551
  op: this._op,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.13.46",
3
+ "version": "0.13.48",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43456,7 +43456,7 @@ var ErrorEnvelopeSchema = exports_external.object({
43456
43456
  why: exports_external.string().optional(),
43457
43457
  fix: ErrorFixSchema.optional(),
43458
43458
  docs: exports_external.string().url().optional(),
43459
- request_id: exports_external.string().min(1)
43459
+ request_id: exports_external.string().min(1).optional()
43460
43460
  });
43461
43461
  var ResponseEnvelope = {
43462
43462
  v: exports_external.literal(1),
@@ -48732,10 +48732,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
48732
48732
  }
48733
48733
 
48734
48734
  // ../src/build-info.ts
48735
- var VERSION = "0.13.46";
48736
- var COMMIT_SHA = "dbee5c3d";
48737
- var COMMIT_DATE = "2026-05-25T19:11:00Z";
48738
- var LATEST_PR = 1830;
48735
+ var VERSION = "0.13.48";
48736
+ var COMMIT_SHA = "576a7cef";
48737
+ var COMMIT_DATE = "2026-05-25T20:47:09Z";
48738
+ var LATEST_PR = 1838;
48739
48739
  var COMMITS_AHEAD_OF_TAG = 0;
48740
48740
 
48741
48741
  // gateway/boot-version.ts
@@ -28,6 +28,16 @@
28
28
  "timeout": 5
29
29
  }
30
30
  ]
31
+ },
32
+ {
33
+ "matcher": "^(Read|Edit|Write|MultiEdit|NotebookEdit|Bash)$",
34
+ "hooks": [
35
+ {
36
+ "type": "command",
37
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/repo-context-pretool.mjs\"",
38
+ "timeout": 5
39
+ }
40
+ ]
31
41
  }
32
42
  ],
33
43
  "PostToolUse": [