claude-threads 1.26.0 → 1.28.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/dist/index.js +63572 -62742
- package/dist/mcp/mcp-server.js +313 -195
- package/docs/CONFIGURATION.md +105 -0
- package/package.json +5 -5
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -47754,7 +47754,11 @@ function truncateWithEllipsis(str, maxLength) {
|
|
|
47754
47754
|
return str.substring(0, maxLength) + "...";
|
|
47755
47755
|
}
|
|
47756
47756
|
function escapeCodeBlockContent(content) {
|
|
47757
|
-
|
|
47757
|
+
let result = content;
|
|
47758
|
+
while (result.includes("```")) {
|
|
47759
|
+
result = result.replace(/```/g, "` ``");
|
|
47760
|
+
}
|
|
47761
|
+
return result;
|
|
47758
47762
|
}
|
|
47759
47763
|
// src/operations/tool-formatters/registry.ts
|
|
47760
47764
|
class ToolFormatterRegistry {
|
|
@@ -48553,6 +48557,15 @@ var fileToolsFormatter = {
|
|
|
48553
48557
|
}
|
|
48554
48558
|
};
|
|
48555
48559
|
// src/operations/tool-formatters/bash-tools.ts
|
|
48560
|
+
var PERMISSION_COMMAND_MAX = 1500;
|
|
48561
|
+
function truncateAtCodePoint(text, max) {
|
|
48562
|
+
if (text.length <= max)
|
|
48563
|
+
return { text, truncated: false };
|
|
48564
|
+
const points = Array.from(text);
|
|
48565
|
+
if (points.length <= max)
|
|
48566
|
+
return { text, truncated: false };
|
|
48567
|
+
return { text: points.slice(0, max).join(""), truncated: true };
|
|
48568
|
+
}
|
|
48556
48569
|
var bashToolFormatter = {
|
|
48557
48570
|
toolNames: ["Bash"],
|
|
48558
48571
|
format(toolName, input, options) {
|
|
@@ -48565,9 +48578,13 @@ var bashToolFormatter = {
|
|
|
48565
48578
|
}
|
|
48566
48579
|
const truncated = cmd.length > maxCommandLength;
|
|
48567
48580
|
const displayCmd = cmd.substring(0, maxCommandLength);
|
|
48581
|
+
const permission = truncateAtCodePoint(cmd, PERMISSION_COMMAND_MAX);
|
|
48582
|
+
const permissionCmd = escapeCodeBlockContent(permission.text) + (permission.truncated ? `
|
|
48583
|
+
[... truncated]` : "");
|
|
48568
48584
|
return {
|
|
48569
48585
|
display: `\uD83D\uDCBB ${formatter.formatBold("Bash")} ${formatter.formatCode(displayCmd + (truncated ? "..." : ""))}`,
|
|
48570
|
-
permissionText: `\uD83D\uDCBB ${formatter.formatBold("Bash")}
|
|
48586
|
+
permissionText: `\uD83D\uDCBB ${formatter.formatBold("Bash")}
|
|
48587
|
+
${formatter.formatCodeBlock(permissionCmd, "bash")}`,
|
|
48571
48588
|
isDestructive: true
|
|
48572
48589
|
};
|
|
48573
48590
|
}
|
|
@@ -49632,6 +49649,13 @@ function convertMarkdownTablesToSlack(content) {
|
|
|
49632
49649
|
`);
|
|
49633
49650
|
});
|
|
49634
49651
|
}
|
|
49652
|
+
var DCM_THREAD_PREFIX = "dcm:";
|
|
49653
|
+
function isDcmThreadId(threadId) {
|
|
49654
|
+
return !!threadId && threadId.startsWith(DCM_THREAD_PREFIX);
|
|
49655
|
+
}
|
|
49656
|
+
function resolvePostThreadId(threadId) {
|
|
49657
|
+
return isDcmThreadId(threadId) ? undefined : threadId;
|
|
49658
|
+
}
|
|
49635
49659
|
|
|
49636
49660
|
// src/version.ts
|
|
49637
49661
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -50748,6 +50772,144 @@ class SystemExecutor extends BaseExecutor {
|
|
|
50748
50772
|
}
|
|
50749
50773
|
// src/operations/executors/question-approval.ts
|
|
50750
50774
|
init_emoji();
|
|
50775
|
+
|
|
50776
|
+
// src/persistence/audit-log.ts
|
|
50777
|
+
import { chmodSync, closeSync, constants as fsConstants, fchmodSync, lstatSync, mkdirSync, openSync, writeSync } from "fs";
|
|
50778
|
+
import { join as join2 } from "path";
|
|
50779
|
+
import { homedir } from "os";
|
|
50780
|
+
|
|
50781
|
+
// src/utils/logger.ts
|
|
50782
|
+
var globalLogHandler = null;
|
|
50783
|
+
var COMPONENT_WIDTH = 10;
|
|
50784
|
+
function createLogger(component, useStderr = false, sessionId) {
|
|
50785
|
+
const isDebug = () => process.env.DEBUG === "1";
|
|
50786
|
+
const consoleLog = useStderr ? console.error : console.log;
|
|
50787
|
+
const paddedComponent = component.length > COMPONENT_WIDTH ? component.substring(0, COMPONENT_WIDTH) : component.padEnd(COMPONENT_WIDTH);
|
|
50788
|
+
const formatMessage = (msg, args) => {
|
|
50789
|
+
if (args.length === 0)
|
|
50790
|
+
return msg;
|
|
50791
|
+
return `${msg} ${args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")}`;
|
|
50792
|
+
};
|
|
50793
|
+
const DEFAULT_JSON_MAX_LEN = 60;
|
|
50794
|
+
return {
|
|
50795
|
+
debug: (msg, ...args) => {
|
|
50796
|
+
if (isDebug()) {
|
|
50797
|
+
const fullMsg = formatMessage(msg, args);
|
|
50798
|
+
if (globalLogHandler) {
|
|
50799
|
+
globalLogHandler("debug", paddedComponent, fullMsg, sessionId);
|
|
50800
|
+
} else {
|
|
50801
|
+
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
50802
|
+
}
|
|
50803
|
+
}
|
|
50804
|
+
},
|
|
50805
|
+
debugJson: (label, data, maxLen = DEFAULT_JSON_MAX_LEN) => {
|
|
50806
|
+
if (isDebug()) {
|
|
50807
|
+
const json2 = JSON.stringify(data);
|
|
50808
|
+
const truncated = json2.length > maxLen ? `${json2.substring(0, maxLen)}…` : json2;
|
|
50809
|
+
const fullMsg = `${label}: ${truncated}`;
|
|
50810
|
+
if (globalLogHandler) {
|
|
50811
|
+
globalLogHandler("debug", paddedComponent, fullMsg, sessionId);
|
|
50812
|
+
} else {
|
|
50813
|
+
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
50814
|
+
}
|
|
50815
|
+
}
|
|
50816
|
+
},
|
|
50817
|
+
info: (msg, ...args) => {
|
|
50818
|
+
const fullMsg = formatMessage(msg, args);
|
|
50819
|
+
if (globalLogHandler) {
|
|
50820
|
+
globalLogHandler("info", paddedComponent, fullMsg, sessionId);
|
|
50821
|
+
} else {
|
|
50822
|
+
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
50823
|
+
}
|
|
50824
|
+
},
|
|
50825
|
+
warn: (msg, ...args) => {
|
|
50826
|
+
const fullMsg = formatMessage(msg, args);
|
|
50827
|
+
if (globalLogHandler) {
|
|
50828
|
+
globalLogHandler("warn", paddedComponent, fullMsg, sessionId);
|
|
50829
|
+
} else {
|
|
50830
|
+
console.warn(`[${paddedComponent}] ⚠️ ${fullMsg}`);
|
|
50831
|
+
}
|
|
50832
|
+
},
|
|
50833
|
+
error: (msg, err) => {
|
|
50834
|
+
const fullMsg = err && isDebug() ? `${msg}
|
|
50835
|
+
${err.stack || err.message}` : msg;
|
|
50836
|
+
if (globalLogHandler) {
|
|
50837
|
+
globalLogHandler("error", paddedComponent, fullMsg, sessionId);
|
|
50838
|
+
} else {
|
|
50839
|
+
console.error(`[${paddedComponent}] ❌ ${msg}`);
|
|
50840
|
+
if (err && isDebug()) {
|
|
50841
|
+
console.error(err);
|
|
50842
|
+
}
|
|
50843
|
+
}
|
|
50844
|
+
},
|
|
50845
|
+
forSession: (sid) => createLogger(component, useStderr, sid)
|
|
50846
|
+
};
|
|
50847
|
+
}
|
|
50848
|
+
var mcpLogger = createLogger("MCP", true);
|
|
50849
|
+
var wsLogger = createLogger("ws", false);
|
|
50850
|
+
|
|
50851
|
+
// src/persistence/audit-log.ts
|
|
50852
|
+
var log = createLogger("audit");
|
|
50853
|
+
var DETAIL_MAX = 500;
|
|
50854
|
+
var enabledPlatforms = new Set;
|
|
50855
|
+
var preparedDirs = new Set;
|
|
50856
|
+
var openFds = new Map;
|
|
50857
|
+
function auditDir() {
|
|
50858
|
+
return process.env.CLAUDE_THREADS_AUDIT_DIR || join2(homedir(), ".claude-threads", "audit");
|
|
50859
|
+
}
|
|
50860
|
+
function openAuditFd(platformId) {
|
|
50861
|
+
const cached3 = openFds.get(platformId);
|
|
50862
|
+
if (cached3 !== undefined)
|
|
50863
|
+
return cached3;
|
|
50864
|
+
const dir = auditDir();
|
|
50865
|
+
if (!preparedDirs.has(dir)) {
|
|
50866
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
50867
|
+
chmodSync(dir, 448);
|
|
50868
|
+
preparedDirs.add(dir);
|
|
50869
|
+
}
|
|
50870
|
+
const file2 = join2(dir, `${encodeURIComponent(platformId)}.jsonl`);
|
|
50871
|
+
try {
|
|
50872
|
+
const st = lstatSync(file2);
|
|
50873
|
+
if (st.isSymbolicLink() || !st.isFile()) {
|
|
50874
|
+
throw new Error(`audit path exists but is not a regular file: ${file2}`);
|
|
50875
|
+
}
|
|
50876
|
+
} catch (err) {
|
|
50877
|
+
if (err.code !== "ENOENT")
|
|
50878
|
+
throw err;
|
|
50879
|
+
}
|
|
50880
|
+
const noFollow = typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0;
|
|
50881
|
+
const fd = openSync(file2, fsConstants.O_WRONLY | fsConstants.O_APPEND | fsConstants.O_CREAT | noFollow, 384);
|
|
50882
|
+
try {
|
|
50883
|
+
fchmodSync(fd, 384);
|
|
50884
|
+
} catch {}
|
|
50885
|
+
openFds.set(platformId, fd);
|
|
50886
|
+
return fd;
|
|
50887
|
+
}
|
|
50888
|
+
function auditLog(platformId, entry) {
|
|
50889
|
+
if (!enabledPlatforms.has(platformId))
|
|
50890
|
+
return;
|
|
50891
|
+
try {
|
|
50892
|
+
const full = {
|
|
50893
|
+
ts: new Date().toISOString(),
|
|
50894
|
+
platformId,
|
|
50895
|
+
...entry,
|
|
50896
|
+
...entry.detail !== undefined ? { detail: entry.detail.slice(0, DETAIL_MAX) } : {}
|
|
50897
|
+
};
|
|
50898
|
+
writeSync(openAuditFd(platformId), JSON.stringify(full) + `
|
|
50899
|
+
`);
|
|
50900
|
+
} catch (err) {
|
|
50901
|
+
const fd = openFds.get(platformId);
|
|
50902
|
+
if (fd !== undefined) {
|
|
50903
|
+
openFds.delete(platformId);
|
|
50904
|
+
try {
|
|
50905
|
+
closeSync(fd);
|
|
50906
|
+
} catch {}
|
|
50907
|
+
}
|
|
50908
|
+
log.warn(`audit write failed for ${platformId}: ${err}`);
|
|
50909
|
+
}
|
|
50910
|
+
}
|
|
50911
|
+
|
|
50912
|
+
// src/operations/executors/question-approval.ts
|
|
50751
50913
|
class QuestionApprovalExecutor extends BaseExecutor {
|
|
50752
50914
|
constructor(options) {
|
|
50753
50915
|
super(options, QuestionApprovalExecutor.createInitialState());
|
|
@@ -50962,14 +51124,29 @@ class QuestionApprovalExecutor extends BaseExecutor {
|
|
|
50962
51124
|
return false;
|
|
50963
51125
|
}
|
|
50964
51126
|
if (this.state.pendingApproval?.postId === postId) {
|
|
51127
|
+
const approvalType = this.state.pendingApproval.type;
|
|
51128
|
+
const auditDecision = (approved) => {
|
|
51129
|
+
if (approvalType !== "plan")
|
|
51130
|
+
return;
|
|
51131
|
+
auditLog(ctx.platform.platformId, {
|
|
51132
|
+
threadId: ctx.threadId,
|
|
51133
|
+
sessionId: ctx.sessionId,
|
|
51134
|
+
actor: user,
|
|
51135
|
+
kind: "plan_approval",
|
|
51136
|
+
approved,
|
|
51137
|
+
detail: "via reaction"
|
|
51138
|
+
});
|
|
51139
|
+
};
|
|
50965
51140
|
if (isApprovalEmoji(emoji4)) {
|
|
50966
51141
|
ctx.logger.debug(`Approval reaction from @${user}: approved`);
|
|
51142
|
+
auditDecision(true);
|
|
50967
51143
|
const handled = await this.handleApprovalResponse(postId, true, ctx);
|
|
50968
51144
|
ctx.logger.debug(`QuestionApprovalExecutor: approval outcome=approved, handled=${handled}`);
|
|
50969
51145
|
return handled;
|
|
50970
51146
|
}
|
|
50971
51147
|
if (isDenialEmoji(emoji4)) {
|
|
50972
51148
|
ctx.logger.debug(`Approval reaction from @${user}: denied`);
|
|
51149
|
+
auditDecision(false);
|
|
50973
51150
|
const handled = await this.handleApprovalResponse(postId, false, ctx);
|
|
50974
51151
|
ctx.logger.debug(`QuestionApprovalExecutor: approval outcome=denied, handled=${handled}`);
|
|
50975
51152
|
return handled;
|
|
@@ -51426,79 +51603,7 @@ class BugReportExecutor extends BaseExecutor {
|
|
|
51426
51603
|
}
|
|
51427
51604
|
// src/operations/executors/worktree-prompt.ts
|
|
51428
51605
|
init_emoji();
|
|
51429
|
-
|
|
51430
|
-
// src/utils/logger.ts
|
|
51431
|
-
var globalLogHandler = null;
|
|
51432
|
-
var COMPONENT_WIDTH = 10;
|
|
51433
|
-
function createLogger(component, useStderr = false, sessionId) {
|
|
51434
|
-
const isDebug = () => process.env.DEBUG === "1";
|
|
51435
|
-
const consoleLog = useStderr ? console.error : console.log;
|
|
51436
|
-
const paddedComponent = component.length > COMPONENT_WIDTH ? component.substring(0, COMPONENT_WIDTH) : component.padEnd(COMPONENT_WIDTH);
|
|
51437
|
-
const formatMessage = (msg, args) => {
|
|
51438
|
-
if (args.length === 0)
|
|
51439
|
-
return msg;
|
|
51440
|
-
return `${msg} ${args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")}`;
|
|
51441
|
-
};
|
|
51442
|
-
const DEFAULT_JSON_MAX_LEN = 60;
|
|
51443
|
-
return {
|
|
51444
|
-
debug: (msg, ...args) => {
|
|
51445
|
-
if (isDebug()) {
|
|
51446
|
-
const fullMsg = formatMessage(msg, args);
|
|
51447
|
-
if (globalLogHandler) {
|
|
51448
|
-
globalLogHandler("debug", paddedComponent, fullMsg, sessionId);
|
|
51449
|
-
} else {
|
|
51450
|
-
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
51451
|
-
}
|
|
51452
|
-
}
|
|
51453
|
-
},
|
|
51454
|
-
debugJson: (label, data, maxLen = DEFAULT_JSON_MAX_LEN) => {
|
|
51455
|
-
if (isDebug()) {
|
|
51456
|
-
const json2 = JSON.stringify(data);
|
|
51457
|
-
const truncated = json2.length > maxLen ? `${json2.substring(0, maxLen)}…` : json2;
|
|
51458
|
-
const fullMsg = `${label}: ${truncated}`;
|
|
51459
|
-
if (globalLogHandler) {
|
|
51460
|
-
globalLogHandler("debug", paddedComponent, fullMsg, sessionId);
|
|
51461
|
-
} else {
|
|
51462
|
-
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
51463
|
-
}
|
|
51464
|
-
}
|
|
51465
|
-
},
|
|
51466
|
-
info: (msg, ...args) => {
|
|
51467
|
-
const fullMsg = formatMessage(msg, args);
|
|
51468
|
-
if (globalLogHandler) {
|
|
51469
|
-
globalLogHandler("info", paddedComponent, fullMsg, sessionId);
|
|
51470
|
-
} else {
|
|
51471
|
-
consoleLog(`[${paddedComponent}] ${fullMsg}`);
|
|
51472
|
-
}
|
|
51473
|
-
},
|
|
51474
|
-
warn: (msg, ...args) => {
|
|
51475
|
-
const fullMsg = formatMessage(msg, args);
|
|
51476
|
-
if (globalLogHandler) {
|
|
51477
|
-
globalLogHandler("warn", paddedComponent, fullMsg, sessionId);
|
|
51478
|
-
} else {
|
|
51479
|
-
console.warn(`[${paddedComponent}] ⚠️ ${fullMsg}`);
|
|
51480
|
-
}
|
|
51481
|
-
},
|
|
51482
|
-
error: (msg, err) => {
|
|
51483
|
-
const fullMsg = err && isDebug() ? `${msg}
|
|
51484
|
-
${err.stack || err.message}` : msg;
|
|
51485
|
-
if (globalLogHandler) {
|
|
51486
|
-
globalLogHandler("error", paddedComponent, fullMsg, sessionId);
|
|
51487
|
-
} else {
|
|
51488
|
-
console.error(`[${paddedComponent}] ❌ ${msg}`);
|
|
51489
|
-
if (err && isDebug()) {
|
|
51490
|
-
console.error(err);
|
|
51491
|
-
}
|
|
51492
|
-
}
|
|
51493
|
-
},
|
|
51494
|
-
forSession: (sid) => createLogger(component, useStderr, sid)
|
|
51495
|
-
};
|
|
51496
|
-
}
|
|
51497
|
-
var mcpLogger = createLogger("MCP", true);
|
|
51498
|
-
var wsLogger = createLogger("ws", false);
|
|
51499
|
-
|
|
51500
|
-
// src/operations/executors/worktree-prompt.ts
|
|
51501
|
-
var log = createLogger("wt-prompt");
|
|
51606
|
+
var log2 = createLogger("wt-prompt");
|
|
51502
51607
|
// src/operations/message-manager-events.ts
|
|
51503
51608
|
import { EventEmitter } from "events";
|
|
51504
51609
|
|
|
@@ -51547,7 +51652,7 @@ function formatBytes(bytes) {
|
|
|
51547
51652
|
}
|
|
51548
51653
|
|
|
51549
51654
|
// src/operations/streaming/handler.ts
|
|
51550
|
-
var
|
|
51655
|
+
var log3 = createLogger("streaming");
|
|
51551
51656
|
async function postSkippedFilesFeedback(platform, threadId, skipped) {
|
|
51552
51657
|
if (skipped.length === 0)
|
|
51553
51658
|
return;
|
|
@@ -51615,7 +51720,7 @@ function formatRelativeTime(date8) {
|
|
|
51615
51720
|
return `${diffMin} min ago`;
|
|
51616
51721
|
}
|
|
51617
51722
|
// src/operations/message-manager.ts
|
|
51618
|
-
var
|
|
51723
|
+
var log4 = createLogger("msg-mgr");
|
|
51619
51724
|
|
|
51620
51725
|
class MessageManager {
|
|
51621
51726
|
platform;
|
|
@@ -51708,7 +51813,7 @@ class MessageManager {
|
|
|
51708
51813
|
});
|
|
51709
51814
|
}
|
|
51710
51815
|
async handleEvent(event) {
|
|
51711
|
-
const logger =
|
|
51816
|
+
const logger = log4.forSession(this.sessionId);
|
|
51712
51817
|
const transformCtx = {
|
|
51713
51818
|
sessionId: this.sessionId,
|
|
51714
51819
|
formatter: this.platform.getFormatter(),
|
|
@@ -51762,7 +51867,7 @@ class MessageManager {
|
|
|
51762
51867
|
}
|
|
51763
51868
|
}
|
|
51764
51869
|
async executeOperation(op) {
|
|
51765
|
-
const logger =
|
|
51870
|
+
const logger = log4.forSession(this.sessionId);
|
|
51766
51871
|
const ctx = this.getExecutorContext();
|
|
51767
51872
|
try {
|
|
51768
51873
|
if (isContentOp(op)) {
|
|
@@ -51830,7 +51935,7 @@ class MessageManager {
|
|
|
51830
51935
|
threadId: this.threadId,
|
|
51831
51936
|
platform: this.platform,
|
|
51832
51937
|
formatter: this.platform.getFormatter(),
|
|
51833
|
-
logger:
|
|
51938
|
+
logger: log4.forSession(this.sessionId),
|
|
51834
51939
|
postTracker: this.postTracker,
|
|
51835
51940
|
contentBreaker: this.contentBreaker,
|
|
51836
51941
|
threadLogger: this.session.threadLogger,
|
|
@@ -52050,13 +52155,13 @@ class MessageManager {
|
|
|
52050
52155
|
return this.systemExecutor.postSuccess(message, this.getExecutorContext());
|
|
52051
52156
|
}
|
|
52052
52157
|
async prepareForUserMessage() {
|
|
52053
|
-
const logger =
|
|
52158
|
+
const logger = log4.forSession(this.sessionId);
|
|
52054
52159
|
logger.debug("Preparing for new user message");
|
|
52055
52160
|
await this.closeCurrentPost();
|
|
52056
52161
|
await this.bumpTaskList();
|
|
52057
52162
|
}
|
|
52058
52163
|
async handleUserMessage(message, files, username, displayName) {
|
|
52059
|
-
const logger =
|
|
52164
|
+
const logger = log4.forSession(this.sessionId);
|
|
52060
52165
|
if (!this.session.claude.isRunning()) {
|
|
52061
52166
|
logger.debug("Claude not running, ignoring user message");
|
|
52062
52167
|
return false;
|
|
@@ -52099,7 +52204,7 @@ class MessageManager {
|
|
|
52099
52204
|
];
|
|
52100
52205
|
}
|
|
52101
52206
|
async handleReaction(postId, emoji4, user, action) {
|
|
52102
|
-
const logger =
|
|
52207
|
+
const logger = log4.forSession(this.sessionId);
|
|
52103
52208
|
const ctx = this.getExecutorContext();
|
|
52104
52209
|
logger.debug(`Routing reaction: postId=${postId}, emoji=${emoji4}, user=${user}, action=${action}`);
|
|
52105
52210
|
for (const { name, executor } of this.reactionDispatchList()) {
|
|
@@ -52196,7 +52301,7 @@ class MessageManager {
|
|
|
52196
52301
|
}
|
|
52197
52302
|
}
|
|
52198
52303
|
// src/session/lifecycle-fsm.ts
|
|
52199
|
-
var
|
|
52304
|
+
var log5 = createLogger("fsm");
|
|
52200
52305
|
var ALLOWED_TRANSITIONS = {
|
|
52201
52306
|
starting: new Set(["active", "paused", "interrupted", "cancelling", "restarting"]),
|
|
52202
52307
|
active: new Set([
|
|
@@ -52223,7 +52328,7 @@ var ALLOWED_TRANSITIONS = {
|
|
|
52223
52328
|
};
|
|
52224
52329
|
// src/config/index.ts
|
|
52225
52330
|
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
52226
|
-
import { homedir } from "os";
|
|
52331
|
+
import { homedir as homedir2 } from "os";
|
|
52227
52332
|
|
|
52228
52333
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
52229
52334
|
function getDefaultExportFromCjs(x) {
|
|
@@ -55335,7 +55440,7 @@ var jsYamlExports = requireJsYaml();
|
|
|
55335
55440
|
var yaml = /* @__PURE__ */ getDefaultExportFromCjs(jsYamlExports);
|
|
55336
55441
|
|
|
55337
55442
|
// src/config/index.ts
|
|
55338
|
-
var CONFIG_PATH = resolve2(
|
|
55443
|
+
var CONFIG_PATH = resolve2(homedir2(), ".config", "claude-threads", "config.yaml");
|
|
55339
55444
|
|
|
55340
55445
|
// src/utils/battery.ts
|
|
55341
55446
|
import { exec } from "child_process";
|
|
@@ -55440,7 +55545,7 @@ function formatReleaseNotes(notes, formatter) {
|
|
|
55440
55545
|
|
|
55441
55546
|
// src/utils/keep-alive.ts
|
|
55442
55547
|
import { spawn } from "child_process";
|
|
55443
|
-
var
|
|
55548
|
+
var log6 = createLogger("keepalive");
|
|
55444
55549
|
function keepAliveSpawnSpec(platform, parentPid) {
|
|
55445
55550
|
switch (platform) {
|
|
55446
55551
|
case "darwin":
|
|
@@ -55496,7 +55601,7 @@ class KeepAliveManager {
|
|
|
55496
55601
|
if (!enabled && this.keepAliveProcess) {
|
|
55497
55602
|
this.stopKeepAlive();
|
|
55498
55603
|
}
|
|
55499
|
-
|
|
55604
|
+
log6.debug(`Keep-alive ${enabled ? "enabled" : "disabled"}`);
|
|
55500
55605
|
}
|
|
55501
55606
|
isEnabled() {
|
|
55502
55607
|
return this.enabled;
|
|
@@ -55506,7 +55611,7 @@ class KeepAliveManager {
|
|
|
55506
55611
|
}
|
|
55507
55612
|
sessionStarted() {
|
|
55508
55613
|
this.activeSessionCount++;
|
|
55509
|
-
|
|
55614
|
+
log6.debug(`Session started (${this.activeSessionCount} active)`);
|
|
55510
55615
|
if (this.activeSessionCount === 1) {
|
|
55511
55616
|
this.startKeepAlive();
|
|
55512
55617
|
}
|
|
@@ -55515,7 +55620,7 @@ class KeepAliveManager {
|
|
|
55515
55620
|
if (this.activeSessionCount > 0) {
|
|
55516
55621
|
this.activeSessionCount--;
|
|
55517
55622
|
}
|
|
55518
|
-
|
|
55623
|
+
log6.debug(`Session ended (${this.activeSessionCount} active)`);
|
|
55519
55624
|
if (this.activeSessionCount === 0) {
|
|
55520
55625
|
this.stopKeepAlive();
|
|
55521
55626
|
}
|
|
@@ -55529,11 +55634,11 @@ class KeepAliveManager {
|
|
|
55529
55634
|
}
|
|
55530
55635
|
startKeepAlive() {
|
|
55531
55636
|
if (!this.enabled) {
|
|
55532
|
-
|
|
55637
|
+
log6.debug("Keep-alive disabled, skipping");
|
|
55533
55638
|
return;
|
|
55534
55639
|
}
|
|
55535
55640
|
if (this.keepAliveProcess) {
|
|
55536
|
-
|
|
55641
|
+
log6.debug("Keep-alive already running");
|
|
55537
55642
|
return;
|
|
55538
55643
|
}
|
|
55539
55644
|
switch (this.platform) {
|
|
@@ -55547,12 +55652,12 @@ class KeepAliveManager {
|
|
|
55547
55652
|
this.startWindowsKeepAlive();
|
|
55548
55653
|
break;
|
|
55549
55654
|
default:
|
|
55550
|
-
|
|
55655
|
+
log6.warn(`Keep-alive not supported on ${this.platform}`);
|
|
55551
55656
|
}
|
|
55552
55657
|
}
|
|
55553
55658
|
stopKeepAlive() {
|
|
55554
55659
|
if (this.keepAliveProcess) {
|
|
55555
|
-
|
|
55660
|
+
log6.debug("Stopping keep-alive");
|
|
55556
55661
|
this.keepAliveProcess.kill();
|
|
55557
55662
|
this.keepAliveProcess = null;
|
|
55558
55663
|
}
|
|
@@ -55567,18 +55672,18 @@ class KeepAliveManager {
|
|
|
55567
55672
|
detached: false
|
|
55568
55673
|
});
|
|
55569
55674
|
this.keepAliveProcess.on("error", (err) => {
|
|
55570
|
-
|
|
55675
|
+
log6.error(`Failed to start caffeinate: ${err.message}`);
|
|
55571
55676
|
this.keepAliveProcess = null;
|
|
55572
55677
|
});
|
|
55573
55678
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55574
55679
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55575
|
-
|
|
55680
|
+
log6.debug(`caffeinate exited with code ${code}`);
|
|
55576
55681
|
}
|
|
55577
55682
|
this.keepAliveProcess = null;
|
|
55578
55683
|
});
|
|
55579
|
-
|
|
55684
|
+
log6.info("Sleep prevention active (caffeinate)");
|
|
55580
55685
|
} catch (err) {
|
|
55581
|
-
|
|
55686
|
+
log6.error(`Failed to start caffeinate: ${err}`);
|
|
55582
55687
|
}
|
|
55583
55688
|
}
|
|
55584
55689
|
startLinuxKeepAlive() {
|
|
@@ -55591,19 +55696,19 @@ class KeepAliveManager {
|
|
|
55591
55696
|
detached: false
|
|
55592
55697
|
});
|
|
55593
55698
|
this.keepAliveProcess.on("error", (err) => {
|
|
55594
|
-
|
|
55699
|
+
log6.debug(`systemd-inhibit not available: ${err.message}`);
|
|
55595
55700
|
this.keepAliveProcess = null;
|
|
55596
55701
|
this.startLinuxKeepAliveFallback();
|
|
55597
55702
|
});
|
|
55598
55703
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55599
55704
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55600
|
-
|
|
55705
|
+
log6.debug(`systemd-inhibit exited with code ${code}`);
|
|
55601
55706
|
}
|
|
55602
55707
|
this.keepAliveProcess = null;
|
|
55603
55708
|
});
|
|
55604
|
-
|
|
55709
|
+
log6.info("Sleep prevention active (systemd-inhibit)");
|
|
55605
55710
|
} catch (err) {
|
|
55606
|
-
|
|
55711
|
+
log6.debug(`Failed to start systemd-inhibit: ${err}`);
|
|
55607
55712
|
this.startLinuxKeepAliveFallback();
|
|
55608
55713
|
}
|
|
55609
55714
|
}
|
|
@@ -55614,15 +55719,15 @@ class KeepAliveManager {
|
|
|
55614
55719
|
detached: false
|
|
55615
55720
|
});
|
|
55616
55721
|
this.keepAliveProcess.on("error", (err) => {
|
|
55617
|
-
|
|
55722
|
+
log6.warn(`Linux keep-alive fallback not available: ${err.message}`);
|
|
55618
55723
|
this.keepAliveProcess = null;
|
|
55619
55724
|
});
|
|
55620
55725
|
this.keepAliveProcess.on("exit", () => {
|
|
55621
55726
|
this.keepAliveProcess = null;
|
|
55622
55727
|
});
|
|
55623
|
-
|
|
55728
|
+
log6.info("Sleep prevention active (xdg-screensaver)");
|
|
55624
55729
|
} catch (err) {
|
|
55625
|
-
|
|
55730
|
+
log6.warn(`Linux keep-alive not available: ${err}`);
|
|
55626
55731
|
}
|
|
55627
55732
|
}
|
|
55628
55733
|
startWindowsKeepAlive() {
|
|
@@ -55634,18 +55739,18 @@ class KeepAliveManager {
|
|
|
55634
55739
|
windowsHide: true
|
|
55635
55740
|
});
|
|
55636
55741
|
this.keepAliveProcess.on("error", (err) => {
|
|
55637
|
-
|
|
55742
|
+
log6.warn(`Windows keep-alive not available: ${err.message}`);
|
|
55638
55743
|
this.keepAliveProcess = null;
|
|
55639
55744
|
});
|
|
55640
55745
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55641
55746
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55642
|
-
|
|
55747
|
+
log6.debug(`PowerShell keep-alive exited with code ${code}`);
|
|
55643
55748
|
}
|
|
55644
55749
|
this.keepAliveProcess = null;
|
|
55645
55750
|
});
|
|
55646
|
-
|
|
55751
|
+
log6.info("Sleep prevention active (SetThreadExecutionState)");
|
|
55647
55752
|
} catch (err) {
|
|
55648
|
-
|
|
55753
|
+
log6.warn(`Windows keep-alive not available: ${err}`);
|
|
55649
55754
|
}
|
|
55650
55755
|
}
|
|
55651
55756
|
}
|
|
@@ -55659,7 +55764,7 @@ function formatSponsorFooter(formatter) {
|
|
|
55659
55764
|
}
|
|
55660
55765
|
|
|
55661
55766
|
// src/operations/sticky-message/handler.ts
|
|
55662
|
-
var
|
|
55767
|
+
var log7 = createLogger("sticky");
|
|
55663
55768
|
var botStartedAt = new Date;
|
|
55664
55769
|
var stickyPostIds = new Map;
|
|
55665
55770
|
var needsBump = new Map;
|
|
@@ -55898,10 +56003,10 @@ class Redactor {
|
|
|
55898
56003
|
}
|
|
55899
56004
|
|
|
55900
56005
|
// src/persistence/thread-logger.ts
|
|
55901
|
-
import { homedir as
|
|
55902
|
-
import { join as
|
|
55903
|
-
var
|
|
55904
|
-
var LOGS_BASE_DIR =
|
|
56006
|
+
import { homedir as homedir3 } from "os";
|
|
56007
|
+
import { join as join3, dirname as dirname4 } from "path";
|
|
56008
|
+
var log8 = createLogger("thread-log");
|
|
56009
|
+
var LOGS_BASE_DIR = join3(homedir3(), ".claude-threads", "logs");
|
|
55905
56010
|
|
|
55906
56011
|
// src/operations/bug-report/handler.ts
|
|
55907
56012
|
var piiRedactor = new Redactor({ aggressive: true });
|
|
@@ -55924,7 +56029,7 @@ class UsernameAnonymizer {
|
|
|
55924
56029
|
// src/mcp/decision-bridge.ts
|
|
55925
56030
|
import { createServer, createConnection } from "node:net";
|
|
55926
56031
|
import { tmpdir } from "node:os";
|
|
55927
|
-
import { join as
|
|
56032
|
+
import { join as join4 } from "node:path";
|
|
55928
56033
|
import { randomUUID } from "node:crypto";
|
|
55929
56034
|
import { mkdtempSync } from "node:fs";
|
|
55930
56035
|
import { rm } from "node:fs/promises";
|
|
@@ -55935,8 +56040,8 @@ function bridgeSocketPath() {
|
|
|
55935
56040
|
if (process.platform === "win32") {
|
|
55936
56041
|
return `\\\\.\\pipe\\ctb-${randomUUID()}`;
|
|
55937
56042
|
}
|
|
55938
|
-
const dir = mkdtempSync(
|
|
55939
|
-
return
|
|
56043
|
+
const dir = mkdtempSync(join4(tmpdir(), "ctb-"));
|
|
56044
|
+
return join4(dir, "b.sock");
|
|
55940
56045
|
}
|
|
55941
56046
|
|
|
55942
56047
|
class DecisionBridgeServer {
|
|
@@ -56006,7 +56111,7 @@ class DecisionBridgeServer {
|
|
|
56006
56111
|
});
|
|
56007
56112
|
} catch (err) {
|
|
56008
56113
|
if (process.platform !== "win32") {
|
|
56009
|
-
await rm(
|
|
56114
|
+
await rm(join4(path, ".."), { recursive: true, force: true }).catch(() => {});
|
|
56010
56115
|
}
|
|
56011
56116
|
throw err;
|
|
56012
56117
|
}
|
|
@@ -56019,7 +56124,7 @@ class DecisionBridgeServer {
|
|
|
56019
56124
|
socket.destroy();
|
|
56020
56125
|
await new Promise((resolve4) => this.server.close(() => resolve4()));
|
|
56021
56126
|
if (process.platform !== "win32") {
|
|
56022
|
-
await rm(
|
|
56127
|
+
await rm(join4(this.path, ".."), { recursive: true, force: true }).catch(() => {});
|
|
56023
56128
|
}
|
|
56024
56129
|
}
|
|
56025
56130
|
}
|
|
@@ -56082,7 +56187,7 @@ import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
|
56082
56187
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
56083
56188
|
import { existsSync as existsSync4, readFileSync as readFileSync3, watchFile, unwatchFile, unlinkSync, statSync, readdirSync, writeFileSync } from "fs";
|
|
56084
56189
|
import { tmpdir as tmpdir2 } from "os";
|
|
56085
|
-
import { join as
|
|
56190
|
+
import { join as join5 } from "path";
|
|
56086
56191
|
|
|
56087
56192
|
// src/mcp/outbound-env.ts
|
|
56088
56193
|
var OUTBOUND_ENV = {
|
|
@@ -56173,25 +56278,25 @@ function parseRateLimitEvent(event, now = Date.now()) {
|
|
|
56173
56278
|
}
|
|
56174
56279
|
|
|
56175
56280
|
// src/claude/cli.ts
|
|
56176
|
-
var
|
|
56281
|
+
var log9 = createLogger("claude");
|
|
56177
56282
|
function cleanupBrowserBridgeSockets() {
|
|
56178
56283
|
try {
|
|
56179
56284
|
const tempDir = tmpdir2();
|
|
56180
56285
|
const files = readdirSync(tempDir);
|
|
56181
56286
|
for (const file2 of files) {
|
|
56182
56287
|
if (file2.startsWith("claude-mcp-browser-bridge-")) {
|
|
56183
|
-
const filePath =
|
|
56288
|
+
const filePath = join5(tempDir, file2);
|
|
56184
56289
|
try {
|
|
56185
56290
|
const stats = statSync(filePath);
|
|
56186
56291
|
if (stats.isSocket()) {
|
|
56187
56292
|
unlinkSync(filePath);
|
|
56188
|
-
|
|
56293
|
+
log9.debug(`Removed stale browser bridge socket: ${file2}`);
|
|
56189
56294
|
}
|
|
56190
56295
|
} catch {}
|
|
56191
56296
|
}
|
|
56192
56297
|
}
|
|
56193
56298
|
} catch (err) {
|
|
56194
|
-
|
|
56299
|
+
log9.debug(`Browser bridge cleanup failed: ${err}`);
|
|
56195
56300
|
}
|
|
56196
56301
|
}
|
|
56197
56302
|
function buildClaudeChildEnv(parentEnv, account, opts) {
|
|
@@ -56250,7 +56355,7 @@ function materializeMcpConfig(config3, sessionId, opts = {}) {
|
|
|
56250
56355
|
return { mode: "inline", value: JSON.stringify(config3) };
|
|
56251
56356
|
}
|
|
56252
56357
|
const dir = opts.tmpDirOverride ?? tmpdir2();
|
|
56253
|
-
const path =
|
|
56358
|
+
const path = join5(dir, `claude-threads-mcp-${sessionId ?? process.pid}-${Date.now()}.json`);
|
|
56254
56359
|
writeFileSync(path, JSON.stringify(config3), { mode: 384 });
|
|
56255
56360
|
return { mode: "file", path };
|
|
56256
56361
|
}
|
|
@@ -56433,7 +56538,7 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
56433
56538
|
}
|
|
56434
56539
|
let statusLineCommand;
|
|
56435
56540
|
if (this.options.sessionId) {
|
|
56436
|
-
this.statusFilePath =
|
|
56541
|
+
this.statusFilePath = join5(tmpdir2(), `claude-threads-status-${this.options.sessionId}.json`);
|
|
56437
56542
|
const statusLineWriterPath = this.getStatusLineWriterPath();
|
|
56438
56543
|
const runtime = runtimeForScriptPath(statusLineWriterPath);
|
|
56439
56544
|
statusLineCommand = `${runtime} ${statusLineWriterPath} ${this.options.sessionId}`;
|
|
@@ -57355,7 +57460,7 @@ handlers.set("compact", createPassthroughHandler("compact"));
|
|
|
57355
57460
|
handlers.set("model", createPassthroughHandler("model"));
|
|
57356
57461
|
handlers.set("effort", createPassthroughHandler("effort"));
|
|
57357
57462
|
// src/commands/system-prompt-generator.ts
|
|
57358
|
-
var
|
|
57463
|
+
var log10 = createLogger("system-prompt");
|
|
57359
57464
|
function formatUserCommand(cmd) {
|
|
57360
57465
|
const cmdStr = cmd.args ? `\`!${cmd.command} ${cmd.args}\`` : `\`!${cmd.command}\``;
|
|
57361
57466
|
const description = cmd.description;
|
|
@@ -57440,7 +57545,7 @@ ${avoidCommands.map((c) => `- \`!${c.command}\` - ${c.reason}`).join(`
|
|
|
57440
57545
|
`.trim();
|
|
57441
57546
|
}
|
|
57442
57547
|
// src/utils/error-handler/index.ts
|
|
57443
|
-
var
|
|
57548
|
+
var log11 = createLogger("error");
|
|
57444
57549
|
|
|
57445
57550
|
// src/utils/session-log.ts
|
|
57446
57551
|
function createSessionLog(baseLog) {
|
|
@@ -57457,45 +57562,45 @@ init_emoji();
|
|
|
57457
57562
|
|
|
57458
57563
|
// src/git/worktree.ts
|
|
57459
57564
|
import * as path from "path";
|
|
57460
|
-
import { homedir as
|
|
57461
|
-
var
|
|
57462
|
-
var WORKTREES_DIR = path.join(
|
|
57463
|
-
var METADATA_STORE_PATH = path.join(
|
|
57565
|
+
import { homedir as homedir4 } from "os";
|
|
57566
|
+
var log12 = createLogger("git-wt");
|
|
57567
|
+
var WORKTREES_DIR = path.join(homedir4(), ".claude-threads", "worktrees");
|
|
57568
|
+
var METADATA_STORE_PATH = path.join(homedir4(), ".claude-threads", "worktree-metadata.json");
|
|
57464
57569
|
|
|
57465
57570
|
// src/operations/post-helpers/index.ts
|
|
57466
|
-
var
|
|
57467
|
-
var sessionLog = createSessionLog(
|
|
57571
|
+
var log13 = createLogger("helpers");
|
|
57572
|
+
var sessionLog = createSessionLog(log13);
|
|
57468
57573
|
|
|
57469
57574
|
// src/claude/quick-query.ts
|
|
57470
|
-
var
|
|
57575
|
+
var log14 = createLogger("query");
|
|
57471
57576
|
|
|
57472
57577
|
// src/operations/suggestions/title.ts
|
|
57473
|
-
var
|
|
57578
|
+
var log15 = createLogger("title");
|
|
57474
57579
|
|
|
57475
57580
|
// src/operations/suggestions/tag.ts
|
|
57476
|
-
var
|
|
57581
|
+
var log16 = createLogger("tags");
|
|
57477
57582
|
|
|
57478
57583
|
// src/operations/context-prompt/handler.ts
|
|
57479
57584
|
init_emoji();
|
|
57480
|
-
var
|
|
57481
|
-
var sessionLog2 = createSessionLog(
|
|
57585
|
+
var log17 = createLogger("context");
|
|
57586
|
+
var sessionLog2 = createSessionLog(log17);
|
|
57482
57587
|
var contextPromptTimeouts = new Map;
|
|
57483
57588
|
var contextPromptFiles = new Map;
|
|
57484
57589
|
// src/memory/store.ts
|
|
57485
57590
|
import { createHash } from "crypto";
|
|
57486
57591
|
import {
|
|
57487
|
-
chmodSync,
|
|
57592
|
+
chmodSync as chmodSync2,
|
|
57488
57593
|
existsSync as existsSync5,
|
|
57489
|
-
mkdirSync,
|
|
57594
|
+
mkdirSync as mkdirSync2,
|
|
57490
57595
|
readFileSync as readFileSync4,
|
|
57491
57596
|
renameSync,
|
|
57492
57597
|
realpathSync,
|
|
57493
57598
|
writeFileSync as writeFileSync2
|
|
57494
57599
|
} from "fs";
|
|
57495
|
-
import { homedir as
|
|
57496
|
-
import { basename as basename3, dirname as dirname7, join as
|
|
57497
|
-
var
|
|
57498
|
-
var DEFAULT_ROOT =
|
|
57600
|
+
import { homedir as homedir5 } from "os";
|
|
57601
|
+
import { basename as basename3, dirname as dirname7, join as join7, sep as sep2 } from "path";
|
|
57602
|
+
var log18 = createLogger("memory");
|
|
57603
|
+
var DEFAULT_ROOT = join7(homedir5(), ".config", "claude-threads", "memory");
|
|
57499
57604
|
var CHANNEL_BLOCK_MAX_LINES = 200;
|
|
57500
57605
|
var CHANNEL_BLOCK_MAX_BYTES = 25 * 1024;
|
|
57501
57606
|
var CHANNEL_FILE_MAX_ENTRIES = 400;
|
|
@@ -57538,10 +57643,10 @@ class MemoryStore {
|
|
|
57538
57643
|
return this.root;
|
|
57539
57644
|
}
|
|
57540
57645
|
channelMemoryPath(platformId) {
|
|
57541
|
-
return
|
|
57646
|
+
return join7(this.root, platformSegment(platformId), "channel", "MEMORY.md");
|
|
57542
57647
|
}
|
|
57543
57648
|
repoMemoryDir(platformId, repoKey) {
|
|
57544
|
-
const dir =
|
|
57649
|
+
const dir = join7(this.root, platformSegment(platformId), "repos", repoKey);
|
|
57545
57650
|
this.ensureDir(dir);
|
|
57546
57651
|
return dir;
|
|
57547
57652
|
}
|
|
@@ -57588,7 +57693,7 @@ class MemoryStore {
|
|
|
57588
57693
|
if (result.added.length > 0) {
|
|
57589
57694
|
this.enforceFileCap(lines);
|
|
57590
57695
|
this.writeLines(platformId, lines);
|
|
57591
|
-
|
|
57696
|
+
log18.debug(`Channel memory for ${platformId}: +${result.added.length} entries` + (result.duplicates.length ? ` (${result.duplicates.length} duplicates skipped)` : ""));
|
|
57592
57697
|
}
|
|
57593
57698
|
return result;
|
|
57594
57699
|
});
|
|
@@ -57627,14 +57732,14 @@ class MemoryStore {
|
|
|
57627
57732
|
}
|
|
57628
57733
|
lines.splice(target.lineIndex, 1);
|
|
57629
57734
|
this.writeLines(platformId, lines);
|
|
57630
|
-
|
|
57735
|
+
log18.debug(`Channel memory for ${platformId}: removed one entry`);
|
|
57631
57736
|
return { ok: true, removed: target.entry };
|
|
57632
57737
|
});
|
|
57633
57738
|
}
|
|
57634
57739
|
clearChannel(platformId) {
|
|
57635
57740
|
return this.runExclusive(platformId, () => {
|
|
57636
57741
|
this.writeLines(platformId, []);
|
|
57637
|
-
|
|
57742
|
+
log18.debug(`Channel memory for ${platformId}: cleared`);
|
|
57638
57743
|
});
|
|
57639
57744
|
}
|
|
57640
57745
|
buildChannelMemoryBlock(platformId) {
|
|
@@ -57642,7 +57747,7 @@ class MemoryStore {
|
|
|
57642
57747
|
try {
|
|
57643
57748
|
lines = this.loadLines(platformId);
|
|
57644
57749
|
} catch (err) {
|
|
57645
|
-
|
|
57750
|
+
log18.warn(`Failed to read channel memory for ${platformId}: ${err.message}`);
|
|
57646
57751
|
return null;
|
|
57647
57752
|
}
|
|
57648
57753
|
if (lines.length === 0)
|
|
@@ -57717,21 +57822,22 @@ _(older entries omitted — \`!memory\` shows all)_` : rendered;
|
|
|
57717
57822
|
const tempFile = `${file2}.tmp`;
|
|
57718
57823
|
writeFileSync2(tempFile, content, { encoding: "utf-8", mode: 384 });
|
|
57719
57824
|
renameSync(tempFile, file2);
|
|
57720
|
-
|
|
57825
|
+
chmodSync2(file2, 384);
|
|
57721
57826
|
}
|
|
57722
57827
|
ensureDir(dir) {
|
|
57723
57828
|
if (!existsSync5(dir)) {
|
|
57724
|
-
|
|
57829
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
57725
57830
|
}
|
|
57726
57831
|
}
|
|
57727
57832
|
}
|
|
57728
57833
|
|
|
57729
57834
|
// src/memory/distiller.ts
|
|
57730
|
-
var
|
|
57835
|
+
var log19 = createLogger("memory");
|
|
57731
57836
|
|
|
57732
57837
|
// src/session/lifecycle.ts
|
|
57733
|
-
var
|
|
57734
|
-
var sessionLog3 = createSessionLog(
|
|
57838
|
+
var log20 = createLogger("lifecycle");
|
|
57839
|
+
var sessionLog3 = createSessionLog(log20);
|
|
57840
|
+
var _inFlightSessionStarts = new Map;
|
|
57735
57841
|
var CHAT_PLATFORM_PROMPT = generateChatPlatformPrompt();
|
|
57736
57842
|
// src/update-notifier.ts
|
|
57737
57843
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
@@ -57740,20 +57846,20 @@ var import_semver2 = __toESM(require_semver2(), 1);
|
|
|
57740
57846
|
init_emoji();
|
|
57741
57847
|
|
|
57742
57848
|
// src/persistence/github-emails-store.ts
|
|
57743
|
-
import { homedir as homedir5 } from "os";
|
|
57744
|
-
import { join as join7 } from "path";
|
|
57745
|
-
var log20 = createLogger("gh-emails");
|
|
57746
|
-
var DEFAULT_CONFIG_DIR = join7(homedir5(), ".config", "claude-threads");
|
|
57747
|
-
var DEFAULT_FILE = join7(DEFAULT_CONFIG_DIR, "github-emails.yaml");
|
|
57748
|
-
|
|
57749
|
-
// src/persistence/routines-store.ts
|
|
57750
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "fs";
|
|
57751
57849
|
import { homedir as homedir6 } from "os";
|
|
57752
57850
|
import { join as join8 } from "path";
|
|
57851
|
+
var log21 = createLogger("gh-emails");
|
|
57852
|
+
var DEFAULT_CONFIG_DIR = join8(homedir6(), ".config", "claude-threads");
|
|
57853
|
+
var DEFAULT_FILE = join8(DEFAULT_CONFIG_DIR, "github-emails.yaml");
|
|
57854
|
+
|
|
57855
|
+
// src/persistence/routines-store.ts
|
|
57856
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
|
|
57857
|
+
import { homedir as homedir7 } from "os";
|
|
57858
|
+
import { join as join9 } from "path";
|
|
57753
57859
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
57754
57860
|
|
|
57755
57861
|
// src/persistence/atomic-file.ts
|
|
57756
|
-
import { chmodSync as
|
|
57862
|
+
import { chmodSync as chmodSync3, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
57757
57863
|
|
|
57758
57864
|
class SerialQueue {
|
|
57759
57865
|
tail = Promise.resolve();
|
|
@@ -57769,13 +57875,13 @@ function writeFileAtomic(file2, content) {
|
|
|
57769
57875
|
const tempFile = `${file2}.tmp`;
|
|
57770
57876
|
writeFileSync3(tempFile, content, { encoding: "utf-8", mode: 384 });
|
|
57771
57877
|
renameSync2(tempFile, file2);
|
|
57772
|
-
|
|
57878
|
+
chmodSync3(file2, 384);
|
|
57773
57879
|
}
|
|
57774
57880
|
|
|
57775
57881
|
// src/persistence/routines-store.ts
|
|
57776
|
-
var
|
|
57777
|
-
var DEFAULT_CONFIG_DIR2 =
|
|
57778
|
-
var DEFAULT_FILE2 =
|
|
57882
|
+
var log22 = createLogger("routines");
|
|
57883
|
+
var DEFAULT_CONFIG_DIR2 = join9(homedir7(), ".config", "claude-threads");
|
|
57884
|
+
var DEFAULT_FILE2 = join9(DEFAULT_CONFIG_DIR2, "routines.yaml");
|
|
57779
57885
|
var STORE_VERSION = 1;
|
|
57780
57886
|
var DEFAULT_MAX_ROUTINES = 10;
|
|
57781
57887
|
var SCHEDULE_PRESETS = ["hourly", "daily", "weekdays", "weekly"];
|
|
@@ -57819,13 +57925,13 @@ class RoutinesStore {
|
|
|
57819
57925
|
const effective = filePath ?? process.env.CLAUDE_THREADS_ROUTINES_PATH;
|
|
57820
57926
|
if (effective) {
|
|
57821
57927
|
this.file = effective;
|
|
57822
|
-
this.configDir =
|
|
57928
|
+
this.configDir = join9(effective, "..");
|
|
57823
57929
|
} else {
|
|
57824
57930
|
this.file = DEFAULT_FILE2;
|
|
57825
57931
|
this.configDir = DEFAULT_CONFIG_DIR2;
|
|
57826
57932
|
}
|
|
57827
57933
|
if (!existsSync6(this.configDir)) {
|
|
57828
|
-
|
|
57934
|
+
mkdirSync3(this.configDir, { recursive: true, mode: 448 });
|
|
57829
57935
|
}
|
|
57830
57936
|
}
|
|
57831
57937
|
list(platformId) {
|
|
@@ -57859,7 +57965,7 @@ class RoutinesStore {
|
|
|
57859
57965
|
};
|
|
57860
57966
|
data.routines[platformId] = [...existing, full];
|
|
57861
57967
|
this.writeAtomic(data);
|
|
57862
|
-
|
|
57968
|
+
log22.info(`Routine "${full.name}" created on ${platformId} by @${full.createdBy}`);
|
|
57863
57969
|
return { ok: true, routine: full };
|
|
57864
57970
|
});
|
|
57865
57971
|
}
|
|
@@ -57886,7 +57992,7 @@ class RoutinesStore {
|
|
|
57886
57992
|
if (routines.length === 0)
|
|
57887
57993
|
delete data.routines[platformId];
|
|
57888
57994
|
this.writeAtomic(data);
|
|
57889
|
-
|
|
57995
|
+
log22.info(`Routine "${removed.name}" removed from ${platformId}`);
|
|
57890
57996
|
return removed;
|
|
57891
57997
|
});
|
|
57892
57998
|
}
|
|
@@ -57911,7 +58017,7 @@ class RoutinesStore {
|
|
|
57911
58017
|
}
|
|
57912
58018
|
return { version: parsed.version ?? STORE_VERSION, routines };
|
|
57913
58019
|
} catch (err) {
|
|
57914
|
-
|
|
58020
|
+
log22.warn(`Failed to read ${this.file}: ${err.message} — starting empty`);
|
|
57915
58021
|
return { version: STORE_VERSION, routines: {} };
|
|
57916
58022
|
}
|
|
57917
58023
|
}
|
|
@@ -57921,25 +58027,25 @@ class RoutinesStore {
|
|
|
57921
58027
|
}
|
|
57922
58028
|
|
|
57923
58029
|
// src/routines/parser.ts
|
|
57924
|
-
var
|
|
58030
|
+
var log23 = createLogger("routines");
|
|
57925
58031
|
|
|
57926
58032
|
// src/operations/commands/handler.ts
|
|
57927
|
-
var
|
|
57928
|
-
var sessionLog4 = createSessionLog(
|
|
58033
|
+
var log24 = createLogger("commands");
|
|
58034
|
+
var sessionLog4 = createSessionLog(log24);
|
|
57929
58035
|
// src/operations/suggestions/branch.ts
|
|
57930
58036
|
import { exec as exec2 } from "child_process";
|
|
57931
58037
|
import { promisify as promisify2 } from "util";
|
|
57932
58038
|
var execAsync2 = promisify2(exec2);
|
|
57933
|
-
var
|
|
58039
|
+
var log25 = createLogger("branch");
|
|
57934
58040
|
|
|
57935
58041
|
// src/operations/worktree/handler.ts
|
|
57936
|
-
var
|
|
57937
|
-
var sessionLog5 = createSessionLog(
|
|
58042
|
+
var log26 = createLogger("worktree");
|
|
58043
|
+
var sessionLog5 = createSessionLog(log26);
|
|
57938
58044
|
// src/operations/events/handler.ts
|
|
57939
|
-
var
|
|
57940
|
-
var sessionLog6 = createSessionLog(
|
|
58045
|
+
var log27 = createLogger("events");
|
|
58046
|
+
var sessionLog6 = createSessionLog(log27);
|
|
57941
58047
|
// src/operations/monitor/handler.ts
|
|
57942
|
-
var
|
|
58048
|
+
var log28 = createLogger("monitor");
|
|
57943
58049
|
var DEFAULT_INTERVAL_MS = 60 * 1000;
|
|
57944
58050
|
// src/utils/websocket.ts
|
|
57945
58051
|
var WS;
|
|
@@ -58021,7 +58127,7 @@ ${code}
|
|
|
58021
58127
|
|
|
58022
58128
|
// src/platform/mattermost/upload.ts
|
|
58023
58129
|
import { readFile } from "fs/promises";
|
|
58024
|
-
var
|
|
58130
|
+
var log29 = createLogger("mm-upload");
|
|
58025
58131
|
async function uploadFileMattermost(args) {
|
|
58026
58132
|
const { url: url2, token, channelId, threadId, filePath, filename, caption } = args;
|
|
58027
58133
|
const buffer = await readFile(filePath);
|
|
@@ -58029,7 +58135,7 @@ async function uploadFileMattermost(args) {
|
|
|
58029
58135
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
58030
58136
|
const formData = new FormData;
|
|
58031
58137
|
formData.append("files", new Blob([arrayBuffer]), filename);
|
|
58032
|
-
|
|
58138
|
+
log29.debug(`POST /files (${buffer.length} bytes, ${filename})`);
|
|
58033
58139
|
const uploadResponse = await fetch(uploadUrl, {
|
|
58034
58140
|
method: "POST",
|
|
58035
58141
|
headers: {
|
|
@@ -58050,10 +58156,10 @@ async function uploadFileMattermost(args) {
|
|
|
58050
58156
|
const postBody = {
|
|
58051
58157
|
channel_id: channelId,
|
|
58052
58158
|
message: caption ?? "",
|
|
58053
|
-
root_id: threadId,
|
|
58159
|
+
root_id: resolvePostThreadId(threadId),
|
|
58054
58160
|
file_ids: [fileInfo.id]
|
|
58055
58161
|
};
|
|
58056
|
-
|
|
58162
|
+
log29.debug(`POST /posts (file_ids=[${fileInfo.id}])`);
|
|
58057
58163
|
const postResponse = await fetch(postUrl, {
|
|
58058
58164
|
method: "POST",
|
|
58059
58165
|
headers: {
|
|
@@ -58106,7 +58212,7 @@ async function createPost(config3, channelId, message, rootId) {
|
|
|
58106
58212
|
return mattermostApi(config3, "POST", "/posts", {
|
|
58107
58213
|
channel_id: channelId,
|
|
58108
58214
|
message,
|
|
58109
|
-
root_id: rootId
|
|
58215
|
+
root_id: resolvePostThreadId(rootId)
|
|
58110
58216
|
});
|
|
58111
58217
|
}
|
|
58112
58218
|
async function updatePostRaw(config3, postId, message) {
|
|
@@ -58547,7 +58653,7 @@ ${code}
|
|
|
58547
58653
|
|
|
58548
58654
|
// src/platform/slack/upload.ts
|
|
58549
58655
|
import { readFile as readFile2 } from "fs/promises";
|
|
58550
|
-
var
|
|
58656
|
+
var log30 = createLogger("slack-upload");
|
|
58551
58657
|
var DEFAULT_API_URL = "https://slack.com/api";
|
|
58552
58658
|
async function uploadFileSlack(args) {
|
|
58553
58659
|
const { botToken, channelId, threadTs, filePath, filename, caption } = args;
|
|
@@ -58555,7 +58661,7 @@ async function uploadFileSlack(args) {
|
|
|
58555
58661
|
const buffer = await readFile2(filePath);
|
|
58556
58662
|
const params = new URLSearchParams({ filename, length: String(buffer.length) });
|
|
58557
58663
|
const step1Url = `${apiUrl}/files.getUploadURLExternal?${params.toString()}`;
|
|
58558
|
-
|
|
58664
|
+
log30.debug(`GET files.getUploadURLExternal (${buffer.length} bytes, ${filename})`);
|
|
58559
58665
|
const step1Response = await fetch(step1Url, {
|
|
58560
58666
|
method: "GET",
|
|
58561
58667
|
headers: {
|
|
@@ -58573,7 +58679,7 @@ async function uploadFileSlack(args) {
|
|
|
58573
58679
|
const uploadUrl = step1Data.upload_url;
|
|
58574
58680
|
const fileId = step1Data.file_id;
|
|
58575
58681
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
58576
|
-
|
|
58682
|
+
log30.debug(`POST <upload_url>`);
|
|
58577
58683
|
const step2Response = await fetch(uploadUrl, {
|
|
58578
58684
|
method: "POST",
|
|
58579
58685
|
headers: {
|
|
@@ -58588,12 +58694,12 @@ async function uploadFileSlack(args) {
|
|
|
58588
58694
|
const step3Body = {
|
|
58589
58695
|
files: [{ id: fileId, title: caption ?? filename }],
|
|
58590
58696
|
channel_id: channelId,
|
|
58591
|
-
thread_ts: threadTs
|
|
58697
|
+
thread_ts: resolvePostThreadId(threadTs)
|
|
58592
58698
|
};
|
|
58593
58699
|
if (caption !== undefined) {
|
|
58594
58700
|
step3Body.initial_comment = caption;
|
|
58595
58701
|
}
|
|
58596
|
-
|
|
58702
|
+
log30.debug(`POST files.completeUploadExternal (file_id=${fileId}, thread_ts=${threadTs})`);
|
|
58597
58703
|
const step3Response = await fetch(`${apiUrl}/files.completeUploadExternal`, {
|
|
58598
58704
|
method: "POST",
|
|
58599
58705
|
headers: {
|
|
@@ -58611,7 +58717,7 @@ async function uploadFileSlack(args) {
|
|
|
58611
58717
|
throw new Error(`Slack completeUploadExternal error: ${step3Data.error || "unknown"}`);
|
|
58612
58718
|
}
|
|
58613
58719
|
if (!step3Data.ts) {
|
|
58614
|
-
|
|
58720
|
+
log30.warn(`Slack completeUploadExternal returned no ts; using fileId ${fileId} as postId. ` + `Do not use this id for updatePost/addReaction.`);
|
|
58615
58721
|
}
|
|
58616
58722
|
return { fileId, postId: step3Data.ts ?? fileId };
|
|
58617
58723
|
}
|
|
@@ -58687,7 +58793,7 @@ class SlackMcpPlatformApi {
|
|
|
58687
58793
|
const response = await slackApi("chat.postMessage", this.config.botToken, {
|
|
58688
58794
|
channel: this.config.channelId,
|
|
58689
58795
|
text: message,
|
|
58690
|
-
thread_ts: threadTs || this.config.threadTs,
|
|
58796
|
+
thread_ts: resolvePostThreadId(threadTs || this.config.threadTs),
|
|
58691
58797
|
mrkdwn: true
|
|
58692
58798
|
});
|
|
58693
58799
|
const messageTs = response.ts;
|
|
@@ -59631,6 +59737,12 @@ async function resolveLatestThreadPost(cfg) {
|
|
|
59631
59737
|
if (!cfg.sessionThreadId) {
|
|
59632
59738
|
return { ok: false, reason: "no session thread to react in — pass a permalink URL instead" };
|
|
59633
59739
|
}
|
|
59740
|
+
if (isDcmThreadId(cfg.sessionThreadId)) {
|
|
59741
|
+
return {
|
|
59742
|
+
ok: false,
|
|
59743
|
+
reason: "this session runs in direct channel mode (no thread of its own) — pass a permalink URL to the target message instead"
|
|
59744
|
+
};
|
|
59745
|
+
}
|
|
59634
59746
|
let thread;
|
|
59635
59747
|
try {
|
|
59636
59748
|
thread = await cfg.api.readThread(cfg.sessionThreadId);
|
|
@@ -59732,6 +59844,12 @@ async function handleListThreadWith(args, cfg) {
|
|
|
59732
59844
|
reason: "no session thread to read — pass a permalink URL instead"
|
|
59733
59845
|
};
|
|
59734
59846
|
}
|
|
59847
|
+
if (isDcmThreadId(cfg.sessionThreadId)) {
|
|
59848
|
+
return {
|
|
59849
|
+
ok: false,
|
|
59850
|
+
reason: "this session runs in direct channel mode (no thread of its own) — use read_channel_history, or pass a permalink URL"
|
|
59851
|
+
};
|
|
59852
|
+
}
|
|
59735
59853
|
rootId = cfg.sessionThreadId;
|
|
59736
59854
|
}
|
|
59737
59855
|
const limit = clampThreadLimit(args.max_messages);
|