claude-threads 1.30.0 → 1.30.2

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,16 @@ 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.30.2] - 2026-08-29
9
+
10
+ ### Changed
11
+ - **Latest verified Claude CLI: 2.1.251** (from 2.1.226). The full verification battery ran against it: all 17 reference event streams re-captured (`tests/integration/fixtures/real-cli-captures/`), structural dialect diff against the 2.1.226 captures, and the decision-bridge e2e. Dialect drift found and verified benign: a new top-level `autocompact_state` event and a new `system/task_summary` subtype (both ignored by the bot), and the post-compact `user` echo events are no longer emitted (the bot never consumed them). Deployments on current CLIs no longer show the "⚠️ untested" warning.
12
+
13
+ ## [1.30.1] - 2026-08-28
14
+
15
+ ### Security
16
+ - **The card-injection guard now also covers the haiku-parsed `!watch`/`!routine` paths and the store-level gates.** 1.30.0 collapsed watch *keywords*; model-authored names, conditions and prompts from the natural-language parsers — and the stores' own name/condition normalization, the gate no caller can bypass — now go through the same shared `singleLine` helper (`utils/format.ts`), which replaces the two inline copies of the whitespace-collapse regex.
17
+
8
18
  ## [1.30.0] - 2026-08-28
9
19
 
10
20
  ### Added
package/dist/index.js CHANGED
@@ -4221,7 +4221,7 @@ function validateClaudeCli() {
4221
4221
  rawOutput: result.rawOutput ?? undefined
4222
4222
  };
4223
4223
  }
4224
- var import_semver, COMMON_CLAUDE_PATHS, CLAUDE_CLI_MIN_VERSION = "2.0.74", CLAUDE_CLI_VERIFIED_RANGE = ">=2.0.74 <2.2.0", CLAUDE_CLI_SUPPORTED_MAJOR = 2, CLAUDE_CLI_LATEST_VERIFIED = "2.1.226", discoveredClaudePath = null;
4224
+ var import_semver, COMMON_CLAUDE_PATHS, CLAUDE_CLI_MIN_VERSION = "2.0.74", CLAUDE_CLI_VERIFIED_RANGE = ">=2.0.74 <2.2.0", CLAUDE_CLI_SUPPORTED_MAJOR = 2, CLAUDE_CLI_LATEST_VERIFIED = "2.1.251", discoveredClaudePath = null;
4225
4225
  var init_version_check = __esm(() => {
4226
4226
  import_semver = __toESM(require_semver2(), 1);
4227
4227
  COMMON_CLAUDE_PATHS = process.platform === "win32" ? [
@@ -54578,6 +54578,9 @@ function truncateAtWord(str2, maxLength) {
54578
54578
  }
54579
54579
  return truncated + "…";
54580
54580
  }
54581
+ function singleLine(text) {
54582
+ return text.replace(/[\s\u0085]+/g, " ").trim();
54583
+ }
54581
54584
 
54582
54585
  // src/utils/error-handler/index.ts
54583
54586
  var log7 = createLogger("error");
@@ -64908,7 +64911,7 @@ class RoutinesStore extends PlatformListStore {
64908
64911
  const scheduleError = validateSchedule(routine.schedule);
64909
64912
  if (scheduleError)
64910
64913
  return scheduleError;
64911
- const name = routine.name.trim().slice(0, 80);
64914
+ const name = singleLine(routine.name).slice(0, 80);
64912
64915
  const prompt = routine.prompt.trim().slice(0, 2000);
64913
64916
  if (!name || !prompt)
64914
64917
  return "name and prompt are required";
@@ -64988,8 +64991,8 @@ function validateParsedRoutine(raw, defaultTimezone) {
64988
64991
  if (typeof raw.error === "string" && raw.error) {
64989
64992
  return { ok: false, error: raw.error };
64990
64993
  }
64991
- const name = typeof raw.name === "string" ? raw.name.trim() : "";
64992
- const prompt = typeof raw.prompt === "string" ? raw.prompt.trim() : "";
64994
+ const name = typeof raw.name === "string" ? singleLine(raw.name) : "";
64995
+ const prompt = typeof raw.prompt === "string" ? singleLine(raw.prompt) : "";
64993
64996
  const preset = raw.preset;
64994
64997
  if (!name)
64995
64998
  return { ok: false, error: "could not derive a routine name" };
@@ -65038,7 +65041,7 @@ var MAX_KEYWORD_LENGTH = 60;
65038
65041
  function validateKeywords(raw) {
65039
65042
  if (!Array.isArray(raw))
65040
65043
  return "keywords must be a list";
65041
- const cleaned = [...new Set(raw.filter((k) => typeof k === "string").map((k) => k.replace(/[\s\u0085]+/g, " ").trim().toLowerCase()).filter((k) => k.length > 0 && k.length <= MAX_KEYWORD_LENGTH))];
65044
+ const cleaned = [...new Set(raw.filter((k) => typeof k === "string").map((k) => singleLine(k).toLowerCase()).filter((k) => k.length > 0 && k.length <= MAX_KEYWORD_LENGTH))];
65042
65045
  if (cleaned.length < MIN_KEYWORDS)
65043
65046
  return "at least one usable keyword is required";
65044
65047
  return cleaned.slice(0, MAX_KEYWORDS);
@@ -65051,7 +65054,7 @@ class WatchesStore extends PlatformListStore {
65051
65054
  applyItemDefaults(w) {
65052
65055
  w.enabled = w.enabled ?? true;
65053
65056
  w.consecutiveFailures = w.consecutiveFailures ?? 0;
65054
- w.keywords = Array.isArray(w.keywords) ? w.keywords.filter((k) => typeof k === "string").map((k) => k.replace(/[\s\u0085]+/g, " ").trim().toLowerCase()).filter((k) => k.length > 0) : [];
65057
+ w.keywords = Array.isArray(w.keywords) ? w.keywords.filter((k) => typeof k === "string").map((k) => singleLine(k).toLowerCase()).filter((k) => k.length > 0) : [];
65055
65058
  }
65056
65059
  warn(message) {
65057
65060
  log20.warn(message);
@@ -65061,8 +65064,8 @@ class WatchesStore extends PlatformListStore {
65061
65064
  }
65062
65065
  async add(platformId, watch, maxWatches = DEFAULT_MAX_WATCHES) {
65063
65066
  const result = await this.addItem(platformId, maxWatches, "watch", () => {
65064
- const name = watch.name.trim().slice(0, 80);
65065
- const condition = watch.condition.trim().slice(0, 500);
65067
+ const name = singleLine(watch.name).slice(0, 80);
65068
+ const condition = singleLine(watch.condition).slice(0, 500);
65066
65069
  const prompt = watch.prompt.trim().slice(0, 2000);
65067
65070
  if (!name || !condition || !prompt)
65068
65071
  return "name, condition and prompt are required";
@@ -65112,9 +65115,9 @@ function validateParsedWatch(raw) {
65112
65115
  if (typeof raw.error === "string" && raw.error) {
65113
65116
  return { ok: false, error: raw.error };
65114
65117
  }
65115
- const name = typeof raw.name === "string" ? raw.name.trim() : "";
65116
- const condition = typeof raw.condition === "string" ? raw.condition.trim() : "";
65117
- const prompt = typeof raw.prompt === "string" ? raw.prompt.trim() : "";
65118
+ const name = typeof raw.name === "string" ? singleLine(raw.name) : "";
65119
+ const condition = typeof raw.condition === "string" ? singleLine(raw.condition) : "";
65120
+ const prompt = typeof raw.prompt === "string" ? singleLine(raw.prompt) : "";
65118
65121
  if (!name || !condition || !prompt) {
65119
65122
  return { ok: false, error: "could not extract a name, condition and task from the request" };
65120
65123
  }
@@ -68055,9 +68058,6 @@ function refuseProposal(session, ctx, flavor) {
68055
68058
  return null;
68056
68059
  }
68057
68060
  var PROPOSED = "proposed_awaiting_human_approval";
68058
- function singleLine(text) {
68059
- return text.replace(/[\s\u0085]+/g, " ").trim();
68060
- }
68061
68061
  async function proposeRoutine(session, ctx, input, signal) {
68062
68062
  const refusal = refuseProposal(session, ctx, "routines");
68063
68063
  if (refusal)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.30.0",
3
+ "version": "1.30.2",
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",