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.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -0
- package/dist/index.js +1229 -577
- package/dist/mcp/mcp-server.js +371 -51
- package/docs/CONFIGURATION.md +72 -0
- package/package.json +4 -4
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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
|
-
|
|
56350
|
-
|
|
56351
|
-
|
|
56352
|
-
|
|
56353
|
-
|
|
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
|
|
57295
|
-
var sessionLog3 = createSessionLog(
|
|
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
|
|
57305
|
-
import { join as
|
|
57306
|
-
var
|
|
57307
|
-
var DEFAULT_CONFIG_DIR =
|
|
57308
|
-
var DEFAULT_FILE =
|
|
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
|
|
57312
|
-
var sessionLog4 = createSessionLog(
|
|
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
|
|
57637
|
+
var log22 = createLogger("branch");
|
|
57318
57638
|
|
|
57319
57639
|
// src/operations/worktree/handler.ts
|
|
57320
|
-
var
|
|
57321
|
-
var sessionLog5 = createSessionLog(
|
|
57640
|
+
var log23 = createLogger("worktree");
|
|
57641
|
+
var sessionLog5 = createSessionLog(log23);
|
|
57322
57642
|
// src/operations/events/handler.ts
|
|
57323
|
-
var
|
|
57324
|
-
var sessionLog6 = createSessionLog(
|
|
57643
|
+
var log24 = createLogger("events");
|
|
57644
|
+
var sessionLog6 = createSessionLog(log24);
|
|
57325
57645
|
// src/operations/monitor/handler.ts
|
|
57326
|
-
var
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 (!
|
|
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) {
|