switchroom 0.13.24 → 0.13.26

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.
@@ -11034,7 +11034,6 @@ var SessionSchema = exports_external.object({
11034
11034
  var SessionContinuitySchema = exports_external.object({
11035
11035
  enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
11036
11036
  show_handoff_line: exports_external.boolean().optional().describe("Whether the telegram plugin prepends a visible '↩️ Picked up…' " + "line to the first assistant reply after a restart (default true)."),
11037
- summarizer_model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional().describe("Anthropic model used to produce the handoff briefing."),
11038
11037
  max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
11039
11038
  resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
11040
11039
  resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
@@ -11081,10 +11080,9 @@ var TelegramChannelSchema = exports_external.object({
11081
11080
  start: exports_external.number().int().min(0).max(23),
11082
11081
  end: exports_external.number().int().min(0).max(23),
11083
11082
  tz: exports_external.string().optional()
11084
- }).optional(),
11085
- model: exports_external.string().optional()
11083
+ }).optional()
11086
11084
  })).optional()
11087
- }).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "spawn a one-shot `claude -p` turn for the agent with the rendered " + "prompt. Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
11085
+ }).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "inject the rendered prompt into the agent's live session (#1625). " + "Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
11088
11086
  webhook_rate_limit: exports_external.object({
11089
11087
  rpm: exports_external.number().int().positive()
11090
11088
  }).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit.")
@@ -11034,7 +11034,6 @@ var SessionSchema = exports_external.object({
11034
11034
  var SessionContinuitySchema = exports_external.object({
11035
11035
  enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
11036
11036
  show_handoff_line: exports_external.boolean().optional().describe("Whether the telegram plugin prepends a visible '↩️ Picked up…' " + "line to the first assistant reply after a restart (default true)."),
11037
- summarizer_model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional().describe("Anthropic model used to produce the handoff briefing."),
11038
11037
  max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
11039
11038
  resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
11040
11039
  resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
@@ -11081,10 +11080,9 @@ var TelegramChannelSchema = exports_external.object({
11081
11080
  start: exports_external.number().int().min(0).max(23),
11082
11081
  end: exports_external.number().int().min(0).max(23),
11083
11082
  tz: exports_external.string().optional()
11084
- }).optional(),
11085
- model: exports_external.string().optional()
11083
+ }).optional()
11086
11084
  })).optional()
11087
- }).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "spawn a one-shot `claude -p` turn for the agent with the rendered " + "prompt. Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
11085
+ }).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "inject the rendered prompt into the agent's live session (#1625). " + "Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
11088
11086
  webhook_rate_limit: exports_external.object({
11089
11087
  rpm: exports_external.number().int().positive()
11090
11088
  }).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit.")
@@ -11646,7 +11644,7 @@ function resolveAgentsDir(config) {
11646
11644
  import * as net from "node:net";
11647
11645
  import {
11648
11646
  chmodSync,
11649
- chownSync,
11647
+ chownSync as chownSync2,
11650
11648
  existsSync as existsSync6,
11651
11649
  lstatSync,
11652
11650
  mkdirSync as mkdirSync3,
@@ -12107,6 +12105,7 @@ function atomicWriteJsonSync(destPath, value, mode = 384) {
12107
12105
 
12108
12106
  // src/auth/account-store.ts
12109
12107
  import {
12108
+ chownSync,
12110
12109
  existsSync as existsSync4,
12111
12110
  mkdirSync,
12112
12111
  readFileSync as readFileSync3,
@@ -12203,6 +12202,18 @@ function writeAccountCredentials(label, value, home2 = homedir2()) {
12203
12202
  mkdirSync(accountDir(label, home2), { recursive: true });
12204
12203
  atomicWriteJson(accountCredentialsPath(label, home2), enrichClaudeCreds(value));
12205
12204
  }
12205
+ function chownAccountFiles(label, uid, home2 = homedir2()) {
12206
+ validateAccountLabel(label);
12207
+ const dir = accountDir(label, home2);
12208
+ if (existsSync4(dir))
12209
+ chownSync(dir, uid, uid);
12210
+ const creds = accountCredentialsPath(label, home2);
12211
+ if (existsSync4(creds))
12212
+ chownSync(creds, uid, uid);
12213
+ const meta = accountMetaPath(label, home2);
12214
+ if (existsSync4(meta))
12215
+ chownSync(meta, uid, uid);
12216
+ }
12206
12217
  function readAccountMeta(label, home2 = homedir2()) {
12207
12218
  const p = accountMetaPath(label, home2);
12208
12219
  if (!existsSync4(p))
@@ -13135,7 +13146,7 @@ class AuthBroker {
13135
13146
  const dir = dirname2(sockPath);
13136
13147
  if (existsSync6(dir)) {
13137
13148
  try {
13138
- chownSync(dir, 0, 0);
13149
+ chownSync2(dir, 0, 0);
13139
13150
  } catch {}
13140
13151
  try {
13141
13152
  chmodSync(dir, 448);
@@ -13158,10 +13169,10 @@ class AuthBroker {
13158
13169
  chmodSync(sockPath, sockMode);
13159
13170
  } catch {}
13160
13171
  try {
13161
- chownSync(sockPath, targetUid, targetUid);
13172
+ chownSync2(sockPath, targetUid, targetUid);
13162
13173
  } catch {}
13163
13174
  try {
13164
- chownSync(dir, targetUid, targetUid);
13175
+ chownSync2(dir, targetUid, targetUid);
13165
13176
  } catch {}
13166
13177
  this.listeners.set(sockPath, { server, identity: identity2, socketPath: sockPath });
13167
13178
  resolveP();
@@ -13507,6 +13518,7 @@ class AuthBroker {
13507
13518
  socket.write(encodeError(id, "INTERNAL", err.message));
13508
13519
  return;
13509
13520
  }
13521
+ this.chownAccountFilesIfRoot(label);
13510
13522
  const contents = readFileSync5(accountCredentialsPath(label, this.home), "utf-8");
13511
13523
  this.shaIndex[label] = sha256Hex(contents);
13512
13524
  this.lastWrittenExpiresAt.set(label, credentials.claudeAiOauth?.expiresAt);
@@ -13749,6 +13761,7 @@ class AuthBroker {
13749
13761
  };
13750
13762
  const outcome = await refreshAccountIfNeeded(label, opts);
13751
13763
  if (outcome.kind === "refreshed") {
13764
+ this.chownAccountFilesIfRoot(label);
13752
13765
  const creds = readAccountCredentials(label, this.home);
13753
13766
  const newExpiresAt = creds?.claudeAiOauth?.expiresAt ?? outcome.newExpiresAt;
13754
13767
  this.lastWrittenExpiresAt.set(label, newExpiresAt);
@@ -13899,7 +13912,7 @@ class AuthBroker {
13899
13912
  atomicWriteFileSync(targetPath, mirrorContent, 384);
13900
13913
  try {
13901
13914
  const uid = allocateAgentUid(agentName);
13902
- chownSync(targetPath, uid, uid);
13915
+ chownSync2(targetPath, uid, uid);
13903
13916
  } catch (err) {
13904
13917
  this.warnCapChownMissing(err);
13905
13918
  }
@@ -14026,6 +14039,15 @@ class AuthBroker {
14026
14039
  const msg = err instanceof Error ? err.message : String(err);
14027
14040
  this.logErr(`chown failed (CAP_CHOWN missing?): ${msg}. ` + `Per-agent mirror written but ownership not flipped. ` + `Suppressing further chown warnings for this process.`);
14028
14041
  }
14042
+ chownAccountFilesIfRoot(label) {
14043
+ if (this.operatorUid === undefined)
14044
+ return;
14045
+ try {
14046
+ chownAccountFiles(label, this.operatorUid, this.home);
14047
+ } catch (err) {
14048
+ this.warnCapChownMissing(err);
14049
+ }
14050
+ }
14029
14051
  assertConfigConsistent(cfg) {
14030
14052
  const shape = configToShape(cfg);
14031
14053
  const errs = validateConsumerNames(shape);