claude-threads 1.21.2 → 1.22.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.22.0] - 2026-08-08
9
+
10
+ ### Changed
11
+ - **A newer Claude CLI no longer takes the bot down — the version check is now a three-tier policy.** Previously the single hard range `>=2.0.74 <2.2.0` meant that the day Anthropic ships CLI 2.2.0, every bot whose CLI auto-updates would refuse to start until a claude-threads release widened the range — the worst failure mode for a bot people depend on. Now: below the floor (`2.0.74`) or on a new major (3.x+) the bot still exits with an error (those genuinely can't work / are a different contract); but a **newer 2.x above the verified range starts normally with a visible warning** — at startup, in the terminal header, and as an "⚠️ untested" marker next to the CLI version in the sticky channel message and session headers. `--skip-version-check` still bypasses the hard exits, and a bypassed hard exit is no longer silent either: the bot warns at startup and marks the version "⚠️ unsupported" in the same places. Onboarding speaks the same policy (warn-and-continue on untested, tier-specific messages on the hard tiers). The verified range (latest verified: 2.1.223) is unchanged; when a new CLI minor ships, it gets verified and the range bumped in a patch release — the warning is the prompt to do that, not a permanent state.
12
+
8
13
  ## [1.21.2] - 2026-08-07
9
14
 
10
15
  ### Added
package/dist/index.js CHANGED
@@ -16965,8 +16965,8 @@ var require_gt3 = __commonJS((exports, module) => {
16965
16965
  // node_modules/package-json/node_modules/semver/functions/lt.js
16966
16966
  var require_lt2 = __commonJS((exports, module) => {
16967
16967
  var compare = require_compare3();
16968
- var lt = (a, b, loose) => compare(a, b, loose) < 0;
16969
- module.exports = lt;
16968
+ var lt2 = (a, b, loose) => compare(a, b, loose) < 0;
16969
+ module.exports = lt2;
16970
16970
  });
16971
16971
 
16972
16972
  // node_modules/package-json/node_modules/semver/functions/eq.js
@@ -17003,7 +17003,7 @@ var require_cmp2 = __commonJS((exports, module) => {
17003
17003
  var neq = require_neq2();
17004
17004
  var gt = require_gt3();
17005
17005
  var gte = require_gte2();
17006
- var lt = require_lt2();
17006
+ var lt2 = require_lt2();
17007
17007
  var lte = require_lte2();
17008
17008
  var cmp = (a, op, b, loose) => {
17009
17009
  switch (op) {
@@ -17034,7 +17034,7 @@ var require_cmp2 = __commonJS((exports, module) => {
17034
17034
  case ">=":
17035
17035
  return gte(a, b, loose);
17036
17036
  case "<":
17037
- return lt(a, b, loose);
17037
+ return lt2(a, b, loose);
17038
17038
  case "<=":
17039
17039
  return lte(a, b, loose);
17040
17040
  default:
@@ -17755,7 +17755,7 @@ var require_outside2 = __commonJS((exports, module) => {
17755
17755
  var Range = require_range2();
17756
17756
  var satisfies2 = require_satisfies2();
17757
17757
  var gt = require_gt3();
17758
- var lt = require_lt2();
17758
+ var lt2 = require_lt2();
17759
17759
  var lte = require_lte2();
17760
17760
  var gte = require_gte2();
17761
17761
  var outside = (version, range, hilo, options) => {
@@ -17766,12 +17766,12 @@ var require_outside2 = __commonJS((exports, module) => {
17766
17766
  case ">":
17767
17767
  gtfn = gt;
17768
17768
  ltefn = lte;
17769
- ltfn = lt;
17769
+ ltfn = lt2;
17770
17770
  comp = ">";
17771
17771
  ecomp = ">=";
17772
17772
  break;
17773
17773
  case "<":
17774
- gtfn = lt;
17774
+ gtfn = lt2;
17775
17775
  ltefn = gte;
17776
17776
  ltfn = gt;
17777
17777
  comp = "<";
@@ -17937,12 +17937,12 @@ var require_subset2 = __commonJS((exports, module) => {
17937
17937
  }
17938
17938
  }
17939
17939
  const eqSet = new Set;
17940
- let gt, lt;
17940
+ let gt, lt2;
17941
17941
  for (const c of sub) {
17942
17942
  if (c.operator === ">" || c.operator === ">=") {
17943
17943
  gt = higherGT(gt, c, options);
17944
17944
  } else if (c.operator === "<" || c.operator === "<=") {
17945
- lt = lowerLT(lt, c, options);
17945
+ lt2 = lowerLT(lt2, c, options);
17946
17946
  } else {
17947
17947
  eqSet.add(c.semver);
17948
17948
  }
@@ -17951,11 +17951,11 @@ var require_subset2 = __commonJS((exports, module) => {
17951
17951
  return null;
17952
17952
  }
17953
17953
  let gtltComp;
17954
- if (gt && lt) {
17955
- gtltComp = compare(gt.semver, lt.semver, options);
17954
+ if (gt && lt2) {
17955
+ gtltComp = compare(gt.semver, lt2.semver, options);
17956
17956
  if (gtltComp > 0) {
17957
17957
  return null;
17958
- } else if (gtltComp === 0 && (gt.operator !== ">=" || lt.operator !== "<=")) {
17958
+ } else if (gtltComp === 0 && (gt.operator !== ">=" || lt2.operator !== "<=")) {
17959
17959
  return null;
17960
17960
  }
17961
17961
  }
@@ -17963,7 +17963,7 @@ var require_subset2 = __commonJS((exports, module) => {
17963
17963
  if (gt && !satisfies2(eq, String(gt), options)) {
17964
17964
  return null;
17965
17965
  }
17966
- if (lt && !satisfies2(eq, String(lt), options)) {
17966
+ if (lt2 && !satisfies2(eq, String(lt2), options)) {
17967
17967
  return null;
17968
17968
  }
17969
17969
  for (const c of dom) {
@@ -17975,9 +17975,9 @@ var require_subset2 = __commonJS((exports, module) => {
17975
17975
  }
17976
17976
  let higher, lower;
17977
17977
  let hasDomLT, hasDomGT;
17978
- let needDomLTPre = lt && !options.includePrerelease && lt.semver.prerelease.length ? lt.semver : false;
17978
+ let needDomLTPre = lt2 && !options.includePrerelease && lt2.semver.prerelease.length ? lt2.semver : false;
17979
17979
  let needDomGTPre = gt && !options.includePrerelease && gt.semver.prerelease.length ? gt.semver : false;
17980
- if (needDomLTPre && needDomLTPre.prerelease.length === 1 && lt.operator === "<" && needDomLTPre.prerelease[0] === 0) {
17980
+ if (needDomLTPre && needDomLTPre.prerelease.length === 1 && lt2.operator === "<" && needDomLTPre.prerelease[0] === 0) {
17981
17981
  needDomLTPre = false;
17982
17982
  }
17983
17983
  for (const c of dom) {
@@ -17998,29 +17998,29 @@ var require_subset2 = __commonJS((exports, module) => {
17998
17998
  return false;
17999
17999
  }
18000
18000
  }
18001
- if (lt) {
18001
+ if (lt2) {
18002
18002
  if (needDomLTPre) {
18003
18003
  if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomLTPre.major && c.semver.minor === needDomLTPre.minor && c.semver.patch === needDomLTPre.patch) {
18004
18004
  needDomLTPre = false;
18005
18005
  }
18006
18006
  }
18007
18007
  if (c.operator === "<" || c.operator === "<=") {
18008
- lower = lowerLT(lt, c, options);
18009
- if (lower === c && lower !== lt) {
18008
+ lower = lowerLT(lt2, c, options);
18009
+ if (lower === c && lower !== lt2) {
18010
18010
  return false;
18011
18011
  }
18012
- } else if (lt.operator === "<=" && !satisfies2(lt.semver, String(c), options)) {
18012
+ } else if (lt2.operator === "<=" && !satisfies2(lt2.semver, String(c), options)) {
18013
18013
  return false;
18014
18014
  }
18015
18015
  }
18016
- if (!c.operator && (lt || gt) && gtltComp !== 0) {
18016
+ if (!c.operator && (lt2 || gt) && gtltComp !== 0) {
18017
18017
  return false;
18018
18018
  }
18019
18019
  }
18020
- if (gt && hasDomLT && !lt && gtltComp !== 0) {
18020
+ if (gt && hasDomLT && !lt2 && gtltComp !== 0) {
18021
18021
  return false;
18022
18022
  }
18023
- if (lt && hasDomGT && !gt && gtltComp !== 0) {
18023
+ if (lt2 && hasDomGT && !gt && gtltComp !== 0) {
18024
18024
  return false;
18025
18025
  }
18026
18026
  if (needDomGTPre || needDomLTPre) {
@@ -18067,7 +18067,7 @@ var require_semver5 = __commonJS((exports, module) => {
18067
18067
  var sort = require_sort2();
18068
18068
  var rsort = require_rsort2();
18069
18069
  var gt = require_gt3();
18070
- var lt = require_lt2();
18070
+ var lt2 = require_lt2();
18071
18071
  var eq = require_eq2();
18072
18072
  var neq = require_neq2();
18073
18073
  var gte = require_gte2();
@@ -18105,7 +18105,7 @@ var require_semver5 = __commonJS((exports, module) => {
18105
18105
  sort,
18106
18106
  rsort,
18107
18107
  gt,
18108
- lt,
18108
+ lt: lt2,
18109
18109
  eq,
18110
18110
  neq,
18111
18111
  gte,
@@ -51296,6 +51296,7 @@ var dim = (s) => `${colors.dim}${s}${colors.reset}`;
51296
51296
  var bold = (s) => `${colors.bold}${s}${colors.reset}`;
51297
51297
  var green = (s) => `${colors.green}${s}${colors.reset}`;
51298
51298
  var red = (s) => `${colors.red}${s}${colors.reset}`;
51299
+ var yellow = (s) => `${colors.yellow}${s}${colors.reset}`;
51299
51300
 
51300
51301
  // src/claude/version-check.ts
51301
51302
  var import_semver = __toESM(require_semver2(), 1);
@@ -51315,7 +51316,10 @@ var COMMON_CLAUDE_PATHS = process.platform === "win32" ? [
51315
51316
  `${process.env.HOME}/.bun/bin/claude`,
51316
51317
  "/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js"
51317
51318
  ];
51318
- var CLAUDE_CLI_VERSION_RANGE = ">=2.0.74 <2.2.0";
51319
+ var CLAUDE_CLI_MIN_VERSION = "2.0.74";
51320
+ var CLAUDE_CLI_VERIFIED_RANGE = ">=2.0.74 <2.2.0";
51321
+ var CLAUDE_CLI_SUPPORTED_MAJOR = 2;
51322
+ var CLAUDE_CLI_LATEST_VERIFIED = "2.1.223";
51319
51323
  function tryClaudeVersion(claudePath) {
51320
51324
  try {
51321
51325
  const output = execSync(`"${claudePath}" --version`, {
@@ -51387,11 +51391,17 @@ function getClaudeCliVersion() {
51387
51391
  error: `Command 'claude' not found. Searched: ${checkedPaths.slice(0, 3).join(", ")}...`
51388
51392
  };
51389
51393
  }
51390
- function isVersionCompatible(version) {
51394
+ function classifyClaudeVersion(version) {
51391
51395
  const semverVersion = import_semver.coerce(version);
51392
51396
  if (!semverVersion)
51393
- return false;
51394
- return import_semver.satisfies(semverVersion, CLAUDE_CLI_VERSION_RANGE);
51397
+ return "incompatible";
51398
+ if (import_semver.lt(semverVersion, CLAUDE_CLI_MIN_VERSION))
51399
+ return "incompatible";
51400
+ if (semverVersion.major > CLAUDE_CLI_SUPPORTED_MAJOR)
51401
+ return "incompatible";
51402
+ if (import_semver.satisfies(semverVersion, CLAUDE_CLI_VERIFIED_RANGE))
51403
+ return "ok";
51404
+ return "untested";
51395
51405
  }
51396
51406
  function getClaudePath() {
51397
51407
  if (process.env.CLAUDE_PATH) {
@@ -51419,36 +51429,41 @@ function validateClaudeCli() {
51419
51429
  installed: false,
51420
51430
  version: null,
51421
51431
  compatible: false,
51432
+ status: "incompatible",
51422
51433
  message: `Claude CLI not found at '${claudePath}'. Install it with: npm install -g @anthropic-ai/claude-code`,
51423
51434
  error: result.error
51424
51435
  };
51425
51436
  }
51426
- if (!result.version && result.rawOutput) {
51437
+ if (!result.version) {
51427
51438
  return {
51428
51439
  installed: true,
51429
51440
  version: null,
51430
51441
  compatible: true,
51442
+ status: "ok",
51431
51443
  message: `Claude CLI found (version unknown)`,
51432
- rawOutput: result.rawOutput
51444
+ rawOutput: result.rawOutput ?? undefined
51433
51445
  };
51434
51446
  }
51435
- if (!result.version) {
51447
+ const status = classifyClaudeVersion(result.version);
51448
+ if (status === "incompatible") {
51449
+ const semverVersion = import_semver.coerce(result.version);
51450
+ const reason = semverVersion && semverVersion.major > CLAUDE_CLI_SUPPORTED_MAJOR ? `is a new major version (only ${CLAUDE_CLI_SUPPORTED_MAJOR}.x is supported)` : `is too old (minimum: ${CLAUDE_CLI_MIN_VERSION})`;
51436
51451
  return {
51437
51452
  installed: true,
51438
- version: null,
51439
- compatible: true,
51440
- message: "Claude CLI found (version unknown)",
51453
+ version: result.version,
51454
+ compatible: false,
51455
+ status,
51456
+ message: `Claude CLI version ${result.version} ${reason}. ` + `Install a verified version: npm install -g @anthropic-ai/claude-code@${CLAUDE_CLI_LATEST_VERIFIED}`,
51441
51457
  rawOutput: result.rawOutput ?? undefined
51442
51458
  };
51443
51459
  }
51444
- const compatible = isVersionCompatible(result.version);
51445
- if (!compatible) {
51460
+ if (status === "untested") {
51446
51461
  return {
51447
51462
  installed: true,
51448
51463
  version: result.version,
51449
- compatible: false,
51450
- message: `Claude CLI version ${result.version} is not compatible. Required: ${CLAUDE_CLI_VERSION_RANGE}
51451
- ` + `Install a compatible version: npm install -g @anthropic-ai/claude-code@2.1.223`,
51464
+ compatible: true,
51465
+ status,
51466
+ message: `Claude CLI ${result.version} is newer than the latest verified version (${CLAUDE_CLI_LATEST_VERIFIED}) — untested, continuing anyway. ` + `Features may misbehave; pin a verified version with: npm install -g @anthropic-ai/claude-code@${CLAUDE_CLI_LATEST_VERIFIED}`,
51452
51467
  rawOutput: result.rawOutput ?? undefined
51453
51468
  };
51454
51469
  }
@@ -51456,6 +51471,7 @@ function validateClaudeCli() {
51456
51471
  installed: true,
51457
51472
  version: result.version,
51458
51473
  compatible: true,
51474
+ status,
51459
51475
  message: `Claude CLI ${result.version} ✓`,
51460
51476
  rawOutput: result.rawOutput ?? undefined
51461
51477
  };
@@ -51694,34 +51710,30 @@ async function runOnboarding(reconfigure = false) {
51694
51710
  }
51695
51711
  if (!claudeCheck.compatible) {
51696
51712
  console.log("");
51697
- if (claudeCheck.version) {
51698
- console.log(dim(` ⚠️ Claude Code CLI ${claudeCheck.version} is not compatible`));
51699
- console.log("");
51700
- console.log(dim(` Install a compatible version:`));
51701
- console.log(dim(" npm install -g @anthropic-ai/claude-code@2.1.223"));
51702
- } else {
51703
- console.log(dim(" ⚠️ Claude Code CLI found but version could not be determined"));
51704
- if (claudeCheck.rawOutput) {
51705
- console.log(dim(` Output from "claude --version": ${claudeCheck.rawOutput}`));
51706
- }
51707
- console.log("");
51708
- console.log(dim(" This may work fine - Claude was installed in a non-standard way."));
51709
- }
51713
+ console.log(dim(` ⚠️ ${claudeCheck.message}`));
51710
51714
  console.log("");
51711
51715
  const { continueAnyway } = await import_prompts.default({
51712
51716
  type: "confirm",
51713
51717
  name: "continueAnyway",
51714
51718
  message: "Continue anyway? (may not work correctly)",
51715
- initial: !claudeCheck.version
51719
+ initial: false
51716
51720
  }, { onCancel });
51717
51721
  if (!continueAnyway) {
51718
51722
  console.log("");
51719
51723
  console.log(dim(" Setup cancelled."));
51720
51724
  process.exit(0);
51721
51725
  }
51726
+ } else if (claudeCheck.status === "untested") {
51727
+ console.log("");
51728
+ console.log(dim(` ⚠️ ${claudeCheck.message}`));
51729
+ } else if (!claudeCheck.version) {
51730
+ console.log(dim(" ⚠️ Claude Code CLI found but version could not be determined"));
51731
+ if (claudeCheck.rawOutput) {
51732
+ console.log(dim(` Output from "claude --version": ${claudeCheck.rawOutput}`));
51733
+ }
51734
+ console.log(dim(" This may work fine - Claude was installed in a non-standard way."));
51722
51735
  } else {
51723
- const versionInfo = claudeCheck.version ?? "version unknown";
51724
- console.log(dim(` ✓ Claude Code CLI ${versionInfo}`));
51736
+ console.log(dim(` ✓ Claude Code CLI ${claudeCheck.version}`));
51725
51737
  }
51726
51738
  console.log("");
51727
51739
  console.log(dim(" \uD83D\uDCD6 Need help creating a bot?"));
@@ -53034,7 +53046,11 @@ function formatRelativeTimeShort(date) {
53034
53046
  }
53035
53047
  function formatVersionString() {
53036
53048
  const claudeVersion = getClaudeCliVersion().version;
53037
- return claudeVersion ? `CT v${VERSION} · CC v${claudeVersion}` : `CT v${VERSION}`;
53049
+ if (!claudeVersion)
53050
+ return `CT v${VERSION}`;
53051
+ const status = classifyClaudeVersion(claudeVersion);
53052
+ const marker = status === "untested" ? " ⚠️ untested" : status === "incompatible" ? " ⚠️ unsupported" : "";
53053
+ return `CT v${VERSION} · CC v${claudeVersion}${marker}`;
53038
53054
  }
53039
53055
  function truncateAtWord(str2, maxLength) {
53040
53056
  if (str2.length <= maxLength)
@@ -77414,7 +77430,7 @@ var import_react61 = __toESM(require_react(), 1);
77414
77430
 
77415
77431
  // src/ui/components/Header.tsx
77416
77432
  var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
77417
- function Header({ version, workingDir, claudeVersion }) {
77433
+ function Header({ version, workingDir, claudeVersion, claudeStatus }) {
77418
77434
  return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
77419
77435
  borderStyle: "round",
77420
77436
  paddingX: 1,
@@ -77500,7 +77516,15 @@ function Header({ version, workingDir, claudeVersion }) {
77500
77516
  " | Claude ",
77501
77517
  claudeVersion
77502
77518
  ]
77503
- }, undefined, true, undefined, this)
77519
+ }, undefined, true, undefined, this),
77520
+ claudeStatus === "untested" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
77521
+ color: "yellow",
77522
+ children: " ⚠ untested"
77523
+ }, undefined, false, undefined, this),
77524
+ claudeStatus === "incompatible" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
77525
+ color: "yellow",
77526
+ children: " ⚠ unsupported"
77527
+ }, undefined, false, undefined, this)
77504
77528
  ]
77505
77529
  }, undefined, true, undefined, this)
77506
77530
  ]
@@ -81468,7 +81492,8 @@ function App2({ config, onStateReady, onResizeReady, onQuit, toggleCallbacks })
81468
81492
  const headerContent = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Header, {
81469
81493
  version: config.version,
81470
81494
  workingDir: config.workingDir,
81471
- claudeVersion: config.claudeVersion
81495
+ claudeVersion: config.claudeVersion,
81496
+ claudeStatus: config.claudeStatus
81472
81497
  }, undefined, false, undefined, this);
81473
81498
  const footerContent = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Footer, {
81474
81499
  ready: state.ready,
@@ -81856,7 +81881,8 @@ class HeadlessProvider {
81856
81881
  const { config } = this.options;
81857
81882
  this.log("HeadlessProvider", `claude-threads v${config.version} starting in headless mode`);
81858
81883
  this.log("HeadlessProvider", `Working directory: ${config.workingDir}`);
81859
- this.log("HeadlessProvider", `Claude CLI: ${config.claudeVersion}`);
81884
+ const cliMarker = config.claudeStatus === "untested" ? " ⚠️ untested (newer than the verified range)" : config.claudeStatus === "incompatible" ? " ⚠️ unsupported (version check bypassed)" : "";
81885
+ this.log("HeadlessProvider", `Claude CLI: ${config.claudeVersion}${cliMarker}`);
81860
81886
  }
81861
81887
  async stop() {
81862
81888
  this.log("HeadlessProvider", "Stopped");
@@ -83277,6 +83303,15 @@ async function startWithoutDaemon() {
83277
83303
  console.error("");
83278
83304
  process.exit(1);
83279
83305
  }
83306
+ if (claudeValidation.status === "untested") {
83307
+ console.error(yellow(` ⚠️ ${claudeValidation.message}`));
83308
+ console.error("");
83309
+ }
83310
+ if (!claudeValidation.compatible && opts.skipVersionCheck) {
83311
+ const prefix = claudeValidation.installed ? "running with an unsupported Claude CLI. " : "";
83312
+ console.error(yellow(` ⚠️ --skip-version-check: ${prefix}${claudeValidation.message}`));
83313
+ console.error("");
83314
+ }
83280
83315
  if (process.env.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB === "1") {
83281
83316
  const hasSkipPermissionPlatform = config.platforms.some((p) => p.skipPermissions === true);
83282
83317
  if (hasSkipPermissionPlatform) {
@@ -83311,7 +83346,7 @@ async function startWithoutDaemon() {
83311
83346
  version: VERSION,
83312
83347
  workingDir,
83313
83348
  claudeVersion: claudeValidation.version || "unknown",
83314
- claudeCompatible: claudeValidation.compatible,
83349
+ claudeStatus: claudeValidation.status,
83315
83350
  permissionMode: runtimeConfig.permissionMode,
83316
83351
  chromeEnabled: runtimeConfig.chromeEnabled,
83317
83352
  keepAliveEnabled: runtimeConfig.keepAliveEnabled
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.21.2",
3
+ "version": "1.22.0",
4
4
  "description": "Run Claude Code from Slack or Mattermost. Sessions stream live into threads where your whole team can watch and steer.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",