switchroom 0.15.17 → 0.15.19

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.
@@ -25739,6 +25739,7 @@ var init_inject = __esm(() => {
25739
25739
  ["/hooks", { description: "List configured hooks", expectsOutput: true }],
25740
25740
  ["/memory", { description: "Open memory picker", expectsOutput: true }],
25741
25741
  ["/model", { description: "Open model picker", expectsOutput: true }],
25742
+ ["/effort", { description: "Set reasoning effort", expectsOutput: true }],
25742
25743
  [
25743
25744
  "/clear",
25744
25745
  { description: "Clear session screen", expectsOutput: false }
@@ -49571,9 +49572,9 @@ __export(exports_server, {
49571
49572
  dispatchTool: () => dispatchTool,
49572
49573
  TOOLS: () => TOOLS
49573
49574
  });
49574
- import { spawnSync as spawnSync13 } from "node:child_process";
49575
+ import { spawnSync as spawnSync14 } from "node:child_process";
49575
49576
  function execCli(args, stdin) {
49576
- const r = spawnSync13(CLI_BIN, args, {
49577
+ const r = spawnSync14(CLI_BIN, args, {
49577
49578
  encoding: "utf-8",
49578
49579
  env: process.env,
49579
49580
  timeout: 15000,
@@ -50459,8 +50460,8 @@ var {
50459
50460
  } = import__.default;
50460
50461
 
50461
50462
  // src/build-info.ts
50462
- var VERSION = "0.15.17";
50463
- var COMMIT_SHA = "a5129bd3";
50463
+ var VERSION = "0.15.19";
50464
+ var COMMIT_SHA = "3f40c6f9";
50464
50465
 
50465
50466
  // src/cli/agent.ts
50466
50467
  init_source();
@@ -57061,6 +57062,7 @@ function registerAgentCommand(program3) {
57061
57062
  status: status?.active ?? "unknown",
57062
57063
  uptime: formatUptime2(status?.uptime ?? null),
57063
57064
  model: resolved.model ?? SWITCHROOM_DEFAULT_MAIN_MODEL,
57065
+ thinking_effort: resolved.thinking_effort ?? SWITCHROOM_DEFAULT_THINKING_EFFORT,
57064
57066
  extends: agentConfig.extends ?? "default",
57065
57067
  topic_name: agentConfig.topic_name,
57066
57068
  topic_emoji: agentConfig.topic_emoji,
@@ -76809,6 +76811,194 @@ function registerUpdateCommand(program3) {
76809
76811
  });
76810
76812
  }
76811
76813
 
76814
+ // src/cli/rollout.ts
76815
+ init_helpers();
76816
+ import { spawnSync as spawnSync10 } from "node:child_process";
76817
+ function normalizeVersion(v) {
76818
+ return v.trim().replace(/^v/, "");
76819
+ }
76820
+ function isVersionAssertable(target) {
76821
+ return /^v?\d+\.\d+\.\d+$/.test(target.trim());
76822
+ }
76823
+ function orderAgentsCanaryFirst(agents) {
76824
+ const canary = agents.filter((a) => a === "test-harness");
76825
+ const rest = agents.filter((a) => a !== "test-harness");
76826
+ return [...canary, ...rest];
76827
+ }
76828
+ function planRollout(agents, opts = {}) {
76829
+ const steps = [{ kind: "apply" }];
76830
+ for (const agent of orderAgentsCanaryFirst(agents)) {
76831
+ steps.push({ kind: "restart-agent", agent });
76832
+ }
76833
+ if (!opts.skipWeb) {
76834
+ steps.push({ kind: "refresh-web" });
76835
+ steps.push({ kind: "refresh-hostd" });
76836
+ }
76837
+ steps.push({ kind: "sweep" });
76838
+ return steps;
76839
+ }
76840
+ function formatRolloutPlan(steps, target) {
76841
+ const lines = [`Rollout plan \u2192 ${target}:`];
76842
+ let n = 0;
76843
+ for (const s of steps) {
76844
+ n += 1;
76845
+ switch (s.kind) {
76846
+ case "apply":
76847
+ lines.push(` ${n}. apply \u2014 regenerate compose with ${target} image refs`);
76848
+ break;
76849
+ case "restart-agent":
76850
+ lines.push(` ${n}. restart ${s.agent} (--wait --force) + assert --version=${target}`);
76851
+ break;
76852
+ case "refresh-web":
76853
+ lines.push(` ${n}. webd install --tag ${target} (separate compose project)`);
76854
+ break;
76855
+ case "refresh-hostd":
76856
+ lines.push(` ${n}. hostd install --tag ${target} (separate compose project)`);
76857
+ break;
76858
+ case "sweep":
76859
+ lines.push(` ${n}. sweep \u2014 print per-agent version table`);
76860
+ break;
76861
+ }
76862
+ }
76863
+ lines.push("");
76864
+ lines.push("Stops on the first agent that doesn't come back on the target version.");
76865
+ return lines.join(`
76866
+ `);
76867
+ }
76868
+ function executeRollout(steps, target, deps, pinOnApply) {
76869
+ const targetNorm = normalizeVersion(target);
76870
+ const rolled = [];
76871
+ const warnings = [];
76872
+ for (const step of steps) {
76873
+ switch (step.kind) {
76874
+ case "apply": {
76875
+ deps.log(`\u2192 apply \u2014 regenerating compose for ${target}`);
76876
+ const args = pinOnApply ? ["apply", "--pin", target] : ["apply"];
76877
+ const r = deps.run(args);
76878
+ if (r.status !== 0) {
76879
+ return { ok: false, rolled, failedStep: "apply", warnings };
76880
+ }
76881
+ break;
76882
+ }
76883
+ case "restart-agent": {
76884
+ deps.log(`\u2192 restart ${step.agent} (--wait --force)`);
76885
+ deps.run(["agent", "restart", step.agent, "--wait", "--force"]);
76886
+ const got = deps.probeVersion(step.agent);
76887
+ if (got === null || normalizeVersion(got) !== targetNorm) {
76888
+ deps.log(` \u2717 ${step.agent} \u2192 ${got ?? "<unreachable>"} (expected ${target}) \u2014 STOPPING`);
76889
+ return {
76890
+ ok: false,
76891
+ rolled,
76892
+ failedStep: "restart-agent",
76893
+ failedAgent: step.agent,
76894
+ got,
76895
+ warnings
76896
+ };
76897
+ }
76898
+ rolled.push(step.agent);
76899
+ deps.log(` \u2713 ${step.agent} \u2192 ${got}`);
76900
+ break;
76901
+ }
76902
+ case "refresh-web": {
76903
+ deps.log(`\u2192 webd install --tag ${target}`);
76904
+ const r = deps.run(["webd", "install", "--tag", target]);
76905
+ if (r.status !== 0)
76906
+ warnings.push(`web refresh failed (non-fatal); agents already rolled`);
76907
+ break;
76908
+ }
76909
+ case "refresh-hostd": {
76910
+ deps.log(`\u2192 hostd install --tag ${target}`);
76911
+ const r = deps.run(["hostd", "install", "--tag", target]);
76912
+ if (r.status !== 0)
76913
+ warnings.push(`hostd refresh failed (non-fatal); agents already rolled`);
76914
+ break;
76915
+ }
76916
+ case "sweep": {
76917
+ deps.log(`\u2192 sweep`);
76918
+ for (const a of rolled) {
76919
+ const v = deps.probeVersion(a);
76920
+ deps.log(` ${a}: ${v ?? "<unreachable>"}`);
76921
+ }
76922
+ break;
76923
+ }
76924
+ }
76925
+ }
76926
+ return { ok: true, rolled, warnings };
76927
+ }
76928
+ function registerRolloutCommand(program3) {
76929
+ program3.command("rollout").description("Deploy a pinned version to the fleet, safely (staggered restart + " + "per-agent version assert + web/hostd refresh). Run with sudo.").option("--pin <version>", "Version to roll (e.g. v0.15.18). Defaults to release.pin from config.").option("--agents <list>", "Comma-separated subset of agents to roll (default: all configured).").option("--skip-web", "Skip the web + hostd refresh step.").option("--dry-run", "Print the plan and exit without changing anything.").action(async (opts) => {
76930
+ const config = getConfig(program3);
76931
+ const target = opts.pin ?? config.release?.pin;
76932
+ if (!target) {
76933
+ process.stderr.write("rollout needs a pinned version: pass --pin vX.Y.Z, or set " + "`release.pin` in switchroom.yaml. (A floating channel has no " + `fixed version to assert against.)
76934
+ `);
76935
+ process.exitCode = 2;
76936
+ return;
76937
+ }
76938
+ if (!isVersionAssertable(target)) {
76939
+ process.stderr.write(`rollout asserts the in-container \`switchroom --version\` (always a ` + `semver), so the target must be a tagged release like v0.15.18 \u2014 ` + `\`${target}\` isn't version-assertable. Pass --pin vX.Y.Z.
76940
+ `);
76941
+ process.exitCode = 2;
76942
+ return;
76943
+ }
76944
+ const allAgents = Object.keys(config.agents ?? {});
76945
+ const requested = opts.agents ? opts.agents.split(",").map((s) => s.trim()).filter(Boolean) : allAgents;
76946
+ const unknown = requested.filter((a) => !allAgents.includes(a));
76947
+ if (unknown.length > 0) {
76948
+ process.stderr.write(`unknown agent(s): ${unknown.join(", ")}
76949
+ `);
76950
+ process.exitCode = 2;
76951
+ return;
76952
+ }
76953
+ if (requested.length === 0) {
76954
+ process.stderr.write(`no agents to roll.
76955
+ `);
76956
+ process.exitCode = 2;
76957
+ return;
76958
+ }
76959
+ const steps = planRollout(requested, { skipWeb: opts.skipWeb });
76960
+ if (opts.dryRun) {
76961
+ process.stdout.write(formatRolloutPlan(steps, target) + `
76962
+ `);
76963
+ return;
76964
+ }
76965
+ const scriptPath = process.argv[1] ?? "switchroom";
76966
+ const deps = {
76967
+ run: (args) => {
76968
+ const r = spawnSync10(process.execPath, [scriptPath, ...args], { stdio: "inherit" });
76969
+ return { status: r.status ?? 1 };
76970
+ },
76971
+ probeVersion: (agent) => {
76972
+ const r = spawnSync10("docker", ["exec", `switchroom-${agent}`, "sh", "-lc", "switchroom --version"], { encoding: "utf8" });
76973
+ if (r.status !== 0)
76974
+ return null;
76975
+ return (r.stdout ?? "").trim().split(`
76976
+ `).pop()?.trim() ?? null;
76977
+ },
76978
+ log: (line) => process.stdout.write(line + `
76979
+ `)
76980
+ };
76981
+ process.stdout.write(`Rolling ${requested.length} agent(s) to ${target}\u2026
76982
+ `);
76983
+ const result = executeRollout(steps, target, deps, opts.pin != null);
76984
+ for (const w of result.warnings)
76985
+ process.stderr.write(`\u26a0\ufe0f ${w}
76986
+ `);
76987
+ if (!result.ok) {
76988
+ process.stderr.write(`
76989
+ \u2717 Rollout STOPPED at ${result.failedStep}` + (result.failedAgent ? ` (${result.failedAgent} \u2192 ${result.got ?? "unreachable"})` : "") + `.
76990
+ Rolled before stop: ${result.rolled.join(", ") || "none"}.
76991
+ ` + ` Fix the cause, then re-run \`switchroom rollout --pin ${target}\` ` + `(idempotent \u2014 already-current agents bounce back to the same version).
76992
+ `);
76993
+ process.exitCode = 1;
76994
+ return;
76995
+ }
76996
+ process.stdout.write(`
76997
+ \u2705 Rollout complete \u2014 ${result.rolled.length} agent(s) on ${target}` + `${result.warnings.length ? ` (with ${result.warnings.length} warning(s) above)` : ""}.
76998
+ `);
76999
+ });
77000
+ }
77001
+
76812
77002
  // src/cli/restart.ts
76813
77003
  init_source();
76814
77004
  init_helpers();
@@ -78264,7 +78454,7 @@ init_helpers();
78264
78454
  init_loader();
78265
78455
  import { existsSync as existsSync64 } from "node:fs";
78266
78456
  import { resolve as resolve39, sep as sep3 } from "node:path";
78267
- import { spawnSync as spawnSync10 } from "node:child_process";
78457
+ import { spawnSync as spawnSync11 } from "node:child_process";
78268
78458
 
78269
78459
  // src/agents/workspace.ts
78270
78460
  import { readFile as readFile2, stat } from "node:fs/promises";
@@ -78977,7 +79167,7 @@ function registerWorkspaceCommand(program3) {
78977
79167
  process.exit(1);
78978
79168
  }
78979
79169
  const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
78980
- const child = spawnSync10(editor, [target], { stdio: "inherit" });
79170
+ const child = spawnSync11(editor, [target], { stdio: "inherit" });
78981
79171
  if (child.status !== 0 && child.status !== null) {
78982
79172
  process.exit(child.status);
78983
79173
  }
@@ -79044,7 +79234,7 @@ function registerWorkspaceCommand(program3) {
79044
79234
  `);
79045
79235
  return;
79046
79236
  }
79047
- const statusResult = spawnSync10("git", ["status", "--short"], {
79237
+ const statusResult = spawnSync11("git", ["status", "--short"], {
79048
79238
  cwd: dir,
79049
79239
  encoding: "utf-8"
79050
79240
  });
@@ -79059,7 +79249,7 @@ function registerWorkspaceCommand(program3) {
79059
79249
  return;
79060
79250
  }
79061
79251
  const message = opts.message || `checkpoint: ${new Date().toISOString()}`;
79062
- const addResult = spawnSync10("git", ["add", "-A"], {
79252
+ const addResult = spawnSync11("git", ["add", "-A"], {
79063
79253
  cwd: dir,
79064
79254
  encoding: "utf-8"
79065
79255
  });
@@ -79068,7 +79258,7 @@ function registerWorkspaceCommand(program3) {
79068
79258
  `);
79069
79259
  process.exit(1);
79070
79260
  }
79071
- const commitResult = spawnSync10("git", ["commit", "-m", message], {
79261
+ const commitResult = spawnSync11("git", ["commit", "-m", message], {
79072
79262
  cwd: dir,
79073
79263
  encoding: "utf-8"
79074
79264
  });
@@ -79077,7 +79267,7 @@ function registerWorkspaceCommand(program3) {
79077
79267
  `);
79078
79268
  process.exit(1);
79079
79269
  }
79080
- const shaResult = spawnSync10("git", ["rev-parse", "--short", "HEAD"], {
79270
+ const shaResult = spawnSync11("git", ["rev-parse", "--short", "HEAD"], {
79081
79271
  cwd: dir,
79082
79272
  encoding: "utf-8"
79083
79273
  });
@@ -79098,7 +79288,7 @@ function registerWorkspaceCommand(program3) {
79098
79288
  `);
79099
79289
  return;
79100
79290
  }
79101
- const child = spawnSync10("git", ["status", "--short"], {
79291
+ const child = spawnSync11("git", ["status", "--short"], {
79102
79292
  cwd: dir,
79103
79293
  stdio: "inherit"
79104
79294
  });
@@ -84093,7 +84283,7 @@ import {
84093
84283
  } from "node:fs";
84094
84284
  import { tmpdir as tmpdir5, homedir as homedir45 } from "node:os";
84095
84285
  import { dirname as dirname23, join as join79, relative as relative2, resolve as resolve47 } from "node:path";
84096
- import { spawnSync as spawnSync11 } from "node:child_process";
84286
+ import { spawnSync as spawnSync12 } from "node:child_process";
84097
84287
 
84098
84288
  // src/cli/skill-common.ts
84099
84289
  var import_yaml22 = __toESM(require_dist(), 1);
@@ -84346,7 +84536,7 @@ function loadFromDir(dir) {
84346
84536
  function loadFromTarball(tarPath) {
84347
84537
  const isGz = tarPath.endsWith(".gz") || tarPath.endsWith(".tgz");
84348
84538
  const listFlags = isGz ? ["-tzf"] : ["-tf"];
84349
- const list2 = spawnSync11("tar", [...listFlags, tarPath], {
84539
+ const list2 = spawnSync12("tar", [...listFlags, tarPath], {
84350
84540
  encoding: "utf-8",
84351
84541
  stdio: ["ignore", "pipe", "pipe"]
84352
84542
  });
@@ -84363,7 +84553,7 @@ function loadFromTarball(tarPath) {
84363
84553
  const staging = mkdtempSync5(join79(tmpdir5(), "skill-apply-extract-"));
84364
84554
  try {
84365
84555
  const flags = isGz ? ["-xzf"] : ["-xf"];
84366
- const r = spawnSync11("tar", [
84556
+ const r = spawnSync12("tar", [
84367
84557
  ...flags,
84368
84558
  tarPath,
84369
84559
  "-C",
@@ -84438,7 +84628,7 @@ function validatePayload(name, files) {
84438
84628
  if (errors2.length === 0) {
84439
84629
  for (const [path8, content] of Object.entries(files)) {
84440
84630
  if (SH_SCRIPT_RE2.test(path8)) {
84441
- const r = spawnSync11("bash", ["-n"], {
84631
+ const r = spawnSync12("bash", ["-n"], {
84442
84632
  input: content,
84443
84633
  encoding: "utf-8"
84444
84634
  });
@@ -84450,7 +84640,7 @@ function validatePayload(name, files) {
84450
84640
  const tmpPy = join79(tmp, "check.py");
84451
84641
  try {
84452
84642
  writeFileSync39(tmpPy, content);
84453
- const r = spawnSync11("python3", ["-m", "py_compile", tmpPy], {
84643
+ const r = spawnSync12("python3", ["-m", "py_compile", tmpPy], {
84454
84644
  encoding: "utf-8"
84455
84645
  });
84456
84646
  if (r.status !== 0) {
@@ -84613,7 +84803,7 @@ function registerSkillCommand(program3) {
84613
84803
  \u2713 Wrote ${name} to ${currentDir}`));
84614
84804
  const applyBin = process.argv[1] ?? "switchroom";
84615
84805
  console.log(source_default.gray(`Running \`switchroom apply --non-interactive\`...`));
84616
- const r = spawnSync11(process.argv0, [applyBin, "apply", "--non-interactive"], { stdio: "inherit" });
84806
+ const r = spawnSync12(process.argv0, [applyBin, "apply", "--non-interactive"], { stdio: "inherit" });
84617
84807
  if (r.status !== 0) {
84618
84808
  console.error(source_default.yellow(`(warning: \`switchroom apply\` exited ${r.status} \u2014 skill is ` + `in the pool but symlinks may not be refreshed. Re-run manually.)`));
84619
84809
  }
@@ -84645,7 +84835,7 @@ import {
84645
84835
  } from "node:fs";
84646
84836
  import { dirname as dirname24, join as join80, relative as relative3, resolve as resolve48 } from "node:path";
84647
84837
  import { homedir as homedir46, tmpdir as tmpdir6 } from "node:os";
84648
- import { spawnSync as spawnSync12 } from "node:child_process";
84838
+ import { spawnSync as spawnSync13 } from "node:child_process";
84649
84839
  init_helpers();
84650
84840
  init_source();
84651
84841
  var PERSONAL_PREFIX = "personal-";
@@ -84834,7 +85024,7 @@ function behavioralValidate(files) {
84834
85024
  const errors2 = [];
84835
85025
  for (const [path8, content] of Object.entries(files)) {
84836
85026
  if (SH_SCRIPT_RE.test(path8)) {
84837
- const r = spawnSync12("bash", ["-n"], { input: content, encoding: "utf-8" });
85027
+ const r = spawnSync13("bash", ["-n"], { input: content, encoding: "utf-8" });
84838
85028
  if (r.status !== 0) {
84839
85029
  errors2.push(`${path8} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
84840
85030
  }
@@ -84843,7 +85033,7 @@ function behavioralValidate(files) {
84843
85033
  const tmpPy = join80(tmp, "check.py");
84844
85034
  try {
84845
85035
  writeFileSync40(tmpPy, content);
84846
- const r = spawnSync12("python3", ["-m", "py_compile", tmpPy], {
85036
+ const r = spawnSync13("python3", ["-m", "py_compile", tmpPy], {
84847
85037
  encoding: "utf-8"
84848
85038
  });
84849
85039
  if (r.status !== 0) {
@@ -85536,7 +85726,7 @@ init_helpers();
85536
85726
  import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as readFileSync71, writeFileSync as writeFileSync41, statSync as statSync34, copyFileSync as copyFileSync12 } from "node:fs";
85537
85727
  import { homedir as homedir48 } from "node:os";
85538
85728
  import { join as join82 } from "node:path";
85539
- import { spawnSync as spawnSync14 } from "node:child_process";
85729
+ import { spawnSync as spawnSync15 } from "node:child_process";
85540
85730
  init_audit_reader();
85541
85731
  function resolveHostdImageTag(explicitTag, release) {
85542
85732
  if (explicitTag)
@@ -85668,7 +85858,7 @@ function backupExistingCompose() {
85668
85858
  return bak;
85669
85859
  }
85670
85860
  function runDocker(args) {
85671
- const r = spawnSync14("docker", args, { encoding: "utf8" });
85861
+ const r = spawnSync15("docker", args, { encoding: "utf8" });
85672
85862
  return {
85673
85863
  ok: r.status === 0,
85674
85864
  stdout: r.stdout ?? "",
@@ -85861,7 +86051,7 @@ init_helpers();
85861
86051
  import { existsSync as existsSync85, mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, copyFileSync as copyFileSync13 } from "node:fs";
85862
86052
  import { homedir as homedir49 } from "node:os";
85863
86053
  import { join as join83 } from "node:path";
85864
- import { spawnSync as spawnSync15 } from "node:child_process";
86054
+ import { spawnSync as spawnSync16 } from "node:child_process";
85865
86055
  function resolveWebImageTag(explicitTag, release) {
85866
86056
  if (explicitTag)
85867
86057
  return explicitTag;
@@ -85960,7 +86150,7 @@ function backupExistingCompose2() {
85960
86150
  return bak;
85961
86151
  }
85962
86152
  function runDocker2(args) {
85963
- const r = spawnSync15("docker", args, { encoding: "utf8" });
86153
+ const r = spawnSync16("docker", args, { encoding: "utf8" });
85964
86154
  return {
85965
86155
  ok: r.status === 0,
85966
86156
  stdout: r.stdout ?? "",
@@ -86090,6 +86280,7 @@ var program3 = new Command().name("switchroom").description("Multi-agent orchest
86090
86280
  registerSetupCommand(program3);
86091
86281
  registerDoctorCommand(program3);
86092
86282
  registerUpdateCommand(program3);
86283
+ registerRolloutCommand(program3);
86093
86284
  registerRestartCommand(program3);
86094
86285
  registerVersionCommand(program3);
86095
86286
  registerVersionsCommand(program3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.15.17",
3
+ "version": "0.15.19",
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": {