claude-threads 1.24.2 → 1.25.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.
@@ -15725,7 +15725,7 @@ var require_websocket = __commonJS((exports, module) => {
15725
15725
  var http = __require("http");
15726
15726
  var net = __require("net");
15727
15727
  var tls = __require("tls");
15728
- var { randomBytes, createHash } = __require("crypto");
15728
+ var { randomBytes, createHash: createHash2 } = __require("crypto");
15729
15729
  var { Duplex, Readable } = __require("stream");
15730
15730
  var { URL: URL2 } = __require("url");
15731
15731
  var PerMessageDeflate = require_permessage_deflate();
@@ -16268,7 +16268,7 @@ var require_websocket = __commonJS((exports, module) => {
16268
16268
  abortHandshake(websocket, socket, "Invalid Upgrade header");
16269
16269
  return;
16270
16270
  }
16271
- const digest = createHash("sha1").update(key + GUID).digest("base64");
16271
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
16272
16272
  if (res.headers["sec-websocket-accept"] !== digest) {
16273
16273
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
16274
16274
  return;
@@ -16643,7 +16643,7 @@ var require_websocket_server = __commonJS((exports, module) => {
16643
16643
  var EventEmitter3 = __require("events");
16644
16644
  var http = __require("http");
16645
16645
  var { Duplex } = __require("stream");
16646
- var { createHash } = __require("crypto");
16646
+ var { createHash: createHash2 } = __require("crypto");
16647
16647
  var extension = require_extension();
16648
16648
  var PerMessageDeflate = require_permessage_deflate();
16649
16649
  var subprotocol = require_subprotocol();
@@ -16858,7 +16858,7 @@ var require_websocket_server = __commonJS((exports, module) => {
16858
16858
  }
16859
16859
  if (this._state > RUNNING)
16860
16860
  return abortHandshake(socket, 503);
16861
- const digest = createHash("sha1").update(key + GUID).digest("base64");
16861
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
16862
16862
  const headers = [
16863
16863
  "HTTP/1.1 101 Switching Protocols",
16864
16864
  "Upgrade: websocket",
@@ -56131,6 +56131,9 @@ function buildClaudeChildEnv(parentEnv, account, opts) {
56131
56131
  if (env.ENABLE_PROMPT_CACHING_1H === undefined) {
56132
56132
  env.ENABLE_PROMPT_CACHING_1H = "true";
56133
56133
  }
56134
+ if (opts?.disableAutoMemory) {
56135
+ env.CLAUDE_CODE_DISABLE_AUTO_MEMORY = "1";
56136
+ }
56134
56137
  if (opts?.decisionBridge && env.MCP_TOOL_TIMEOUT === undefined) {
56135
56138
  env.MCP_TOOL_TIMEOUT = "3600000";
56136
56139
  }
@@ -56145,6 +56148,21 @@ function buildClaudeChildEnv(parentEnv, account, opts) {
56145
56148
  }
56146
56149
  return env;
56147
56150
  }
56151
+ function buildInlineSettings(statusLineCommand, memory) {
56152
+ const settings = {};
56153
+ if (statusLineCommand) {
56154
+ settings.statusLine = {
56155
+ type: "command",
56156
+ command: statusLineCommand,
56157
+ padding: 0
56158
+ };
56159
+ }
56160
+ if (memory) {
56161
+ settings.autoMemoryEnabled = true;
56162
+ settings.autoMemoryDirectory = memory.autoMemoryDir;
56163
+ }
56164
+ return Object.keys(settings).length > 0 ? settings : null;
56165
+ }
56148
56166
  function runtimeForScriptPath(scriptPath) {
56149
56167
  return scriptPath.endsWith(".ts") ? process.execPath : "node";
56150
56168
  }
@@ -56342,18 +56360,16 @@ class ClaudeCli extends EventEmitter2 {
56342
56360
  if (this.options.appendSystemPrompt) {
56343
56361
  args.push("--append-system-prompt", this.options.appendSystemPrompt);
56344
56362
  }
56363
+ let statusLineCommand;
56345
56364
  if (this.options.sessionId) {
56346
56365
  this.statusFilePath = join4(tmpdir2(), `claude-threads-status-${this.options.sessionId}.json`);
56347
56366
  const statusLineWriterPath = this.getStatusLineWriterPath();
56348
56367
  const runtime = runtimeForScriptPath(statusLineWriterPath);
56349
- const statusLineSettings = {
56350
- statusLine: {
56351
- type: "command",
56352
- command: `${runtime} ${statusLineWriterPath} ${this.options.sessionId}`,
56353
- padding: 0
56354
- }
56355
- };
56356
- args.push("--settings", JSON.stringify(statusLineSettings));
56368
+ statusLineCommand = `${runtime} ${statusLineWriterPath} ${this.options.sessionId}`;
56369
+ }
56370
+ const settings = buildInlineSettings(statusLineCommand, this.options.memory);
56371
+ if (settings) {
56372
+ args.push("--settings", JSON.stringify(settings));
56357
56373
  }
56358
56374
  this.log.debug(`Starting: ${claudePath} ${args.slice(0, 5).join(" ")}...`);
56359
56375
  const childEnv = this.buildChildEnv();
@@ -56575,7 +56591,8 @@ class ClaudeCli extends EventEmitter2 {
56575
56591
  }
56576
56592
  buildChildEnv() {
56577
56593
  return buildClaudeChildEnv(process.env, this.options.account, {
56578
- decisionBridge: this.options.decisionBridgePath !== undefined
56594
+ decisionBridge: this.options.decisionBridgePath !== undefined,
56595
+ disableAutoMemory: this.options.memory === null
56579
56596
  });
56580
56597
  }
56581
56598
  getMcpServerPath() {
@@ -56723,6 +56740,25 @@ var COMMAND_REGISTRY = [
56723
56740
  audience: "user",
56724
56741
  claudeNotes: "User decisions, not yours"
56725
56742
  },
56743
+ {
56744
+ command: "remember",
56745
+ description: "Save a note to this channel's shared memory (visible to all future sessions here)",
56746
+ args: "<text>",
56747
+ category: "settings",
56748
+ audience: "user",
56749
+ claudeNotes: "User decisions, not yours"
56750
+ },
56751
+ {
56752
+ command: "memory",
56753
+ description: "Show channel memory; forget removes entries",
56754
+ args: "[forget <n|text> | forget all]",
56755
+ category: "settings",
56756
+ audience: "user",
56757
+ claudeNotes: "User decisions, not yours",
56758
+ subcommands: [
56759
+ { name: "forget", description: "Remove one entry (by number or matching text), or all", args: "<n|text> | all" }
56760
+ ]
56761
+ },
56726
56762
  {
56727
56763
  command: "update",
56728
56764
  description: "Show auto-update status",
@@ -56963,6 +56999,40 @@ var handleGitHubEmail = async (ctx, args) => {
56963
56999
  await ctx.sessionManager.setGitHubEmail(ctx.threadId, ctx.username, args);
56964
57000
  return { handled: true };
56965
57001
  };
57002
+ var handleRemember = async (ctx, args) => {
57003
+ if (ctx.commandContext === "first-message") {
57004
+ return { handled: false };
57005
+ }
57006
+ if (!ctx.isAllowed) {
57007
+ return { handled: true };
57008
+ }
57009
+ if (!args?.trim()) {
57010
+ await ctx.client.createPost(`⚠️ Usage: ${ctx.formatter.formatCode("!remember <text>")}`, ctx.threadId);
57011
+ return { handled: true };
57012
+ }
57013
+ await ctx.sessionManager.rememberEntry(ctx.threadId, args, ctx.username);
57014
+ return { handled: true };
57015
+ };
57016
+ var handleMemory = async (ctx, args) => {
57017
+ if (ctx.commandContext === "first-message") {
57018
+ return { handled: false };
57019
+ }
57020
+ if (!ctx.isAllowed) {
57021
+ return { handled: true };
57022
+ }
57023
+ const trimmed = args?.trim();
57024
+ if (!trimmed) {
57025
+ await ctx.sessionManager.showMemory(ctx.threadId, ctx.username);
57026
+ return { handled: true };
57027
+ }
57028
+ const forgetMatch = trimmed.match(/^forget\s+([\s\S]+)$/i);
57029
+ if (forgetMatch) {
57030
+ await ctx.sessionManager.forgetMemory(ctx.threadId, forgetMatch[1].trim(), ctx.username);
57031
+ return { handled: true };
57032
+ }
57033
+ await ctx.client.createPost(`⚠️ Usage: ${ctx.formatter.formatCode("!memory")} or ${ctx.formatter.formatCode("!memory forget <n|text>")} or ${ctx.formatter.formatCode("!memory forget all")}`, ctx.threadId);
57034
+ return { handled: true };
57035
+ };
56966
57036
  var handleCd = async (ctx, args) => {
56967
57037
  if (!args) {
56968
57038
  return { handled: false };
@@ -57152,6 +57222,8 @@ handlers.set("approve", handleApprove);
57152
57222
  handlers.set("invite", handleInvite);
57153
57223
  handlers.set("kick", handleKick);
57154
57224
  handlers.set("github-email", handleGitHubEmail);
57225
+ handlers.set("remember", handleRemember);
57226
+ handlers.set("memory", handleMemory);
57155
57227
  handlers.set("cd", handleCd);
57156
57228
  handlers.set("permissions", handlePermissions);
57157
57229
  handlers.set("mentions", handleMentions);
@@ -57290,9 +57362,257 @@ var log16 = createLogger("context");
57290
57362
  var sessionLog2 = createSessionLog(log16);
57291
57363
  var contextPromptTimeouts = new Map;
57292
57364
  var contextPromptFiles = new Map;
57365
+ // src/memory/store.ts
57366
+ import { createHash } from "crypto";
57367
+ import {
57368
+ chmodSync,
57369
+ existsSync as existsSync5,
57370
+ mkdirSync,
57371
+ readFileSync as readFileSync4,
57372
+ renameSync,
57373
+ realpathSync,
57374
+ writeFileSync as writeFileSync2
57375
+ } from "fs";
57376
+ import { homedir as homedir4 } from "os";
57377
+ import { basename as basename3, dirname as dirname7, join as join6, sep as sep2 } from "path";
57378
+ var log17 = createLogger("memory");
57379
+ var DEFAULT_ROOT = join6(homedir4(), ".config", "claude-threads", "memory");
57380
+ var CHANNEL_BLOCK_MAX_LINES = 200;
57381
+ var CHANNEL_BLOCK_MAX_BYTES = 25 * 1024;
57382
+ var CHANNEL_FILE_MAX_ENTRIES = 400;
57383
+ var MAX_ENTRY_LENGTH = 500;
57384
+ var FILE_HEADER = "# Channel memory — managed by claude-threads.";
57385
+ var ENTRY_RE = /^- \[(\d{4}-\d{2}-\d{2})\] \((@[^\s)]+|distilled)\) (.+)$/;
57386
+ function safeIdSegment(id) {
57387
+ return id.replace(/[^A-Za-z0-9._-]/g, "_");
57388
+ }
57389
+ function shortHash(value, length) {
57390
+ return createHash("sha256").update(value).digest("hex").slice(0, length);
57391
+ }
57392
+ function platformSegment(platformId) {
57393
+ return `${safeIdSegment(platformId) || "platform"}-${shortHash(platformId, 6)}`;
57394
+ }
57395
+ function normalizeForDedupe(text) {
57396
+ return text.toLowerCase().replace(/\s+/g, " ").replace(/[.!?\s]+$/g, "").trim();
57397
+ }
57398
+ function collapseEntryText(text) {
57399
+ return text.replace(/\s*[\r\n]+\s*/g, "; ").replace(/\s+/g, " ").trim();
57400
+ }
57401
+ function sanitizeEntryText(text) {
57402
+ return collapseEntryText(text).slice(0, MAX_ENTRY_LENGTH);
57403
+ }
57404
+ function formatEntryLine(entry) {
57405
+ const source = entry.source === "user" ? `@${entry.addedBy ?? "unknown"}` : "distilled";
57406
+ return `- [${entry.addedAt}] (${source}) ${entry.text}`;
57407
+ }
57408
+ function todayStamp() {
57409
+ return new Date().toISOString().slice(0, 10);
57410
+ }
57411
+
57412
+ class MemoryStore {
57413
+ root;
57414
+ locks = new Map;
57415
+ constructor(rootDir) {
57416
+ this.root = rootDir ?? process.env.CLAUDE_THREADS_MEMORY_DIR ?? DEFAULT_ROOT;
57417
+ }
57418
+ get rootDir() {
57419
+ return this.root;
57420
+ }
57421
+ channelMemoryPath(platformId) {
57422
+ return join6(this.root, platformSegment(platformId), "channel", "MEMORY.md");
57423
+ }
57424
+ repoMemoryDir(platformId, repoKey) {
57425
+ const dir = join6(this.root, platformSegment(platformId), "repos", repoKey);
57426
+ this.ensureDir(dir);
57427
+ return dir;
57428
+ }
57429
+ listChannelEntries(platformId) {
57430
+ return this.loadLines(platformId).map((l) => l.entry).filter((e) => e !== undefined);
57431
+ }
57432
+ addChannelEntries(platformId, entries) {
57433
+ return this.runExclusive(platformId, () => {
57434
+ const lines = this.loadLines(platformId);
57435
+ const result = { added: [], duplicates: [], superseded: [] };
57436
+ for (const candidate of entries) {
57437
+ const text = sanitizeEntryText(candidate.text);
57438
+ if (!text)
57439
+ continue;
57440
+ const normalized = normalizeForDedupe(text);
57441
+ const existing = lines.map((l) => l.entry).filter((e) => e !== undefined);
57442
+ const isDuplicate = existing.some((e) => {
57443
+ const en = normalizeForDedupe(e.text);
57444
+ if (en === normalized)
57445
+ return true;
57446
+ return candidate.source === "distilled" && en.includes(normalized);
57447
+ });
57448
+ if (isDuplicate) {
57449
+ result.duplicates.push(text);
57450
+ continue;
57451
+ }
57452
+ const canSupersede = (e) => e.source === "distilled" || candidate.source === "user" && e.source === "user" && e.addedBy === candidate.addedBy;
57453
+ for (let i = lines.length - 1;i >= 0; i--) {
57454
+ const e = lines[i].entry;
57455
+ if (e && canSupersede(e) && normalized.includes(normalizeForDedupe(e.text))) {
57456
+ result.superseded.push(e);
57457
+ lines.splice(i, 1);
57458
+ }
57459
+ }
57460
+ const entry = {
57461
+ text,
57462
+ addedAt: todayStamp(),
57463
+ source: candidate.source,
57464
+ addedBy: candidate.source === "user" ? candidate.addedBy : undefined
57465
+ };
57466
+ lines.push({ raw: formatEntryLine(entry), entry });
57467
+ result.added.push(entry);
57468
+ }
57469
+ if (result.added.length > 0) {
57470
+ this.enforceFileCap(lines);
57471
+ this.writeLines(platformId, lines);
57472
+ log17.debug(`Channel memory for ${platformId}: +${result.added.length} entries` + (result.duplicates.length ? ` (${result.duplicates.length} duplicates skipped)` : ""));
57473
+ }
57474
+ return result;
57475
+ });
57476
+ }
57477
+ forgetChannelEntry(platformId, selector) {
57478
+ return this.runExclusive(platformId, () => {
57479
+ const lines = this.loadLines(platformId);
57480
+ const entryLines = [];
57481
+ lines.forEach((l, i) => {
57482
+ if (l.entry)
57483
+ entryLines.push({ lineIndex: i, entry: l.entry });
57484
+ });
57485
+ if (entryLines.length === 0) {
57486
+ return { ok: false, reason: "empty", matches: [] };
57487
+ }
57488
+ let target;
57489
+ if (typeof selector === "number") {
57490
+ if (!Number.isInteger(selector) || selector < 1 || selector > entryLines.length) {
57491
+ return { ok: false, reason: "not-found", matches: [] };
57492
+ }
57493
+ target = entryLines[selector - 1];
57494
+ } else {
57495
+ const needle = selector.toLowerCase().trim();
57496
+ const matches = entryLines.filter((el) => el.entry.text.toLowerCase().includes(needle));
57497
+ if (matches.length === 0) {
57498
+ return { ok: false, reason: "not-found", matches: [] };
57499
+ }
57500
+ if (matches.length > 1) {
57501
+ return {
57502
+ ok: false,
57503
+ reason: "ambiguous",
57504
+ matches: matches.map((el) => el.entry)
57505
+ };
57506
+ }
57507
+ target = matches[0];
57508
+ }
57509
+ lines.splice(target.lineIndex, 1);
57510
+ this.writeLines(platformId, lines);
57511
+ log17.debug(`Channel memory for ${platformId}: removed one entry`);
57512
+ return { ok: true, removed: target.entry };
57513
+ });
57514
+ }
57515
+ clearChannel(platformId) {
57516
+ return this.runExclusive(platformId, () => {
57517
+ this.writeLines(platformId, []);
57518
+ log17.debug(`Channel memory for ${platformId}: cleared`);
57519
+ });
57520
+ }
57521
+ buildChannelMemoryBlock(platformId) {
57522
+ let lines;
57523
+ try {
57524
+ lines = this.loadLines(platformId);
57525
+ } catch (err) {
57526
+ log17.warn(`Failed to read channel memory for ${platformId}: ${err.message}`);
57527
+ return null;
57528
+ }
57529
+ if (lines.length === 0)
57530
+ return null;
57531
+ let truncated = false;
57532
+ const overCap = (ls) => {
57533
+ if (ls.length > CHANNEL_BLOCK_MAX_LINES)
57534
+ return true;
57535
+ const bytes = Buffer.byteLength(ls.map((l) => l.raw).join(`
57536
+ `), "utf-8");
57537
+ return bytes > CHANNEL_BLOCK_MAX_BYTES;
57538
+ };
57539
+ while (lines.length > 1 && overCap(lines)) {
57540
+ truncated = true;
57541
+ const distilledIdx = lines.findIndex((l) => l.entry?.source === "distilled");
57542
+ lines.splice(distilledIdx >= 0 ? distilledIdx : 0, 1);
57543
+ }
57544
+ const rendered = lines.map((l) => l.raw).join(`
57545
+ `);
57546
+ return truncated ? `${rendered}
57547
+ _(older entries omitted — \`!memory\` shows all)_` : rendered;
57548
+ }
57549
+ runExclusive(platformId, fn) {
57550
+ const tail = this.locks.get(platformId) ?? Promise.resolve();
57551
+ const next = tail.then(fn, fn);
57552
+ this.locks.set(platformId, next.catch(() => {
57553
+ return;
57554
+ }));
57555
+ return next;
57556
+ }
57557
+ loadLines(platformId) {
57558
+ const file2 = this.channelMemoryPath(platformId);
57559
+ if (!existsSync5(file2))
57560
+ return [];
57561
+ const raw = readFileSync4(file2, "utf-8");
57562
+ const lines = [];
57563
+ for (const line of raw.split(`
57564
+ `)) {
57565
+ const trimmed = line.trimEnd();
57566
+ if (!trimmed || trimmed === FILE_HEADER)
57567
+ continue;
57568
+ const m = trimmed.match(ENTRY_RE);
57569
+ if (m) {
57570
+ const source = m[2] === "distilled" ? "distilled" : "user";
57571
+ lines.push({
57572
+ raw: trimmed,
57573
+ entry: {
57574
+ addedAt: m[1],
57575
+ source,
57576
+ addedBy: source === "user" ? m[2].slice(1) : undefined,
57577
+ text: m[3]
57578
+ }
57579
+ });
57580
+ } else {
57581
+ lines.push({ raw: trimmed });
57582
+ }
57583
+ }
57584
+ return lines;
57585
+ }
57586
+ enforceFileCap(lines) {
57587
+ while (lines.length > CHANNEL_FILE_MAX_ENTRIES) {
57588
+ const distilledIdx = lines.findIndex((l) => l.entry?.source === "distilled");
57589
+ lines.splice(distilledIdx >= 0 ? distilledIdx : 0, 1);
57590
+ }
57591
+ }
57592
+ writeLines(platformId, lines) {
57593
+ const file2 = this.channelMemoryPath(platformId);
57594
+ this.ensureDir(dirname7(file2));
57595
+ const content = [FILE_HEADER, ...lines.map((l) => l.raw)].join(`
57596
+ `) + `
57597
+ `;
57598
+ const tempFile = `${file2}.tmp`;
57599
+ writeFileSync2(tempFile, content, { encoding: "utf-8", mode: 384 });
57600
+ renameSync(tempFile, file2);
57601
+ chmodSync(file2, 384);
57602
+ }
57603
+ ensureDir(dir) {
57604
+ if (!existsSync5(dir)) {
57605
+ mkdirSync(dir, { recursive: true, mode: 448 });
57606
+ }
57607
+ }
57608
+ }
57609
+
57610
+ // src/memory/distiller.ts
57611
+ var log18 = createLogger("memory");
57612
+
57293
57613
  // src/session/lifecycle.ts
57294
- var log17 = createLogger("lifecycle");
57295
- var sessionLog3 = createSessionLog(log17);
57614
+ var log19 = createLogger("lifecycle");
57615
+ var sessionLog3 = createSessionLog(log19);
57296
57616
  var CHAT_PLATFORM_PROMPT = generateChatPlatformPrompt();
57297
57617
  // src/update-notifier.ts
57298
57618
  var import_semver2 = __toESM(require_semver2(), 1);
@@ -57301,29 +57621,29 @@ var import_semver2 = __toESM(require_semver2(), 1);
57301
57621
  init_emoji();
57302
57622
 
57303
57623
  // src/persistence/github-emails-store.ts
57304
- import { homedir as homedir4 } from "os";
57305
- import { join as join6 } from "path";
57306
- var log18 = createLogger("gh-emails");
57307
- var DEFAULT_CONFIG_DIR = join6(homedir4(), ".config", "claude-threads");
57308
- var DEFAULT_FILE = join6(DEFAULT_CONFIG_DIR, "github-emails.yaml");
57624
+ import { homedir as homedir5 } from "os";
57625
+ import { join as join7 } from "path";
57626
+ var log20 = createLogger("gh-emails");
57627
+ var DEFAULT_CONFIG_DIR = join7(homedir5(), ".config", "claude-threads");
57628
+ var DEFAULT_FILE = join7(DEFAULT_CONFIG_DIR, "github-emails.yaml");
57309
57629
 
57310
57630
  // src/operations/commands/handler.ts
57311
- var log19 = createLogger("commands");
57312
- var sessionLog4 = createSessionLog(log19);
57631
+ var log21 = createLogger("commands");
57632
+ var sessionLog4 = createSessionLog(log21);
57313
57633
  // src/operations/suggestions/branch.ts
57314
57634
  import { exec as exec2 } from "child_process";
57315
57635
  import { promisify as promisify2 } from "util";
57316
57636
  var execAsync2 = promisify2(exec2);
57317
- var log20 = createLogger("branch");
57637
+ var log22 = createLogger("branch");
57318
57638
 
57319
57639
  // src/operations/worktree/handler.ts
57320
- var log21 = createLogger("worktree");
57321
- var sessionLog5 = createSessionLog(log21);
57640
+ var log23 = createLogger("worktree");
57641
+ var sessionLog5 = createSessionLog(log23);
57322
57642
  // src/operations/events/handler.ts
57323
- var log22 = createLogger("events");
57324
- var sessionLog6 = createSessionLog(log22);
57643
+ var log24 = createLogger("events");
57644
+ var sessionLog6 = createSessionLog(log24);
57325
57645
  // src/operations/monitor/handler.ts
57326
- var log23 = createLogger("monitor");
57646
+ var log25 = createLogger("monitor");
57327
57647
  var DEFAULT_INTERVAL_MS = 60 * 1000;
57328
57648
  // src/utils/websocket.ts
57329
57649
  var WS;
@@ -57405,7 +57725,7 @@ ${code}
57405
57725
 
57406
57726
  // src/platform/mattermost/upload.ts
57407
57727
  import { readFile } from "fs/promises";
57408
- var log24 = createLogger("mm-upload");
57728
+ var log26 = createLogger("mm-upload");
57409
57729
  async function uploadFileMattermost(args) {
57410
57730
  const { url: url2, token, channelId, threadId, filePath, filename, caption } = args;
57411
57731
  const buffer = await readFile(filePath);
@@ -57413,7 +57733,7 @@ async function uploadFileMattermost(args) {
57413
57733
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
57414
57734
  const formData = new FormData;
57415
57735
  formData.append("files", new Blob([arrayBuffer]), filename);
57416
- log24.debug(`POST /files (${buffer.length} bytes, ${filename})`);
57736
+ log26.debug(`POST /files (${buffer.length} bytes, ${filename})`);
57417
57737
  const uploadResponse = await fetch(uploadUrl, {
57418
57738
  method: "POST",
57419
57739
  headers: {
@@ -57437,7 +57757,7 @@ async function uploadFileMattermost(args) {
57437
57757
  root_id: threadId,
57438
57758
  file_ids: [fileInfo.id]
57439
57759
  };
57440
- log24.debug(`POST /posts (file_ids=[${fileInfo.id}])`);
57760
+ log26.debug(`POST /posts (file_ids=[${fileInfo.id}])`);
57441
57761
  const postResponse = await fetch(postUrl, {
57442
57762
  method: "POST",
57443
57763
  headers: {
@@ -57638,7 +57958,7 @@ class MattermostMcpPlatformApi {
57638
57958
  await updatePostRaw(this.apiConfig, postId, message);
57639
57959
  }
57640
57960
  async waitForReaction(postId, botUserId, timeoutMs) {
57641
- return new Promise((resolve5) => {
57961
+ return new Promise((resolve6) => {
57642
57962
  const wsUrl = this.config.url.replace(/^http/, "ws") + "/api/v4/websocket";
57643
57963
  mcpLogger.debug(`Connecting to WebSocket: ${wsUrl}`);
57644
57964
  const ws = new WS(wsUrl);
@@ -57653,7 +57973,7 @@ class MattermostMcpPlatformApi {
57653
57973
  mcpLogger.debug(`Reaction wait timed out after ${timeoutMs}ms`);
57654
57974
  resolved = true;
57655
57975
  cleanup();
57656
- resolve5(null);
57976
+ resolve6(null);
57657
57977
  }
57658
57978
  }, timeoutMs);
57659
57979
  ws.onopen = () => {
@@ -57681,7 +58001,7 @@ class MattermostMcpPlatformApi {
57681
58001
  resolved = true;
57682
58002
  clearTimeout(timeout);
57683
58003
  cleanup();
57684
- resolve5({
58004
+ resolve6({
57685
58005
  postId: reaction.post_id,
57686
58006
  userId: reaction.user_id,
57687
58007
  emojiName: reaction.emoji_name
@@ -57696,7 +58016,7 @@ class MattermostMcpPlatformApi {
57696
58016
  if (!resolved) {
57697
58017
  resolved = true;
57698
58018
  clearTimeout(timeout);
57699
- resolve5(null);
58019
+ resolve6(null);
57700
58020
  }
57701
58021
  };
57702
58022
  ws.onclose = () => {
@@ -57704,7 +58024,7 @@ class MattermostMcpPlatformApi {
57704
58024
  if (!resolved) {
57705
58025
  resolved = true;
57706
58026
  clearTimeout(timeout);
57707
- resolve5(null);
58027
+ resolve6(null);
57708
58028
  }
57709
58029
  };
57710
58030
  });
@@ -57931,7 +58251,7 @@ ${code}
57931
58251
 
57932
58252
  // src/platform/slack/upload.ts
57933
58253
  import { readFile as readFile2 } from "fs/promises";
57934
- var log25 = createLogger("slack-upload");
58254
+ var log27 = createLogger("slack-upload");
57935
58255
  var DEFAULT_API_URL = "https://slack.com/api";
57936
58256
  async function uploadFileSlack(args) {
57937
58257
  const { botToken, channelId, threadTs, filePath, filename, caption } = args;
@@ -57939,7 +58259,7 @@ async function uploadFileSlack(args) {
57939
58259
  const buffer = await readFile2(filePath);
57940
58260
  const params = new URLSearchParams({ filename, length: String(buffer.length) });
57941
58261
  const step1Url = `${apiUrl}/files.getUploadURLExternal?${params.toString()}`;
57942
- log25.debug(`GET files.getUploadURLExternal (${buffer.length} bytes, ${filename})`);
58262
+ log27.debug(`GET files.getUploadURLExternal (${buffer.length} bytes, ${filename})`);
57943
58263
  const step1Response = await fetch(step1Url, {
57944
58264
  method: "GET",
57945
58265
  headers: {
@@ -57957,7 +58277,7 @@ async function uploadFileSlack(args) {
57957
58277
  const uploadUrl = step1Data.upload_url;
57958
58278
  const fileId = step1Data.file_id;
57959
58279
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
57960
- log25.debug(`POST <upload_url>`);
58280
+ log27.debug(`POST <upload_url>`);
57961
58281
  const step2Response = await fetch(uploadUrl, {
57962
58282
  method: "POST",
57963
58283
  headers: {
@@ -57977,7 +58297,7 @@ async function uploadFileSlack(args) {
57977
58297
  if (caption !== undefined) {
57978
58298
  step3Body.initial_comment = caption;
57979
58299
  }
57980
- log25.debug(`POST files.completeUploadExternal (file_id=${fileId}, thread_ts=${threadTs})`);
58300
+ log27.debug(`POST files.completeUploadExternal (file_id=${fileId}, thread_ts=${threadTs})`);
57981
58301
  const step3Response = await fetch(`${apiUrl}/files.completeUploadExternal`, {
57982
58302
  method: "POST",
57983
58303
  headers: {
@@ -57995,7 +58315,7 @@ async function uploadFileSlack(args) {
57995
58315
  throw new Error(`Slack completeUploadExternal error: ${step3Data.error || "unknown"}`);
57996
58316
  }
57997
58317
  if (!step3Data.ts) {
57998
- log25.warn(`Slack completeUploadExternal returned no ts; using fileId ${fileId} as postId. ` + `Do not use this id for updatePost/addReaction.`);
58318
+ log27.warn(`Slack completeUploadExternal returned no ts; using fileId ${fileId} as postId. ` + `Do not use this id for updatePost/addReaction.`);
57999
58319
  }
58000
58320
  return { fileId, postId: step3Data.ts ?? fileId };
58001
58321
  }
@@ -58101,7 +58421,7 @@ class SlackMcpPlatformApi {
58101
58421
  });
58102
58422
  }
58103
58423
  async waitForReaction(postId, botUserId, timeoutMs) {
58104
- return new Promise((resolve5) => {
58424
+ return new Promise((resolve6) => {
58105
58425
  let resolved = false;
58106
58426
  let ws = null;
58107
58427
  const cleanup = () => {
@@ -58114,7 +58434,7 @@ class SlackMcpPlatformApi {
58114
58434
  mcpLogger.debug(`Reaction wait timed out after ${timeoutMs}ms`);
58115
58435
  resolved = true;
58116
58436
  cleanup();
58117
- resolve5(null);
58437
+ resolve6(null);
58118
58438
  }
58119
58439
  }, timeoutMs);
58120
58440
  this.getSocketModeUrl().then((wsUrl) => {
@@ -58152,7 +58472,7 @@ class SlackMcpPlatformApi {
58152
58472
  resolved = true;
58153
58473
  clearTimeout(timeout);
58154
58474
  cleanup();
58155
- resolve5({
58475
+ resolve6({
58156
58476
  postId: item.ts,
58157
58477
  userId,
58158
58478
  emojiName
@@ -58168,7 +58488,7 @@ class SlackMcpPlatformApi {
58168
58488
  resolved = true;
58169
58489
  clearTimeout(timeout);
58170
58490
  cleanup();
58171
- resolve5(null);
58491
+ resolve6(null);
58172
58492
  }
58173
58493
  }
58174
58494
  } catch (err) {
@@ -58181,7 +58501,7 @@ class SlackMcpPlatformApi {
58181
58501
  resolved = true;
58182
58502
  clearTimeout(timeout);
58183
58503
  cleanup();
58184
- resolve5(null);
58504
+ resolve6(null);
58185
58505
  }
58186
58506
  };
58187
58507
  ws.onclose = () => {
@@ -58189,7 +58509,7 @@ class SlackMcpPlatformApi {
58189
58509
  if (!resolved) {
58190
58510
  resolved = true;
58191
58511
  clearTimeout(timeout);
58192
- resolve5(null);
58512
+ resolve6(null);
58193
58513
  }
58194
58514
  };
58195
58515
  }).catch((err) => {
@@ -58197,7 +58517,7 @@ class SlackMcpPlatformApi {
58197
58517
  if (!resolved) {
58198
58518
  resolved = true;
58199
58519
  clearTimeout(timeout);
58200
- resolve5(null);
58520
+ resolve6(null);
58201
58521
  }
58202
58522
  });
58203
58523
  });
@@ -58388,11 +58708,11 @@ function createMcpPlatformApi(platformType, config3) {
58388
58708
 
58389
58709
  // src/mcp/path-validator.ts
58390
58710
  import { lstat, realpath, stat } from "fs/promises";
58391
- import { sep as sep2, isAbsolute } from "path";
58711
+ import { sep as sep3, isAbsolute as isAbsolute2 } from "path";
58392
58712
  function isUnderRoot(needle, root) {
58393
58713
  if (needle === root)
58394
58714
  return true;
58395
- const withSep = root.endsWith(sep2) ? root : root + sep2;
58715
+ const withSep = root.endsWith(sep3) ? root : root + sep3;
58396
58716
  return needle.startsWith(withSep);
58397
58717
  }
58398
58718
  var DANGEROUSLY_WIDE_ROOTS = new Set([
@@ -58417,7 +58737,7 @@ async function validateOutboundPath(inputPath, opts) {
58417
58737
  if (typeof inputPath !== "string" || inputPath.length === 0) {
58418
58738
  return { ok: false, reason: "path is required" };
58419
58739
  }
58420
- if (!isAbsolute(inputPath)) {
58740
+ if (!isAbsolute2(inputPath)) {
58421
58741
  return { ok: false, reason: "path must be absolute" };
58422
58742
  }
58423
58743
  if (!Number.isFinite(opts.maxBytes) || opts.maxBytes <= 0) {