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.
- package/CHANGELOG.md +14 -1
- package/README.md +1 -1
- package/bin/claude-threads-daemon +7 -6
- package/dist/index.js +610 -58
- package/dist/mcp/mcp-server.js +467 -18
- package/docs/CONFIGURATION.md +52 -0
- package/package.json +3 -1
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -12683,20 +12683,469 @@ var init_types = __esm(() => {
|
|
|
12683
12683
|
REMOTE_KEYS = new Set(["type", "url", "headers"]);
|
|
12684
12684
|
});
|
|
12685
12685
|
|
|
12686
|
-
//
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
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
|
-
|
|
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
|
|
13144
|
+
return import_cross_spawn.default(command, args, options ?? {});
|
|
12696
13145
|
}
|
|
12697
|
-
var
|
|
13146
|
+
var import_cross_spawn;
|
|
12698
13147
|
var init_spawn = __esm(() => {
|
|
12699
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
14978
|
+
var parse = require_parse2();
|
|
14530
14979
|
var valid = require_valid();
|
|
14531
14980
|
var clean = require_clean();
|
|
14532
14981
|
var inc = require_inc();
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -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.
|
|
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",
|