claude-threads 1.37.2 → 1.38.1

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.
@@ -12683,20 +12683,469 @@ var init_types = __esm(() => {
12683
12683
  REMOTE_KEYS = new Set(["type", "url", "headers"]);
12684
12684
  });
12685
12685
 
12686
- // src/utils/spawn.ts
12687
- import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "child_process";
12688
- function addWindowsShell(options) {
12689
- if (isWindows && options.shell === undefined) {
12690
- return { ...options, shell: true };
12686
+ // node_modules/isexe/windows.js
12687
+ var require_windows = __commonJS(function(exports, module) {
12688
+ module.exports = isexe;
12689
+ isexe.sync = sync;
12690
+ var fs = __require("fs");
12691
+ function checkPathExt(path, options) {
12692
+ var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
12693
+ if (!pathext) {
12694
+ return true;
12695
+ }
12696
+ pathext = pathext.split(";");
12697
+ if (pathext.indexOf("") !== -1) {
12698
+ return true;
12699
+ }
12700
+ for (var i = 0;i < pathext.length; i++) {
12701
+ var p = pathext[i].toLowerCase();
12702
+ if (p && path.substr(-p.length).toLowerCase() === p) {
12703
+ return true;
12704
+ }
12705
+ }
12706
+ return false;
12691
12707
  }
12692
- return options;
12693
- }
12708
+ function checkStat(stat, path, options) {
12709
+ if (!stat.isSymbolicLink() && !stat.isFile()) {
12710
+ return false;
12711
+ }
12712
+ return checkPathExt(path, options);
12713
+ }
12714
+ function isexe(path, options, cb) {
12715
+ fs.stat(path, function(er, stat) {
12716
+ cb(er, er ? false : checkStat(stat, path, options));
12717
+ });
12718
+ }
12719
+ function sync(path, options) {
12720
+ return checkStat(fs.statSync(path), path, options);
12721
+ }
12722
+ });
12723
+
12724
+ // node_modules/isexe/mode.js
12725
+ var require_mode = __commonJS(function(exports, module) {
12726
+ module.exports = isexe;
12727
+ isexe.sync = sync;
12728
+ var fs = __require("fs");
12729
+ function isexe(path, options, cb) {
12730
+ fs.stat(path, function(er, stat) {
12731
+ cb(er, er ? false : checkStat(stat, options));
12732
+ });
12733
+ }
12734
+ function sync(path, options) {
12735
+ return checkStat(fs.statSync(path), options);
12736
+ }
12737
+ function checkStat(stat, options) {
12738
+ return stat.isFile() && checkMode(stat, options);
12739
+ }
12740
+ function checkMode(stat, options) {
12741
+ var mod = stat.mode;
12742
+ var uid = stat.uid;
12743
+ var gid = stat.gid;
12744
+ var myUid = options.uid !== undefined ? options.uid : process.getuid && process.getuid();
12745
+ var myGid = options.gid !== undefined ? options.gid : process.getgid && process.getgid();
12746
+ var u = parseInt("100", 8);
12747
+ var g = parseInt("010", 8);
12748
+ var o = parseInt("001", 8);
12749
+ var ug = u | g;
12750
+ var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
12751
+ return ret;
12752
+ }
12753
+ });
12754
+
12755
+ // node_modules/isexe/index.js
12756
+ var require_isexe = __commonJS(function(exports, module) {
12757
+ var fs = __require("fs");
12758
+ var core;
12759
+ if (process.platform === "win32" || global.TESTING_WINDOWS) {
12760
+ core = require_windows();
12761
+ } else {
12762
+ core = require_mode();
12763
+ }
12764
+ module.exports = isexe;
12765
+ isexe.sync = sync;
12766
+ function isexe(path, options, cb) {
12767
+ if (typeof options === "function") {
12768
+ cb = options;
12769
+ options = {};
12770
+ }
12771
+ if (!cb) {
12772
+ if (typeof Promise !== "function") {
12773
+ throw new TypeError("callback not provided");
12774
+ }
12775
+ return new Promise(function(resolve, reject) {
12776
+ isexe(path, options || {}, function(er, is) {
12777
+ if (er) {
12778
+ reject(er);
12779
+ } else {
12780
+ resolve(is);
12781
+ }
12782
+ });
12783
+ });
12784
+ }
12785
+ core(path, options || {}, function(er, is) {
12786
+ if (er) {
12787
+ if (er.code === "EACCES" || options && options.ignoreErrors) {
12788
+ er = null;
12789
+ is = false;
12790
+ }
12791
+ }
12792
+ cb(er, is);
12793
+ });
12794
+ }
12795
+ function sync(path, options) {
12796
+ try {
12797
+ return core.sync(path, options || {});
12798
+ } catch (er) {
12799
+ if (options && options.ignoreErrors || er.code === "EACCES") {
12800
+ return false;
12801
+ } else {
12802
+ throw er;
12803
+ }
12804
+ }
12805
+ }
12806
+ });
12807
+
12808
+ // node_modules/which/which.js
12809
+ var require_which = __commonJS(function(exports, module) {
12810
+ var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
12811
+ var path = __require("path");
12812
+ var COLON = isWindows ? ";" : ":";
12813
+ var isexe = require_isexe();
12814
+ var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
12815
+ var getPathInfo = (cmd, opt) => {
12816
+ const colon = opt.colon || COLON;
12817
+ const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
12818
+ ...isWindows ? [process.cwd()] : [],
12819
+ ...(opt.path || process.env.PATH || "").split(colon)
12820
+ ];
12821
+ const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
12822
+ const pathExt = isWindows ? pathExtExe.split(colon) : [""];
12823
+ if (isWindows) {
12824
+ if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
12825
+ pathExt.unshift("");
12826
+ }
12827
+ return {
12828
+ pathEnv,
12829
+ pathExt,
12830
+ pathExtExe
12831
+ };
12832
+ };
12833
+ var which = (cmd, opt, cb) => {
12834
+ if (typeof opt === "function") {
12835
+ cb = opt;
12836
+ opt = {};
12837
+ }
12838
+ if (!opt)
12839
+ opt = {};
12840
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
12841
+ const found = [];
12842
+ const step = (i) => new Promise((resolve, reject) => {
12843
+ if (i === pathEnv.length)
12844
+ return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
12845
+ const ppRaw = pathEnv[i];
12846
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
12847
+ const pCmd = path.join(pathPart, cmd);
12848
+ const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
12849
+ resolve(subStep(p, i, 0));
12850
+ });
12851
+ const subStep = (p, i, ii) => new Promise((resolve, reject) => {
12852
+ if (ii === pathExt.length)
12853
+ return resolve(step(i + 1));
12854
+ const ext = pathExt[ii];
12855
+ isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
12856
+ if (!er && is) {
12857
+ if (opt.all)
12858
+ found.push(p + ext);
12859
+ else
12860
+ return resolve(p + ext);
12861
+ }
12862
+ return resolve(subStep(p, i, ii + 1));
12863
+ });
12864
+ });
12865
+ return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
12866
+ };
12867
+ var whichSync = (cmd, opt) => {
12868
+ opt = opt || {};
12869
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
12870
+ const found = [];
12871
+ for (let i = 0;i < pathEnv.length; i++) {
12872
+ const ppRaw = pathEnv[i];
12873
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
12874
+ const pCmd = path.join(pathPart, cmd);
12875
+ const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
12876
+ for (let j = 0;j < pathExt.length; j++) {
12877
+ const cur = p + pathExt[j];
12878
+ try {
12879
+ const is = isexe.sync(cur, { pathExt: pathExtExe });
12880
+ if (is) {
12881
+ if (opt.all)
12882
+ found.push(cur);
12883
+ else
12884
+ return cur;
12885
+ }
12886
+ } catch (ex) {}
12887
+ }
12888
+ }
12889
+ if (opt.all && found.length)
12890
+ return found;
12891
+ if (opt.nothrow)
12892
+ return null;
12893
+ throw getNotFoundError(cmd);
12894
+ };
12895
+ module.exports = which;
12896
+ which.sync = whichSync;
12897
+ });
12898
+
12899
+ // node_modules/path-key/index.js
12900
+ var require_path_key = __commonJS(function(exports, module) {
12901
+ var pathKey = (options = {}) => {
12902
+ const environment = options.env || process.env;
12903
+ const platform = options.platform || process.platform;
12904
+ if (platform !== "win32") {
12905
+ return "PATH";
12906
+ }
12907
+ return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
12908
+ };
12909
+ module.exports = pathKey;
12910
+ module.exports.default = pathKey;
12911
+ });
12912
+
12913
+ // node_modules/cross-spawn/lib/util/resolveCommand.js
12914
+ var require_resolveCommand = __commonJS(function(exports, module) {
12915
+ var path = __require("path");
12916
+ var which = require_which();
12917
+ var getPathKey = require_path_key();
12918
+ function resolveCommandAttempt(parsed, withoutPathExt) {
12919
+ const env = parsed.options.env || process.env;
12920
+ const cwd = process.cwd();
12921
+ const hasCustomCwd = parsed.options.cwd != null;
12922
+ const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
12923
+ if (shouldSwitchCwd) {
12924
+ try {
12925
+ process.chdir(parsed.options.cwd);
12926
+ } catch (err) {}
12927
+ }
12928
+ let resolved;
12929
+ try {
12930
+ resolved = which.sync(parsed.command, {
12931
+ path: env[getPathKey({ env })],
12932
+ pathExt: withoutPathExt ? path.delimiter : undefined
12933
+ });
12934
+ } catch (e) {} finally {
12935
+ if (shouldSwitchCwd) {
12936
+ process.chdir(cwd);
12937
+ }
12938
+ }
12939
+ if (resolved) {
12940
+ resolved = path.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
12941
+ }
12942
+ return resolved;
12943
+ }
12944
+ function resolveCommand(parsed) {
12945
+ return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
12946
+ }
12947
+ module.exports = resolveCommand;
12948
+ });
12949
+
12950
+ // node_modules/cross-spawn/lib/util/escape.js
12951
+ var require_escape = __commonJS(function(exports, module) {
12952
+ var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
12953
+ function escapeCommand(arg) {
12954
+ arg = arg.replace(metaCharsRegExp, "^$1");
12955
+ return arg;
12956
+ }
12957
+ function escapeArgument(arg, doubleEscapeMetaChars) {
12958
+ arg = `${arg}`;
12959
+ arg = arg.replace(/(?=(\\+?)?)\1"/g, "$1$1\\\"");
12960
+ arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
12961
+ arg = `"${arg}"`;
12962
+ arg = arg.replace(metaCharsRegExp, "^$1");
12963
+ if (doubleEscapeMetaChars) {
12964
+ arg = arg.replace(metaCharsRegExp, "^$1");
12965
+ }
12966
+ return arg;
12967
+ }
12968
+ exports.command = escapeCommand;
12969
+ exports.argument = escapeArgument;
12970
+ });
12971
+
12972
+ // node_modules/shebang-regex/index.js
12973
+ var require_shebang_regex = __commonJS(function(exports, module) {
12974
+ module.exports = /^#!(.*)/;
12975
+ });
12976
+
12977
+ // node_modules/shebang-command/index.js
12978
+ var require_shebang_command = __commonJS(function(exports, module) {
12979
+ var shebangRegex = require_shebang_regex();
12980
+ module.exports = (string = "") => {
12981
+ const match = string.match(shebangRegex);
12982
+ if (!match) {
12983
+ return null;
12984
+ }
12985
+ const [path, argument] = match[0].replace(/#! ?/, "").split(" ");
12986
+ const binary = path.split("/").pop();
12987
+ if (binary === "env") {
12988
+ return argument;
12989
+ }
12990
+ return argument ? `${binary} ${argument}` : binary;
12991
+ };
12992
+ });
12993
+
12994
+ // node_modules/cross-spawn/lib/util/readShebang.js
12995
+ var require_readShebang = __commonJS(function(exports, module) {
12996
+ var fs = __require("fs");
12997
+ var shebangCommand = require_shebang_command();
12998
+ function readShebang(command) {
12999
+ const size = 150;
13000
+ const buffer = Buffer.alloc(size);
13001
+ let fd;
13002
+ try {
13003
+ fd = fs.openSync(command, "r");
13004
+ fs.readSync(fd, buffer, 0, size, 0);
13005
+ fs.closeSync(fd);
13006
+ } catch (e) {}
13007
+ return shebangCommand(buffer.toString());
13008
+ }
13009
+ module.exports = readShebang;
13010
+ });
13011
+
13012
+ // node_modules/cross-spawn/lib/parse.js
13013
+ var require_parse = __commonJS(function(exports, module) {
13014
+ var path = __require("path");
13015
+ var resolveCommand = require_resolveCommand();
13016
+ var escape = require_escape();
13017
+ var readShebang = require_readShebang();
13018
+ var isWin = process.platform === "win32";
13019
+ var isExecutableRegExp = /\.(?:com|exe)$/i;
13020
+ var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
13021
+ function detectShebang(parsed) {
13022
+ parsed.file = resolveCommand(parsed);
13023
+ const shebang = parsed.file && readShebang(parsed.file);
13024
+ if (shebang) {
13025
+ parsed.args.unshift(parsed.file);
13026
+ parsed.command = shebang;
13027
+ return resolveCommand(parsed);
13028
+ }
13029
+ return parsed.file;
13030
+ }
13031
+ function parseNonShell(parsed) {
13032
+ if (!isWin) {
13033
+ return parsed;
13034
+ }
13035
+ const commandFile = detectShebang(parsed);
13036
+ const needsShell = !isExecutableRegExp.test(commandFile);
13037
+ if (parsed.options.forceShell || needsShell) {
13038
+ const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
13039
+ parsed.command = path.normalize(parsed.command);
13040
+ parsed.command = escape.command(parsed.command);
13041
+ parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
13042
+ const shellCommand = [parsed.command].concat(parsed.args).join(" ");
13043
+ parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
13044
+ parsed.command = process.env.comspec || "cmd.exe";
13045
+ parsed.options.windowsVerbatimArguments = true;
13046
+ }
13047
+ return parsed;
13048
+ }
13049
+ function parse(command, args, options) {
13050
+ if (args && !Array.isArray(args)) {
13051
+ options = args;
13052
+ args = null;
13053
+ }
13054
+ args = args ? args.slice(0) : [];
13055
+ options = Object.assign({}, options);
13056
+ const parsed = {
13057
+ command,
13058
+ args,
13059
+ options,
13060
+ file: undefined,
13061
+ original: {
13062
+ command,
13063
+ args
13064
+ }
13065
+ };
13066
+ return options.shell ? parsed : parseNonShell(parsed);
13067
+ }
13068
+ module.exports = parse;
13069
+ });
13070
+
13071
+ // node_modules/cross-spawn/lib/enoent.js
13072
+ var require_enoent = __commonJS(function(exports, module) {
13073
+ var isWin = process.platform === "win32";
13074
+ function notFoundError(original, syscall) {
13075
+ return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
13076
+ code: "ENOENT",
13077
+ errno: "ENOENT",
13078
+ syscall: `${syscall} ${original.command}`,
13079
+ path: original.command,
13080
+ spawnargs: original.args
13081
+ });
13082
+ }
13083
+ function hookChildProcess(cp, parsed) {
13084
+ if (!isWin) {
13085
+ return;
13086
+ }
13087
+ const originalEmit = cp.emit;
13088
+ cp.emit = function(name, arg1) {
13089
+ if (name === "exit") {
13090
+ const err = verifyENOENT(arg1, parsed);
13091
+ if (err) {
13092
+ return originalEmit.call(cp, "error", err);
13093
+ }
13094
+ }
13095
+ return originalEmit.apply(cp, arguments);
13096
+ };
13097
+ }
13098
+ function verifyENOENT(status, parsed) {
13099
+ if (isWin && status === 1 && !parsed.file) {
13100
+ return notFoundError(parsed.original, "spawn");
13101
+ }
13102
+ return null;
13103
+ }
13104
+ function verifyENOENTSync(status, parsed) {
13105
+ if (isWin && status === 1 && !parsed.file) {
13106
+ return notFoundError(parsed.original, "spawnSync");
13107
+ }
13108
+ return null;
13109
+ }
13110
+ module.exports = {
13111
+ hookChildProcess,
13112
+ verifyENOENT,
13113
+ verifyENOENTSync,
13114
+ notFoundError
13115
+ };
13116
+ });
13117
+
13118
+ // node_modules/cross-spawn/index.js
13119
+ var require_cross_spawn = __commonJS(function(exports, module) {
13120
+ var cp = __require("child_process");
13121
+ var parse = require_parse();
13122
+ var enoent = require_enoent();
13123
+ function spawn(command, args, options) {
13124
+ const parsed = parse(command, args, options);
13125
+ const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
13126
+ enoent.hookChildProcess(spawned, parsed);
13127
+ return spawned;
13128
+ }
13129
+ function spawnSync(command, args, options) {
13130
+ const parsed = parse(command, args, options);
13131
+ const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
13132
+ result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
13133
+ return result;
13134
+ }
13135
+ module.exports = spawn;
13136
+ module.exports.spawn = spawn;
13137
+ module.exports.sync = spawnSync;
13138
+ module.exports._parse = parse;
13139
+ module.exports._enoent = enoent;
13140
+ });
13141
+
13142
+ // src/utils/spawn.ts
12694
13143
  function crossSpawn(command, args, options) {
12695
- return nodeSpawn(command, args, addWindowsShell(options ?? {}));
13144
+ return import_cross_spawn.default(command, args, options ?? {});
12696
13145
  }
12697
- var isWindows;
13146
+ var import_cross_spawn;
12698
13147
  var init_spawn = __esm(() => {
12699
- isWindows = process.platform === "win32";
13148
+ import_cross_spawn = __toESM(require_cross_spawn(), 1);
12700
13149
  });
12701
13150
 
12702
13151
  // src/utils/logger.ts
@@ -13210,7 +13659,7 @@ var require_semver = __commonJS(function(exports, module) {
13210
13659
  });
13211
13660
 
13212
13661
  // node_modules/semver/functions/parse.js
13213
- var require_parse = __commonJS(function(exports, module) {
13662
+ var require_parse2 = __commonJS(function(exports, module) {
13214
13663
  var SemVer = require_semver();
13215
13664
  var parse = (version, options, throwErrors = false) => {
13216
13665
  if (version instanceof SemVer) {
@@ -13230,7 +13679,7 @@ var require_parse = __commonJS(function(exports, module) {
13230
13679
 
13231
13680
  // node_modules/semver/functions/valid.js
13232
13681
  var require_valid = __commonJS(function(exports, module) {
13233
- var parse = require_parse();
13682
+ var parse = require_parse2();
13234
13683
  var valid = (version, options) => {
13235
13684
  const v = parse(version, options);
13236
13685
  return v ? v.version : null;
@@ -13240,7 +13689,7 @@ var require_valid = __commonJS(function(exports, module) {
13240
13689
 
13241
13690
  // node_modules/semver/functions/clean.js
13242
13691
  var require_clean = __commonJS(function(exports, module) {
13243
- var parse = require_parse();
13692
+ var parse = require_parse2();
13244
13693
  var clean = (version, options) => {
13245
13694
  const s = parse(version.trim().replace(/^[=v]+/, ""), options);
13246
13695
  return s ? s.version : null;
@@ -13268,7 +13717,7 @@ var require_inc = __commonJS(function(exports, module) {
13268
13717
 
13269
13718
  // node_modules/semver/functions/diff.js
13270
13719
  var require_diff = __commonJS(function(exports, module) {
13271
- var parse = require_parse();
13720
+ var parse = require_parse2();
13272
13721
  var diff = (version1, version2) => {
13273
13722
  const v1 = parse(version1, null, true);
13274
13723
  const v2 = parse(version2, null, true);
@@ -13330,7 +13779,7 @@ var require_patch = __commonJS(function(exports, module) {
13330
13779
 
13331
13780
  // node_modules/semver/functions/prerelease.js
13332
13781
  var require_prerelease = __commonJS(function(exports, module) {
13333
- var parse = require_parse();
13782
+ var parse = require_parse2();
13334
13783
  var prerelease = (version, options) => {
13335
13784
  const parsed = parse(version, options);
13336
13785
  return parsed && parsed.prerelease.length ? parsed.prerelease : null;
@@ -13476,7 +13925,7 @@ var require_cmp = __commonJS(function(exports, module) {
13476
13925
  // node_modules/semver/functions/coerce.js
13477
13926
  var require_coerce = __commonJS(function(exports, module) {
13478
13927
  var SemVer = require_semver();
13479
- var parse = require_parse();
13928
+ var parse = require_parse2();
13480
13929
  var { safeRe: re, t } = require_re();
13481
13930
  var coerce = (version, options) => {
13482
13931
  if (version instanceof SemVer) {
@@ -13518,7 +13967,7 @@ var require_coerce = __commonJS(function(exports, module) {
13518
13967
 
13519
13968
  // node_modules/semver/functions/truncate.js
13520
13969
  var require_truncate = __commonJS(function(exports, module) {
13521
- var parse = require_parse();
13970
+ var parse = require_parse2();
13522
13971
  var constants = require_constants();
13523
13972
  var SemVer = require_semver();
13524
13973
  var truncate = (version, truncation, options) => {
@@ -14526,7 +14975,7 @@ var require_semver2 = __commonJS(function(exports, module) {
14526
14975
  var constants = require_constants();
14527
14976
  var SemVer = require_semver();
14528
14977
  var identifiers = require_identifiers();
14529
- var parse = require_parse();
14978
+ var parse = require_parse2();
14530
14979
  var valid = require_valid();
14531
14980
  var clean = require_clean();
14532
14981
  var inc = require_inc();
@@ -169,6 +169,7 @@ What happens: every `audio/*` attachment (or a file with an audio extension when
169
169
  | `permissionMode` | No | How tool-use is gated: `default` / `auto` / `bypass` (default: `default`). See [Permission Modes](#permission-modes). |
170
170
  | `skipPermissions` | No | **Deprecated.** Use `permissionMode`. `true` maps to `bypass`, `false` to `default`. `permissionMode` wins when both are set. |
171
171
  | `outboundFiles` | No | `send_file` settings: `{ enabled, maxBytes }` (defaults: enabled `true`, `maxBytes` 100 MB) |
172
+ | `mode` | No | Presentation preset: the baseline for `sessionHeader`, `stickyMessage` and `lifecycle`. `full` (default) is the behaviour described below; `assistant` hides all three, so Claude's reply is the whole thread. Any of those three fields set explicitly wins over the preset, so `mode: assistant` with `sessionHeader: full` is valid. `turnMarker` is machine-facing and deliberately not part of the preset. |
172
173
  | `sessionHeader` | No | Per-thread header visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no header post) |
173
174
  | `stickyMessage` | No | Channel sticky visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no sticky, no bumping) |
174
175
  | `lifecycle` | No | Session status posts — idle warning, timeout, pause, resume, and the shutdown notice a deploy leaves in each open thread: `full` (default, all of them) / `minimal` (drops the idle warning, which predicts a timeout the next message would undo anyway) / `hidden` (none). Editing a status post the thread already has is not suppressed at any level: it adds no post and no notification, and leaving a stale "session idle" up across a restart would be worse. ⚠️ An **abnormal exit** (`[Exited: <code>]`, non-zero only) posts at every level including `hidden`: it is a failure report, and silencing it would make a session that died look exactly like one that finished. Note that `hidden` also removes the post a 🔄 reaction resumes from — sending a message in the thread still resumes it, and the channel sticky says so. |
@@ -194,6 +195,7 @@ What happens: every `audio/*` attachment (or a file with an audio extension when
194
195
  | `permissionMode` | No | How tool-use is gated: `default` / `auto` / `bypass` (default: `default`). See [Permission Modes](#permission-modes). |
195
196
  | `skipPermissions` | No | **Deprecated.** Use `permissionMode`. `true` maps to `bypass`, `false` to `default`. `permissionMode` wins when both are set. |
196
197
  | `outboundFiles` | No | `send_file` settings: `{ enabled, maxBytes }` (defaults: enabled `true`, `maxBytes` 100 MB) |
198
+ | `mode` | No | Presentation preset: the baseline for `sessionHeader`, `stickyMessage` and `lifecycle`. `full` (default) is the behaviour described below; `assistant` hides all three, so Claude's reply is the whole thread. Any of those three fields set explicitly wins over the preset, so `mode: assistant` with `sessionHeader: full` is valid. `turnMarker` is machine-facing and deliberately not part of the preset. |
197
199
  | `sessionHeader` | No | Per-thread header visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no header post) |
198
200
  | `stickyMessage` | No | Channel sticky visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no sticky, no bumping) |
199
201
  | `lifecycle` | No | Session status posts — idle warning, timeout, pause, resume, and the shutdown notice a deploy leaves in each open thread: `full` (default, all of them) / `minimal` (drops the idle warning, which predicts a timeout the next message would undo anyway) / `hidden` (none). Editing a status post the thread already has is not suppressed at any level: it adds no post and no notification, and leaving a stale "session idle" up across a restart would be worse. ⚠️ An **abnormal exit** (`[Exited: <code>]`, non-zero only) posts at every level including `hidden`: it is a failure report, and silencing it would make a session that died look exactly like one that finished. Note that `hidden` also removes the post a 🔄 reaction resumes from — sending a message in the thread still resumes it, and the channel sticky says so. |
@@ -203,6 +205,56 @@ What happens: every `audio/*` attachment (or a file with an audio extension when
203
205
  | `reconnectPolicy` | No | What happens when reconnection attempts run out: `retry` (default — log, cool down 60s, reset the counter and keep trying; recovers with no supervisor) or `exit` (leave through the graceful shutdown path and exit non-zero, for `Restart=always` deployments). The bot never stays alive with a dead socket either way. |
204
206
  | `auditLog` | No | Append-only audit trail of what the bot executed for this platform — tool calls (incl. subagents), session lifecycle, security-relevant commands, plan approvals. One JSONL stream per platform under `~/.claude-threads/audit/` (override: `CLAUDE_THREADS_AUDIT_DIR`), files `0600`. The bot never deletes it — rotation/retention is the operator's job (logrotate, SIEM ingestion). See [Audit log](#audit-log). Default off. |
205
207
 
208
+ ### Presentation presets (`mode`)
209
+
210
+ A platform entry carries three fields that decide how much of the bot's own
211
+ scaffolding a channel sees: `sessionHeader`, `stickyMessage` and `lifecycle`.
212
+ They are useful separately, but almost nobody wants to tune them one by one.
213
+ Two deployments asked for the same combination in nearly the same words: the
214
+ reply, and nothing else.
215
+
216
+ `mode` names that combination.
217
+
218
+ ```yaml
219
+ platforms:
220
+ - id: assistant-channel
221
+ type: slack
222
+ mode: assistant # no header, no sticky, no lifecycle notices
223
+ ```
224
+
225
+ | Preset | `sessionHeader` | `stickyMessage` | `lifecycle` |
226
+ |--------|-----------------|-----------------|-------------|
227
+ | `full` (default) | `full` | `full` | `full` |
228
+ | `assistant` | `hidden` | `hidden` | `hidden` |
229
+
230
+ A field set explicitly always wins over the preset, so you can start from a
231
+ preset and keep one thing:
232
+
233
+ ```yaml
234
+ mode: assistant
235
+ sessionHeader: full # replies only, but keep the per-thread header
236
+ ```
237
+
238
+ One caveat worth knowing if you ran the setup wizard. It writes `sessionHeader`
239
+ and `stickyMessage` into your config whenever your answer differed from the
240
+ default, and those are explicit fields, so they win. Adding `mode: assistant`
241
+ to such a config moves `lifecycle` and leaves the other two where the wizard
242
+ put them. Startup warns and names the fields when that happens; remove them to
243
+ let the preset apply.
244
+
245
+ Two more things worth knowing:
246
+
247
+ - The preset is expanded when the config loads, so everything downstream reads
248
+ the same three concrete values it always did. Omitting `mode` resolves to
249
+ exactly the old defaults, which means an existing config behaves identically.
250
+ - `turnMarker` is **not** part of any preset. It is a signal for integrations
251
+ reading the channel rather than something a human sees, so it is not
252
+ something you would switch off because you want a quieter channel.
253
+
254
+ An abnormal exit is still reported under `mode: assistant`, for the reason
255
+ given in the `lifecycle` row above: a session that died must not look like one
256
+ that finished.
257
+
206
258
  ### Direct Channel Mode
207
259
 
208
260
  `directChannelMode: true` turns the configured channel into a single, always-on conversation with the bot:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.37.2",
3
+ "version": "1.38.1",
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",
@@ -75,6 +75,7 @@
75
75
  "@redactpii/node": "^1.0.16",
76
76
  "cli-spinners": "^3.3.0",
77
77
  "commander": "^14.0.2",
78
+ "cross-spawn": "^7.0.6",
78
79
  "diff": "^8.0.3",
79
80
  "express-rate-limit": "^8.3.0",
80
81
  "hono": "4.13.7",
@@ -91,6 +92,7 @@
91
92
  "devDependencies": {
92
93
  "@eslint/js": "^10.0.1",
93
94
  "@types/bun": "latest",
95
+ "@types/cross-spawn": "^6.0.6",
94
96
  "@types/js-yaml": "^4.0.9",
95
97
  "@types/node": "^26.1.1",
96
98
  "@types/prompts": "^2.4.9",