claude-threads 1.0.0 → 1.0.2
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 +15 -0
- package/dist/index.js +205 -163
- package/dist/mcp/permission-server.js +21 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.2] - 2026-01-13
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Session header posts deleted by sticky cleanup** - Fixed bug where session header and task list posts were incorrectly deleted by the sticky message cleanup function (#204)
|
|
12
|
+
- **Table rendering regression** - Fixed pipe escaping in `formatKeyValueList` and missing blank line before tables (#203)
|
|
13
|
+
|
|
14
|
+
## [1.0.1] - 2026-01-13
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Cleaner session header** - Simplified session start message, moved detailed info to help menu (#202)
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Worktree prompt skipped when branch specified** - When starting a session with a branch name in the initial message (e.g., `@bot on branch fix/bug do X`), worktree prompt is now correctly skipped (#201)
|
|
21
|
+
- **Pipe characters in markdown tables** - Fixed escaping of `|` characters in help menu table rows (#200)
|
|
22
|
+
|
|
8
23
|
## [1.0.0] - 2026-01-13
|
|
9
24
|
|
|
10
25
|
### Changed
|
package/dist/index.js
CHANGED
|
@@ -11826,11 +11826,11 @@ var require_util3 = __commonJS((exports) => {
|
|
|
11826
11826
|
if (files.includes("node_modules") || files.includes("package.json") || files.includes("package.json5") || files.includes("package.yaml") || files.includes("pnpm-workspace.yaml")) {
|
|
11827
11827
|
return name2;
|
|
11828
11828
|
}
|
|
11829
|
-
const
|
|
11830
|
-
if (
|
|
11829
|
+
const dirname8 = path6.dirname(name2);
|
|
11830
|
+
if (dirname8 === name2) {
|
|
11831
11831
|
return original;
|
|
11832
11832
|
}
|
|
11833
|
-
return find(
|
|
11833
|
+
return find(dirname8, original);
|
|
11834
11834
|
} catch (error) {
|
|
11835
11835
|
if (name2 === original) {
|
|
11836
11836
|
if (error.code === "ENOENT") {
|
|
@@ -46708,14 +46708,16 @@ ${code}
|
|
|
46708
46708
|
return text.replace(/([*_`[\]()#+\-.!])/g, "\\$1");
|
|
46709
46709
|
}
|
|
46710
46710
|
formatTable(headers, rows) {
|
|
46711
|
-
const
|
|
46711
|
+
const escapeCell = (cell) => cell.replace(/\|/g, "\\|");
|
|
46712
|
+
const headerRow = `| ${headers.map(escapeCell).join(" | ")} |`;
|
|
46712
46713
|
const separatorRow = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
46713
|
-
const dataRows = rows.map((row) => `| ${row.join(" | ")} |`);
|
|
46714
|
+
const dataRows = rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`);
|
|
46714
46715
|
return [headerRow, separatorRow, ...dataRows].join(`
|
|
46715
46716
|
`);
|
|
46716
46717
|
}
|
|
46717
46718
|
formatKeyValueList(items) {
|
|
46718
|
-
const
|
|
46719
|
+
const escapeCell = (cell) => cell.replace(/\|/g, "\\|");
|
|
46720
|
+
const rows = items.map(([icon, label, value]) => `| ${icon} ${this.formatBold(escapeCell(label))} | ${escapeCell(value)} |`);
|
|
46719
46721
|
return ["| | |", "|---|---|", ...rows].join(`
|
|
46720
46722
|
`);
|
|
46721
46723
|
}
|
|
@@ -54499,6 +54501,121 @@ function formatUptime(startedAt) {
|
|
|
54499
54501
|
return `${minutes}m`;
|
|
54500
54502
|
}
|
|
54501
54503
|
|
|
54504
|
+
// src/changelog.ts
|
|
54505
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
54506
|
+
import { dirname as dirname7, resolve as resolve4 } from "path";
|
|
54507
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
54508
|
+
var __dirname4 = dirname7(fileURLToPath4(import.meta.url));
|
|
54509
|
+
function getReleaseNotes(version) {
|
|
54510
|
+
const possiblePaths = [
|
|
54511
|
+
resolve4(__dirname4, "..", "CHANGELOG.md"),
|
|
54512
|
+
resolve4(__dirname4, "..", "..", "CHANGELOG.md")
|
|
54513
|
+
];
|
|
54514
|
+
let changelogPath = null;
|
|
54515
|
+
for (const p of possiblePaths) {
|
|
54516
|
+
if (existsSync8(p)) {
|
|
54517
|
+
changelogPath = p;
|
|
54518
|
+
break;
|
|
54519
|
+
}
|
|
54520
|
+
}
|
|
54521
|
+
if (!changelogPath) {
|
|
54522
|
+
return null;
|
|
54523
|
+
}
|
|
54524
|
+
try {
|
|
54525
|
+
const content = readFileSync7(changelogPath, "utf-8");
|
|
54526
|
+
return parseChangelog(content, version);
|
|
54527
|
+
} catch {
|
|
54528
|
+
return null;
|
|
54529
|
+
}
|
|
54530
|
+
}
|
|
54531
|
+
function parseChangelog(content, targetVersion) {
|
|
54532
|
+
const lines = content.split(`
|
|
54533
|
+
`);
|
|
54534
|
+
let currentVersion = null;
|
|
54535
|
+
let currentDate = null;
|
|
54536
|
+
let currentSection = null;
|
|
54537
|
+
let sections = {};
|
|
54538
|
+
let foundTarget = false;
|
|
54539
|
+
for (const line of lines) {
|
|
54540
|
+
const versionMatch = line.match(/^## \[(\d+\.\d+\.\d+)\](?: - (\d{4}-\d{2}-\d{2}))?/);
|
|
54541
|
+
if (versionMatch) {
|
|
54542
|
+
if (foundTarget) {
|
|
54543
|
+
break;
|
|
54544
|
+
}
|
|
54545
|
+
currentVersion = versionMatch[1];
|
|
54546
|
+
currentDate = versionMatch[2] || "";
|
|
54547
|
+
sections = {};
|
|
54548
|
+
currentSection = null;
|
|
54549
|
+
if (!targetVersion || currentVersion === targetVersion) {
|
|
54550
|
+
foundTarget = true;
|
|
54551
|
+
}
|
|
54552
|
+
continue;
|
|
54553
|
+
}
|
|
54554
|
+
if (!foundTarget)
|
|
54555
|
+
continue;
|
|
54556
|
+
const sectionMatch = line.match(/^### (\w+)/);
|
|
54557
|
+
if (sectionMatch) {
|
|
54558
|
+
currentSection = sectionMatch[1];
|
|
54559
|
+
sections[currentSection] = [];
|
|
54560
|
+
continue;
|
|
54561
|
+
}
|
|
54562
|
+
const itemMatch = line.match(/^- (.+)/);
|
|
54563
|
+
if (itemMatch && currentSection) {
|
|
54564
|
+
sections[currentSection].push(itemMatch[1]);
|
|
54565
|
+
}
|
|
54566
|
+
}
|
|
54567
|
+
if (!foundTarget || !currentVersion) {
|
|
54568
|
+
return null;
|
|
54569
|
+
}
|
|
54570
|
+
return {
|
|
54571
|
+
version: currentVersion,
|
|
54572
|
+
date: currentDate || "",
|
|
54573
|
+
sections
|
|
54574
|
+
};
|
|
54575
|
+
}
|
|
54576
|
+
function formatReleaseNotes(notes, formatter) {
|
|
54577
|
+
let msg = `${formatter.formatHeading(`\uD83D\uDCCB Release Notes - v${notes.version}`, 3)}`;
|
|
54578
|
+
if (notes.date) {
|
|
54579
|
+
msg += ` (${notes.date})`;
|
|
54580
|
+
}
|
|
54581
|
+
msg += `
|
|
54582
|
+
|
|
54583
|
+
`;
|
|
54584
|
+
for (const [section, items] of Object.entries(notes.sections)) {
|
|
54585
|
+
if (items.length === 0)
|
|
54586
|
+
continue;
|
|
54587
|
+
const emoji = section === "Added" ? "\u2728" : section === "Fixed" ? "\uD83D\uDC1B" : section === "Changed" ? "\uD83D\uDD04" : section === "Removed" ? "\uD83D\uDDD1\uFE0F" : "\u2022";
|
|
54588
|
+
msg += `${formatter.formatBold(`${emoji} ${section}`)}
|
|
54589
|
+
`;
|
|
54590
|
+
for (const item of items) {
|
|
54591
|
+
msg += `- ${item}
|
|
54592
|
+
`;
|
|
54593
|
+
}
|
|
54594
|
+
msg += `
|
|
54595
|
+
`;
|
|
54596
|
+
}
|
|
54597
|
+
return msg.trim();
|
|
54598
|
+
}
|
|
54599
|
+
function getWhatsNewSummary(notes) {
|
|
54600
|
+
const items = [];
|
|
54601
|
+
for (const section of ["Added", "Fixed", "Changed"]) {
|
|
54602
|
+
const sectionItems = notes.sections[section] || [];
|
|
54603
|
+
for (const item of sectionItems) {
|
|
54604
|
+
const short = item.split(" - ")[0].replace(/\*\*/g, "");
|
|
54605
|
+
if (short.length <= 50) {
|
|
54606
|
+
items.push(short);
|
|
54607
|
+
} else {
|
|
54608
|
+
items.push(short.substring(0, 47) + "...");
|
|
54609
|
+
}
|
|
54610
|
+
if (items.length >= 2)
|
|
54611
|
+
break;
|
|
54612
|
+
}
|
|
54613
|
+
if (items.length >= 2)
|
|
54614
|
+
break;
|
|
54615
|
+
}
|
|
54616
|
+
return items.join(", ");
|
|
54617
|
+
}
|
|
54618
|
+
|
|
54502
54619
|
// src/utils/pr-detector.ts
|
|
54503
54620
|
var PR_PATTERNS = [
|
|
54504
54621
|
{
|
|
@@ -54835,6 +54952,12 @@ async function buildStickyMessage(sessions, platformId, config, formatter, getTh
|
|
|
54835
54952
|
lines2.push(...formatHistoryEntry(historySession, formatter, getThreadLink));
|
|
54836
54953
|
}
|
|
54837
54954
|
}
|
|
54955
|
+
const releaseNotes2 = getReleaseNotes(VERSION);
|
|
54956
|
+
const whatsNew2 = releaseNotes2 ? getWhatsNewSummary(releaseNotes2) : "";
|
|
54957
|
+
if (whatsNew2) {
|
|
54958
|
+
lines2.push("");
|
|
54959
|
+
lines2.push(`\u2728 ${formatter.formatBold("What's new:")} ${whatsNew2}`);
|
|
54960
|
+
}
|
|
54838
54961
|
lines2.push("");
|
|
54839
54962
|
lines2.push(`${formatter.formatItalic("Mention me to start a session")} \xB7 ${formatter.formatCode("bun install -g claude-threads")} \xB7 ${formatter.formatLink("claude-threads.run", "https://claude-threads.run/")}`);
|
|
54840
54963
|
return lines2.join(`
|
|
@@ -54891,6 +55014,12 @@ async function buildStickyMessage(sessions, platformId, config, formatter, getTh
|
|
|
54891
55014
|
lines.push(...formatHistoryEntry(historySession, formatter, getThreadLink));
|
|
54892
55015
|
}
|
|
54893
55016
|
}
|
|
55017
|
+
const releaseNotes = getReleaseNotes(VERSION);
|
|
55018
|
+
const whatsNew = releaseNotes ? getWhatsNewSummary(releaseNotes) : "";
|
|
55019
|
+
if (whatsNew) {
|
|
55020
|
+
lines.push("");
|
|
55021
|
+
lines.push(`\u2728 ${formatter.formatBold("What's new:")} ${whatsNew}`);
|
|
55022
|
+
}
|
|
54894
55023
|
lines.push("");
|
|
54895
55024
|
lines.push(`${formatter.formatItalic("Mention me to start a session")} \xB7 ${formatter.formatCode("bun install -g claude-threads")} \xB7 ${formatter.formatLink("claude-threads.run", "https://claude-threads.run/")}`);
|
|
54896
55025
|
return lines.join(`
|
|
@@ -54903,8 +55032,8 @@ async function updateStickyMessage(platform, sessions, config) {
|
|
|
54903
55032
|
await pendingUpdate;
|
|
54904
55033
|
}
|
|
54905
55034
|
let releaseLock;
|
|
54906
|
-
const lock = new Promise((
|
|
54907
|
-
releaseLock =
|
|
55035
|
+
const lock = new Promise((resolve5) => {
|
|
55036
|
+
releaseLock = resolve5;
|
|
54908
55037
|
});
|
|
54909
55038
|
updateLocks.set(platformId, lock);
|
|
54910
55039
|
try {
|
|
@@ -54973,8 +55102,21 @@ async function updateStickyMessageImpl(platform, sessions, config) {
|
|
|
54973
55102
|
sessionStore.saveStickyPostId(platform.platformId, post2.id);
|
|
54974
55103
|
}
|
|
54975
55104
|
log17.info(`\uD83D\uDCCC Created sticky message for ${platform.platformId}: ${formatShortId(post2.id)}`);
|
|
55105
|
+
const excludePostIds = new Set;
|
|
55106
|
+
if (sessionStore) {
|
|
55107
|
+
for (const session of sessionStore.load().values()) {
|
|
55108
|
+
if (session.platformId === platform.platformId) {
|
|
55109
|
+
if (session.sessionStartPostId) {
|
|
55110
|
+
excludePostIds.add(session.sessionStartPostId);
|
|
55111
|
+
}
|
|
55112
|
+
if (session.tasksPostId) {
|
|
55113
|
+
excludePostIds.add(session.tasksPostId);
|
|
55114
|
+
}
|
|
55115
|
+
}
|
|
55116
|
+
}
|
|
55117
|
+
}
|
|
54976
55118
|
const botUser = await platform.getBotUser();
|
|
54977
|
-
cleanupOldStickyMessages(platform, botUser.id).catch((err) => {
|
|
55119
|
+
cleanupOldStickyMessages(platform, botUser.id, false, excludePostIds).catch((err) => {
|
|
54978
55120
|
log17.debug(`Background cleanup failed: ${err}`);
|
|
54979
55121
|
});
|
|
54980
55122
|
} catch (err) {
|
|
@@ -54997,7 +55139,7 @@ function isRecentPost(postId) {
|
|
|
54997
55139
|
}
|
|
54998
55140
|
return true;
|
|
54999
55141
|
}
|
|
55000
|
-
async function cleanupOldStickyMessages(platform, botUserId, forceRun = false) {
|
|
55142
|
+
async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, excludePostIds) {
|
|
55001
55143
|
const platformId = platform.platformId;
|
|
55002
55144
|
const now = Date.now();
|
|
55003
55145
|
if (!forceRun) {
|
|
@@ -55011,7 +55153,7 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false) {
|
|
|
55011
55153
|
const currentStickyId = stickyPostIds.get(platformId);
|
|
55012
55154
|
try {
|
|
55013
55155
|
const pinnedPostIds = await platform.getPinnedPosts();
|
|
55014
|
-
const recentPinnedIds = pinnedPostIds.filter((id) => id !== currentStickyId && isRecentPost(id));
|
|
55156
|
+
const recentPinnedIds = pinnedPostIds.filter((id) => id !== currentStickyId && !excludePostIds?.has(id) && isRecentPost(id));
|
|
55015
55157
|
if (recentPinnedIds.length === 0) {
|
|
55016
55158
|
log17.debug(`No recent pinned posts to check (${pinnedPostIds.length} total, current: ${currentStickyId?.substring(0, 8) || "(none)"})`);
|
|
55017
55159
|
return;
|
|
@@ -55688,7 +55830,7 @@ import { existsSync as existsSync9, statSync as statSync3 } from "fs";
|
|
|
55688
55830
|
// node_modules/update-notifier/update-notifier.js
|
|
55689
55831
|
import process10 from "process";
|
|
55690
55832
|
import { spawn as spawn5 } from "child_process";
|
|
55691
|
-
import { fileURLToPath as
|
|
55833
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
55692
55834
|
import path9 from "path";
|
|
55693
55835
|
import { format } from "util";
|
|
55694
55836
|
|
|
@@ -55763,7 +55905,7 @@ var retryifyAsync = (fn, options) => {
|
|
|
55763
55905
|
throw error;
|
|
55764
55906
|
const delay = Math.round(interval * Math.random());
|
|
55765
55907
|
if (delay > 0) {
|
|
55766
|
-
const delayPromise = new Promise((
|
|
55908
|
+
const delayPromise = new Promise((resolve5) => setTimeout(resolve5, delay));
|
|
55767
55909
|
return delayPromise.then(() => attempt.apply(undefined, args));
|
|
55768
55910
|
} else {
|
|
55769
55911
|
return attempt.apply(undefined, args);
|
|
@@ -57316,14 +57458,14 @@ class TimeoutError extends Error {
|
|
|
57316
57458
|
|
|
57317
57459
|
// node_modules/ky/distribution/utils/timeout.js
|
|
57318
57460
|
async function timeout(request, init, abortController, options) {
|
|
57319
|
-
return new Promise((
|
|
57461
|
+
return new Promise((resolve5, reject) => {
|
|
57320
57462
|
const timeoutId = setTimeout(() => {
|
|
57321
57463
|
if (abortController) {
|
|
57322
57464
|
abortController.abort();
|
|
57323
57465
|
}
|
|
57324
57466
|
reject(new TimeoutError(request));
|
|
57325
57467
|
}, options.timeout);
|
|
57326
|
-
options.fetch(request, init).then(
|
|
57468
|
+
options.fetch(request, init).then(resolve5).catch(reject).then(() => {
|
|
57327
57469
|
clearTimeout(timeoutId);
|
|
57328
57470
|
});
|
|
57329
57471
|
});
|
|
@@ -57331,7 +57473,7 @@ async function timeout(request, init, abortController, options) {
|
|
|
57331
57473
|
|
|
57332
57474
|
// node_modules/ky/distribution/utils/delay.js
|
|
57333
57475
|
async function delay(ms, { signal }) {
|
|
57334
|
-
return new Promise((
|
|
57476
|
+
return new Promise((resolve5, reject) => {
|
|
57335
57477
|
if (signal) {
|
|
57336
57478
|
signal.throwIfAborted();
|
|
57337
57479
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
@@ -57342,7 +57484,7 @@ async function delay(ms, { signal }) {
|
|
|
57342
57484
|
}
|
|
57343
57485
|
const timeoutId = setTimeout(() => {
|
|
57344
57486
|
signal?.removeEventListener("abort", abortHandler);
|
|
57345
|
-
|
|
57487
|
+
resolve5();
|
|
57346
57488
|
}, ms);
|
|
57347
57489
|
});
|
|
57348
57490
|
}
|
|
@@ -57827,7 +57969,7 @@ var isNpmOrYarn = isNpm || isYarn;
|
|
|
57827
57969
|
// node_modules/is-installed-globally/index.js
|
|
57828
57970
|
import fs5 from "fs";
|
|
57829
57971
|
import path8 from "path";
|
|
57830
|
-
import { fileURLToPath as
|
|
57972
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
57831
57973
|
|
|
57832
57974
|
// node_modules/global-directory/index.js
|
|
57833
57975
|
var import_ini = __toESM(require_ini3(), 1);
|
|
@@ -57928,10 +58070,10 @@ function isPathInside(childPath, parentPath) {
|
|
|
57928
58070
|
}
|
|
57929
58071
|
|
|
57930
58072
|
// node_modules/is-installed-globally/index.js
|
|
57931
|
-
var
|
|
58073
|
+
var __dirname5 = path8.dirname(fileURLToPath5(import.meta.url));
|
|
57932
58074
|
var isInstalledGlobally = (() => {
|
|
57933
58075
|
try {
|
|
57934
|
-
return isPathInside(
|
|
58076
|
+
return isPathInside(__dirname5, global_directory_default.yarn.packages) || isPathInside(__dirname5, fs5.realpathSync(global_directory_default.npm.packages));
|
|
57935
58077
|
} catch {
|
|
57936
58078
|
return false;
|
|
57937
58079
|
}
|
|
@@ -58960,7 +59102,7 @@ function pupa(template, data, { ignoreMissing = false, transform = ({ value }) =
|
|
|
58960
59102
|
}
|
|
58961
59103
|
|
|
58962
59104
|
// node_modules/update-notifier/update-notifier.js
|
|
58963
|
-
var
|
|
59105
|
+
var __dirname6 = path9.dirname(fileURLToPath6(import.meta.url));
|
|
58964
59106
|
var ONE_DAY = 1000 * 60 * 60 * 24;
|
|
58965
59107
|
|
|
58966
59108
|
class UpdateNotifier {
|
|
@@ -59017,7 +59159,7 @@ class UpdateNotifier {
|
|
|
59017
59159
|
if (Date.now() - this.config.get("lastUpdateCheck") < this.#updateCheckInterval) {
|
|
59018
59160
|
return;
|
|
59019
59161
|
}
|
|
59020
|
-
spawn5(process10.execPath, [path9.join(
|
|
59162
|
+
spawn5(process10.execPath, [path9.join(__dirname6, "check.js"), JSON.stringify(this.#options)], {
|
|
59021
59163
|
detached: true,
|
|
59022
59164
|
stdio: "ignore"
|
|
59023
59165
|
}).unref();
|
|
@@ -59105,121 +59247,6 @@ function getUpdateInfo() {
|
|
|
59105
59247
|
return cachedUpdateInfo;
|
|
59106
59248
|
}
|
|
59107
59249
|
|
|
59108
|
-
// src/changelog.ts
|
|
59109
|
-
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
59110
|
-
import { dirname as dirname7, resolve as resolve4 } from "path";
|
|
59111
|
-
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
59112
|
-
var __dirname6 = dirname7(fileURLToPath6(import.meta.url));
|
|
59113
|
-
function getReleaseNotes(version) {
|
|
59114
|
-
const possiblePaths = [
|
|
59115
|
-
resolve4(__dirname6, "..", "CHANGELOG.md"),
|
|
59116
|
-
resolve4(__dirname6, "..", "..", "CHANGELOG.md")
|
|
59117
|
-
];
|
|
59118
|
-
let changelogPath = null;
|
|
59119
|
-
for (const p of possiblePaths) {
|
|
59120
|
-
if (existsSync8(p)) {
|
|
59121
|
-
changelogPath = p;
|
|
59122
|
-
break;
|
|
59123
|
-
}
|
|
59124
|
-
}
|
|
59125
|
-
if (!changelogPath) {
|
|
59126
|
-
return null;
|
|
59127
|
-
}
|
|
59128
|
-
try {
|
|
59129
|
-
const content = readFileSync7(changelogPath, "utf-8");
|
|
59130
|
-
return parseChangelog(content, version);
|
|
59131
|
-
} catch {
|
|
59132
|
-
return null;
|
|
59133
|
-
}
|
|
59134
|
-
}
|
|
59135
|
-
function parseChangelog(content, targetVersion) {
|
|
59136
|
-
const lines = content.split(`
|
|
59137
|
-
`);
|
|
59138
|
-
let currentVersion = null;
|
|
59139
|
-
let currentDate = null;
|
|
59140
|
-
let currentSection = null;
|
|
59141
|
-
let sections = {};
|
|
59142
|
-
let foundTarget = false;
|
|
59143
|
-
for (const line of lines) {
|
|
59144
|
-
const versionMatch = line.match(/^## \[(\d+\.\d+\.\d+)\](?: - (\d{4}-\d{2}-\d{2}))?/);
|
|
59145
|
-
if (versionMatch) {
|
|
59146
|
-
if (foundTarget) {
|
|
59147
|
-
break;
|
|
59148
|
-
}
|
|
59149
|
-
currentVersion = versionMatch[1];
|
|
59150
|
-
currentDate = versionMatch[2] || "";
|
|
59151
|
-
sections = {};
|
|
59152
|
-
currentSection = null;
|
|
59153
|
-
if (!targetVersion || currentVersion === targetVersion) {
|
|
59154
|
-
foundTarget = true;
|
|
59155
|
-
}
|
|
59156
|
-
continue;
|
|
59157
|
-
}
|
|
59158
|
-
if (!foundTarget)
|
|
59159
|
-
continue;
|
|
59160
|
-
const sectionMatch = line.match(/^### (\w+)/);
|
|
59161
|
-
if (sectionMatch) {
|
|
59162
|
-
currentSection = sectionMatch[1];
|
|
59163
|
-
sections[currentSection] = [];
|
|
59164
|
-
continue;
|
|
59165
|
-
}
|
|
59166
|
-
const itemMatch = line.match(/^- (.+)/);
|
|
59167
|
-
if (itemMatch && currentSection) {
|
|
59168
|
-
sections[currentSection].push(itemMatch[1]);
|
|
59169
|
-
}
|
|
59170
|
-
}
|
|
59171
|
-
if (!foundTarget || !currentVersion) {
|
|
59172
|
-
return null;
|
|
59173
|
-
}
|
|
59174
|
-
return {
|
|
59175
|
-
version: currentVersion,
|
|
59176
|
-
date: currentDate || "",
|
|
59177
|
-
sections
|
|
59178
|
-
};
|
|
59179
|
-
}
|
|
59180
|
-
function formatReleaseNotes(notes, formatter) {
|
|
59181
|
-
let msg = `${formatter.formatHeading(`\uD83D\uDCCB Release Notes - v${notes.version}`, 3)}`;
|
|
59182
|
-
if (notes.date) {
|
|
59183
|
-
msg += ` (${notes.date})`;
|
|
59184
|
-
}
|
|
59185
|
-
msg += `
|
|
59186
|
-
|
|
59187
|
-
`;
|
|
59188
|
-
for (const [section, items] of Object.entries(notes.sections)) {
|
|
59189
|
-
if (items.length === 0)
|
|
59190
|
-
continue;
|
|
59191
|
-
const emoji = section === "Added" ? "\u2728" : section === "Fixed" ? "\uD83D\uDC1B" : section === "Changed" ? "\uD83D\uDD04" : section === "Removed" ? "\uD83D\uDDD1\uFE0F" : "\u2022";
|
|
59192
|
-
msg += `${formatter.formatBold(`${emoji} ${section}`)}
|
|
59193
|
-
`;
|
|
59194
|
-
for (const item of items) {
|
|
59195
|
-
msg += `- ${item}
|
|
59196
|
-
`;
|
|
59197
|
-
}
|
|
59198
|
-
msg += `
|
|
59199
|
-
`;
|
|
59200
|
-
}
|
|
59201
|
-
return msg.trim();
|
|
59202
|
-
}
|
|
59203
|
-
function getWhatsNewSummary(notes) {
|
|
59204
|
-
const items = [];
|
|
59205
|
-
for (const section of ["Added", "Fixed", "Changed"]) {
|
|
59206
|
-
const sectionItems = notes.sections[section] || [];
|
|
59207
|
-
for (const item of sectionItems) {
|
|
59208
|
-
const short = item.split(" - ")[0].replace(/\*\*/g, "");
|
|
59209
|
-
if (short.length <= 50) {
|
|
59210
|
-
items.push(short);
|
|
59211
|
-
} else {
|
|
59212
|
-
items.push(short.substring(0, 47) + "...");
|
|
59213
|
-
}
|
|
59214
|
-
if (items.length >= 2)
|
|
59215
|
-
break;
|
|
59216
|
-
}
|
|
59217
|
-
if (items.length >= 2)
|
|
59218
|
-
break;
|
|
59219
|
-
}
|
|
59220
|
-
return items.join(", ");
|
|
59221
|
-
}
|
|
59222
|
-
|
|
59223
59250
|
// src/operations/commands/handler.ts
|
|
59224
59251
|
init_emoji();
|
|
59225
59252
|
var log18 = createLogger("commands");
|
|
@@ -59473,6 +59500,9 @@ async function updateSessionHeader(session, ctx) {
|
|
|
59473
59500
|
const permMode = isInteractive ? "\uD83D\uDD10 Interactive" : "\u26A1 Auto";
|
|
59474
59501
|
const otherParticipants = [...session.sessionAllowedUsers].filter((u) => u !== session.startedBy).map((u) => formatter.formatUserMention(u)).join(", ");
|
|
59475
59502
|
const statusItems = [];
|
|
59503
|
+
const claudeVersion = getClaudeCliVersion();
|
|
59504
|
+
const versionStr = claudeVersion ? `v${VERSION} \xB7 CLI ${claudeVersion}` : `v${VERSION}`;
|
|
59505
|
+
statusItems.push(formatter.formatCode(versionStr));
|
|
59476
59506
|
if (session.usageStats) {
|
|
59477
59507
|
const stats = session.usageStats;
|
|
59478
59508
|
statusItems.push(formatter.formatCode(`\uD83E\uDD16 ${stats.modelDisplayName}`));
|
|
@@ -59536,34 +59566,24 @@ async function updateSessionHeader(session, ctx) {
|
|
|
59536
59566
|
if (otherParticipants) {
|
|
59537
59567
|
items.push(["\uD83D\uDC65", "Participants", otherParticipants]);
|
|
59538
59568
|
}
|
|
59539
|
-
const claudeVersion = getClaudeCliVersion();
|
|
59540
|
-
if (claudeVersion) {
|
|
59541
|
-
items.push(["\uD83E\uDD16", "Claude CLI", formatter.formatCode(claudeVersion)]);
|
|
59542
|
-
}
|
|
59543
59569
|
items.push(["\uD83C\uDD94", "Session ID", formatter.formatCode(session.claudeSessionId.substring(0, 8))]);
|
|
59544
59570
|
const logPath = getLogFilePath(session.platform.platformId, session.claudeSessionId);
|
|
59545
59571
|
const shortLogPath = logPath.replace(process.env.HOME || "", "~");
|
|
59546
59572
|
items.push(["\uD83D\uDCCB", "Log File", formatter.formatCode(shortLogPath)]);
|
|
59547
59573
|
const updateInfo = getUpdateInfo();
|
|
59548
|
-
const updateNotice = updateInfo ?
|
|
59549
|
-
|
|
59550
|
-
` :
|
|
59551
|
-
const releaseNotes = getReleaseNotes(VERSION);
|
|
59552
|
-
const whatsNew = releaseNotes ? getWhatsNewSummary(releaseNotes) : "";
|
|
59553
|
-
const whatsNewLine = whatsNew ? `
|
|
59554
|
-
> \u2728 ${formatter.formatBold("What's new:")} ${whatsNew}
|
|
59555
|
-
` : "";
|
|
59574
|
+
const updateNotice = updateInfo ? `> \u26A0\uFE0F ${formatter.formatBold("Update available:")} v${updateInfo.current} \u2192 v${updateInfo.latest} - Run ${formatter.formatCode("bun install -g claude-threads")}
|
|
59575
|
+
|
|
59576
|
+
` : undefined;
|
|
59556
59577
|
const msg = [
|
|
59557
|
-
getLogo(VERSION),
|
|
59558
59578
|
updateNotice,
|
|
59559
|
-
whatsNewLine,
|
|
59560
59579
|
statusBar,
|
|
59561
59580
|
"",
|
|
59562
59581
|
formatter.formatKeyValueList(items)
|
|
59563
|
-
].join(`
|
|
59582
|
+
].filter((item) => item !== null && item !== undefined).join(`
|
|
59564
59583
|
`);
|
|
59565
59584
|
const postId = session.sessionStartPostId;
|
|
59566
59585
|
await updatePost2(session, postId, msg);
|
|
59586
|
+
session.platform.pinPost(postId).catch(() => {});
|
|
59567
59587
|
}
|
|
59568
59588
|
async function showUpdateStatus(session, updateManager, ctx) {
|
|
59569
59589
|
const formatter = session.platform.getFormatter();
|
|
@@ -61133,6 +61153,9 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
61133
61153
|
fireMetadataSuggestions(session, options.prompt, ctx);
|
|
61134
61154
|
keepAlive.sessionStarted();
|
|
61135
61155
|
await ctx.ops.updateSessionHeader(session);
|
|
61156
|
+
if (session.sessionStartPostId) {
|
|
61157
|
+
await platform.pinPost(session.sessionStartPostId).catch(() => {});
|
|
61158
|
+
}
|
|
61136
61159
|
await ctx.ops.updateStickyMessage();
|
|
61137
61160
|
ctx.ops.startTyping(session);
|
|
61138
61161
|
claude.on("event", (e) => ctx.ops.handleEvent(sessionId, e));
|
|
@@ -61147,7 +61170,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
61147
61170
|
await ctx.ops.updateStickyMessage();
|
|
61148
61171
|
return;
|
|
61149
61172
|
}
|
|
61150
|
-
const shouldPrompt = await ctx.ops.shouldPromptForWorktree(session);
|
|
61173
|
+
const shouldPrompt = options.skipWorktreePrompt ? null : await ctx.ops.shouldPromptForWorktree(session);
|
|
61151
61174
|
if (shouldPrompt) {
|
|
61152
61175
|
session.queuedPrompt = options.prompt;
|
|
61153
61176
|
session.queuedFiles = options.files;
|
|
@@ -61332,6 +61355,9 @@ ${sessionFormatter.formatItalic("Reconnected to Claude session. You can continue
|
|
|
61332
61355
|
await post(session, "resume", restartMsg);
|
|
61333
61356
|
}
|
|
61334
61357
|
await ctx.ops.updateSessionHeader(session);
|
|
61358
|
+
if (session.sessionStartPostId) {
|
|
61359
|
+
await session.platform.pinPost(session.sessionStartPostId).catch(() => {});
|
|
61360
|
+
}
|
|
61335
61361
|
await ctx.ops.updateStickyMessage();
|
|
61336
61362
|
ctx.ops.persistSession(session);
|
|
61337
61363
|
} catch (err) {
|
|
@@ -62224,15 +62250,6 @@ class SessionManager extends EventEmitter5 {
|
|
|
62224
62250
|
initialize(this.sessionStore);
|
|
62225
62251
|
this.sessionMonitor?.start();
|
|
62226
62252
|
this.backgroundCleanup?.start();
|
|
62227
|
-
for (const platform of this.platforms.values()) {
|
|
62228
|
-
platform.getBotUser().then((botUser) => {
|
|
62229
|
-
cleanupOldStickyMessages(platform, botUser.id, true).catch((err) => {
|
|
62230
|
-
log26.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
|
|
62231
|
-
});
|
|
62232
|
-
}).catch((err) => {
|
|
62233
|
-
log26.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
|
|
62234
|
-
});
|
|
62235
|
-
}
|
|
62236
62253
|
const sessionTimeoutMs = this.limits.sessionTimeoutMinutes * 60 * 1000;
|
|
62237
62254
|
const staleIds = this.sessionStore.cleanStale(sessionTimeoutMs * 2);
|
|
62238
62255
|
if (staleIds.length > 0) {
|
|
@@ -62244,6 +62261,31 @@ class SessionManager extends EventEmitter5 {
|
|
|
62244
62261
|
}
|
|
62245
62262
|
const persisted = this.sessionStore.load();
|
|
62246
62263
|
log26.info(`\uD83D\uDCC2 Loaded ${persisted.size} session(s) from persistence`);
|
|
62264
|
+
const excludePostIdsByPlatform = new Map;
|
|
62265
|
+
for (const session of persisted.values()) {
|
|
62266
|
+
const platformId = session.platformId;
|
|
62267
|
+
let excludeSet = excludePostIdsByPlatform.get(platformId);
|
|
62268
|
+
if (!excludeSet) {
|
|
62269
|
+
excludeSet = new Set;
|
|
62270
|
+
excludePostIdsByPlatform.set(platformId, excludeSet);
|
|
62271
|
+
}
|
|
62272
|
+
if (session.sessionStartPostId) {
|
|
62273
|
+
excludeSet.add(session.sessionStartPostId);
|
|
62274
|
+
}
|
|
62275
|
+
if (session.tasksPostId) {
|
|
62276
|
+
excludeSet.add(session.tasksPostId);
|
|
62277
|
+
}
|
|
62278
|
+
}
|
|
62279
|
+
for (const platform of this.platforms.values()) {
|
|
62280
|
+
const excludePostIds = excludePostIdsByPlatform.get(platform.platformId);
|
|
62281
|
+
platform.getBotUser().then((botUser) => {
|
|
62282
|
+
cleanupOldStickyMessages(platform, botUser.id, true, excludePostIds).catch((err) => {
|
|
62283
|
+
log26.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
|
|
62284
|
+
});
|
|
62285
|
+
}).catch((err) => {
|
|
62286
|
+
log26.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
|
|
62287
|
+
});
|
|
62288
|
+
}
|
|
62247
62289
|
if (persisted.size > 0) {
|
|
62248
62290
|
const activeToResume = [];
|
|
62249
62291
|
const pausedToSkip = [];
|
|
@@ -62501,7 +62543,7 @@ class SessionManager extends EventEmitter5 {
|
|
|
62501
62543
|
return session.sessionAllowedUsers.has(username) || session.platform.isUserAllowed(username);
|
|
62502
62544
|
}
|
|
62503
62545
|
async startSessionWithWorktree(options, branch, username, replyToPostId, platformId = "default", displayName) {
|
|
62504
|
-
await this.startSession(options, username, replyToPostId, platformId, displayName);
|
|
62546
|
+
await this.startSession({ ...options, skipWorktreePrompt: true }, username, replyToPostId, platformId, displayName);
|
|
62505
62547
|
const threadId = replyToPostId || "";
|
|
62506
62548
|
const session = this.registry.find(platformId, threadId);
|
|
62507
62549
|
if (session) {
|
|
@@ -39290,6 +39290,11 @@ function loadPackageJson() {
|
|
|
39290
39290
|
var pkgInfo = loadPackageJson();
|
|
39291
39291
|
var VERSION = pkgInfo.version;
|
|
39292
39292
|
|
|
39293
|
+
// src/changelog.ts
|
|
39294
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
39295
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
39296
|
+
var __dirname3 = dirname2(fileURLToPath2(import.meta.url));
|
|
39297
|
+
|
|
39293
39298
|
// src/claude/version-check.ts
|
|
39294
39299
|
var import_semver = __toESM(require_semver2(), 1);
|
|
39295
39300
|
|
|
@@ -39721,7 +39726,7 @@ class Redactor {
|
|
|
39721
39726
|
|
|
39722
39727
|
// src/persistence/thread-logger.ts
|
|
39723
39728
|
import { homedir } from "os";
|
|
39724
|
-
import { join, dirname as
|
|
39729
|
+
import { join, dirname as dirname3 } from "path";
|
|
39725
39730
|
var log5 = createLogger("thread-log");
|
|
39726
39731
|
var LOGS_BASE_DIR = join(homedir(), ".claude-threads", "logs");
|
|
39727
39732
|
|
|
@@ -39743,8 +39748,8 @@ class UsernameAnonymizer {
|
|
|
39743
39748
|
// src/claude/cli.ts
|
|
39744
39749
|
import { spawn as spawn2 } from "child_process";
|
|
39745
39750
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
39746
|
-
import { resolve as
|
|
39747
|
-
import { fileURLToPath as
|
|
39751
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
39752
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
39748
39753
|
import { existsSync as existsSync2, readFileSync as readFileSync2, watchFile, unwatchFile, unlinkSync, statSync, readdirSync } from "fs";
|
|
39749
39754
|
import { tmpdir } from "os";
|
|
39750
39755
|
import { join as join2 } from "path";
|
|
@@ -40007,7 +40012,7 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
40007
40012
|
const pid = proc.pid;
|
|
40008
40013
|
this.process = null;
|
|
40009
40014
|
this.log.debug(`Killing Claude process (pid=${pid})`);
|
|
40010
|
-
return new Promise((
|
|
40015
|
+
return new Promise((resolve4) => {
|
|
40011
40016
|
this.log.debug("Sending first SIGINT");
|
|
40012
40017
|
proc.kill("SIGINT");
|
|
40013
40018
|
const secondSigint = setTimeout(() => {
|
|
@@ -40026,7 +40031,7 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
40026
40031
|
this.log.debug(`Claude process exited (code=${code})`);
|
|
40027
40032
|
clearTimeout(secondSigint);
|
|
40028
40033
|
clearTimeout(forceKillTimeout);
|
|
40029
|
-
|
|
40034
|
+
resolve4();
|
|
40030
40035
|
});
|
|
40031
40036
|
});
|
|
40032
40037
|
}
|
|
@@ -40040,25 +40045,20 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
40040
40045
|
return true;
|
|
40041
40046
|
}
|
|
40042
40047
|
getMcpServerPath() {
|
|
40043
|
-
const __filename2 =
|
|
40044
|
-
const
|
|
40045
|
-
return
|
|
40048
|
+
const __filename2 = fileURLToPath3(import.meta.url);
|
|
40049
|
+
const __dirname4 = dirname4(__filename2);
|
|
40050
|
+
return resolve3(__dirname4, "..", "mcp", "permission-server.js");
|
|
40046
40051
|
}
|
|
40047
40052
|
getStatusLineWriterPath() {
|
|
40048
|
-
const __filename2 =
|
|
40049
|
-
const
|
|
40050
|
-
return
|
|
40053
|
+
const __filename2 = fileURLToPath3(import.meta.url);
|
|
40054
|
+
const __dirname4 = dirname4(__filename2);
|
|
40055
|
+
return resolve3(__dirname4, "..", "statusline", "writer.js");
|
|
40051
40056
|
}
|
|
40052
40057
|
}
|
|
40053
40058
|
|
|
40054
40059
|
// src/update-notifier.ts
|
|
40055
40060
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
40056
40061
|
|
|
40057
|
-
// src/changelog.ts
|
|
40058
|
-
import { dirname as dirname4, resolve as resolve3 } from "path";
|
|
40059
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
40060
|
-
var __dirname3 = dirname4(fileURLToPath3(import.meta.url));
|
|
40061
|
-
|
|
40062
40062
|
// src/operations/commands/handler.ts
|
|
40063
40063
|
init_emoji();
|
|
40064
40064
|
|
|
@@ -40394,14 +40394,16 @@ ${code}
|
|
|
40394
40394
|
return text.replace(/([*_`[\]()#+\-.!])/g, "\\$1");
|
|
40395
40395
|
}
|
|
40396
40396
|
formatTable(headers, rows) {
|
|
40397
|
-
const
|
|
40397
|
+
const escapeCell = (cell) => cell.replace(/\|/g, "\\|");
|
|
40398
|
+
const headerRow = `| ${headers.map(escapeCell).join(" | ")} |`;
|
|
40398
40399
|
const separatorRow = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
40399
|
-
const dataRows = rows.map((row) => `| ${row.join(" | ")} |`);
|
|
40400
|
+
const dataRows = rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`);
|
|
40400
40401
|
return [headerRow, separatorRow, ...dataRows].join(`
|
|
40401
40402
|
`);
|
|
40402
40403
|
}
|
|
40403
40404
|
formatKeyValueList(items) {
|
|
40404
|
-
const
|
|
40405
|
+
const escapeCell = (cell) => cell.replace(/\|/g, "\\|");
|
|
40406
|
+
const rows = items.map(([icon, label, value]) => `| ${icon} ${this.formatBold(escapeCell(label))} | ${escapeCell(value)} |`);
|
|
40405
40407
|
return ["| | |", "|---|---|", ...rows].join(`
|
|
40406
40408
|
`);
|
|
40407
40409
|
}
|