claude-threads 1.36.0 → 1.37.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 +19 -0
- package/bin/claude-threads-daemon +8 -0
- package/dist/index.js +423 -95
- package/dist/mcp/mcp-server.js +93 -86
- package/docs/CONFIGURATION.md +27 -0
- package/docs/systemd/claude-threads.service +3 -0
- package/docs/turn-marker-spec.md +149 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2128,6 +2128,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2128
2128
|
exports.useColor = useColor;
|
|
2129
2129
|
});
|
|
2130
2130
|
|
|
2131
|
+
// src/utils/state-home.ts
|
|
2132
|
+
import { homedir } from "os";
|
|
2133
|
+
import { resolve } from "path";
|
|
2134
|
+
function stateHome() {
|
|
2135
|
+
return resolve(process.env.CLAUDE_THREADS_HOME || homedir());
|
|
2136
|
+
}
|
|
2137
|
+
function hasStateHomeOverride() {
|
|
2138
|
+
return stateHome() !== resolve(homedir());
|
|
2139
|
+
}
|
|
2140
|
+
var init_state_home = () => {};
|
|
2141
|
+
|
|
2131
2142
|
// src/utils/logger.ts
|
|
2132
2143
|
function setLogHandler(handler) {
|
|
2133
2144
|
globalLogHandler = handler;
|
|
@@ -2221,6 +2232,23 @@ function resolveOverheadVisibility(value, fieldPath) {
|
|
|
2221
2232
|
return value;
|
|
2222
2233
|
throw new Error(`Invalid ${fieldPath}: expected one of ${OVERHEAD_VISIBILITY_VALUES.join(", ")}, got ${JSON.stringify(value)}`);
|
|
2223
2234
|
}
|
|
2235
|
+
function resolveTurnMarker(mode, emoji, platformType, fieldPath) {
|
|
2236
|
+
const m = mode === undefined || mode === null ? "off" : mode;
|
|
2237
|
+
if (!TURN_MARKER_VALUES.includes(m)) {
|
|
2238
|
+
throw new Error(`Invalid ${fieldPath}.turnMarker: expected one of ${TURN_MARKER_VALUES.join(", ")}, got ${JSON.stringify(mode)}`);
|
|
2239
|
+
}
|
|
2240
|
+
if (m === "metadata" && platformType !== "slack") {
|
|
2241
|
+
throw new Error(`Invalid ${fieldPath}.turnMarker: metadata is a Slack feature; use reaction on ${platformType}`);
|
|
2242
|
+
}
|
|
2243
|
+
if (emoji !== undefined && emoji !== null) {
|
|
2244
|
+
if (typeof emoji !== "string" || !/^[a-z0-9_+-]+$/.test(emoji)) {
|
|
2245
|
+
throw new Error(`Invalid ${fieldPath}.turnMarkerEmoji: expected an emoji name like checkered_flag, got ${JSON.stringify(emoji)}`);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (m === "reaction")
|
|
2249
|
+
return { mode: "reaction", emoji: emoji ?? DEFAULT_TURN_MARKER_EMOJI };
|
|
2250
|
+
return { mode: m };
|
|
2251
|
+
}
|
|
2224
2252
|
function resolveMemoryConfig(value, fieldPath) {
|
|
2225
2253
|
if (value === undefined || value === null || value === true)
|
|
2226
2254
|
return DEFAULT_MEMORY_CONFIG;
|
|
@@ -2395,10 +2423,12 @@ function effectivePermissionMode(input) {
|
|
|
2395
2423
|
return "default";
|
|
2396
2424
|
return input.botWideMode;
|
|
2397
2425
|
}
|
|
2398
|
-
var OVERHEAD_VISIBILITY_VALUES, DEFAULT_OVERHEAD_VISIBILITY = "full", RECONNECT_POLICY_VALUES, DEFAULT_RECONNECT_POLICY = "retry", DEFAULT_MEMORY_CONFIG, MEMORY_DISABLED, BOT_MCP_SERVER_NAME = "claude-threads-mcp", STDIO_KEYS, REMOTE_KEYS, LIMITS_DEFAULTS, MODE_INFO;
|
|
2426
|
+
var OVERHEAD_VISIBILITY_VALUES, DEFAULT_OVERHEAD_VISIBILITY = "full", RECONNECT_POLICY_VALUES, DEFAULT_RECONNECT_POLICY = "retry", TURN_MARKER_VALUES, DEFAULT_TURN_MARKER, DEFAULT_TURN_MARKER_EMOJI = "checkered_flag", TURN_COMPLETE_EVENT_TYPE = "claude_threads_turn_complete", TURN_COMPLETE_PAYLOAD_VERSION = 1, DEFAULT_MEMORY_CONFIG, MEMORY_DISABLED, BOT_MCP_SERVER_NAME = "claude-threads-mcp", STDIO_KEYS, REMOTE_KEYS, LIMITS_DEFAULTS, MODE_INFO;
|
|
2399
2427
|
var init_types = __esm(() => {
|
|
2400
2428
|
OVERHEAD_VISIBILITY_VALUES = ["full", "minimal", "hidden"];
|
|
2401
2429
|
RECONNECT_POLICY_VALUES = ["retry", "exit"];
|
|
2430
|
+
TURN_MARKER_VALUES = ["reaction", "metadata", "off"];
|
|
2431
|
+
DEFAULT_TURN_MARKER = { mode: "off" };
|
|
2402
2432
|
DEFAULT_MEMORY_CONFIG = {
|
|
2403
2433
|
enabled: true,
|
|
2404
2434
|
repoLayer: true,
|
|
@@ -4597,7 +4627,7 @@ var init_rate_limit_detector = __esm(() => {
|
|
|
4597
4627
|
|
|
4598
4628
|
// src/claude/cli.ts
|
|
4599
4629
|
import { EventEmitter } from "events";
|
|
4600
|
-
import { resolve as
|
|
4630
|
+
import { resolve as resolve3, dirname as dirname2 } from "path";
|
|
4601
4631
|
import { fileURLToPath } from "url";
|
|
4602
4632
|
import { existsSync as existsSync4, readFileSync as readFileSync2, watchFile, unwatchFile, unlinkSync, statSync, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4603
4633
|
import { tmpdir as tmpdir2 } from "os";
|
|
@@ -5139,15 +5169,15 @@ var init_cli = __esm(() => {
|
|
|
5139
5169
|
getMcpServerPath() {
|
|
5140
5170
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
5141
5171
|
const __dirname2 = dirname2(__filename2);
|
|
5142
|
-
const bundledPath =
|
|
5172
|
+
const bundledPath = resolve3(__dirname2, "mcp", "mcp-server.js");
|
|
5143
5173
|
if (existsSync4(bundledPath)) {
|
|
5144
5174
|
return bundledPath;
|
|
5145
5175
|
}
|
|
5146
|
-
const sourceLayoutPath =
|
|
5176
|
+
const sourceLayoutPath = resolve3(__dirname2, "..", "mcp", "mcp-server.js");
|
|
5147
5177
|
if (existsSync4(sourceLayoutPath)) {
|
|
5148
5178
|
return sourceLayoutPath;
|
|
5149
5179
|
}
|
|
5150
|
-
const tsPath =
|
|
5180
|
+
const tsPath = resolve3(__dirname2, "..", "mcp", "mcp-server.ts");
|
|
5151
5181
|
if (existsSync4(tsPath)) {
|
|
5152
5182
|
return tsPath;
|
|
5153
5183
|
}
|
|
@@ -5156,15 +5186,15 @@ var init_cli = __esm(() => {
|
|
|
5156
5186
|
getStatusLineWriterPath() {
|
|
5157
5187
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
5158
5188
|
const __dirname2 = dirname2(__filename2);
|
|
5159
|
-
const bundledPath =
|
|
5189
|
+
const bundledPath = resolve3(__dirname2, "statusline", "writer.js");
|
|
5160
5190
|
if (existsSync4(bundledPath)) {
|
|
5161
5191
|
return bundledPath;
|
|
5162
5192
|
}
|
|
5163
|
-
const sourceLayoutPath =
|
|
5193
|
+
const sourceLayoutPath = resolve3(__dirname2, "..", "statusline", "writer.js");
|
|
5164
5194
|
if (existsSync4(sourceLayoutPath)) {
|
|
5165
5195
|
return sourceLayoutPath;
|
|
5166
5196
|
}
|
|
5167
|
-
const tsPath =
|
|
5197
|
+
const tsPath = resolve3(__dirname2, "..", "statusline", "writer.ts");
|
|
5168
5198
|
if (existsSync4(tsPath)) {
|
|
5169
5199
|
return tsPath;
|
|
5170
5200
|
}
|
|
@@ -5411,7 +5441,7 @@ var init_render = __esm(() => {
|
|
|
5411
5441
|
});
|
|
5412
5442
|
|
|
5413
5443
|
// src/usage/index.ts
|
|
5414
|
-
import { homedir as
|
|
5444
|
+
import { homedir as homedir2 } from "os";
|
|
5415
5445
|
import path3 from "path";
|
|
5416
5446
|
function toLimits(usage) {
|
|
5417
5447
|
const limits = [
|
|
@@ -5461,7 +5491,7 @@ async function collectUsage(options) {
|
|
|
5461
5491
|
}
|
|
5462
5492
|
return results;
|
|
5463
5493
|
}
|
|
5464
|
-
const configDir = process.env.CLAUDE_CONFIG_DIR ?? path3.join(
|
|
5494
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR ?? path3.join(homedir2(), ".claude");
|
|
5465
5495
|
return [await readSeat(profileNameFor(configDir), configDir)];
|
|
5466
5496
|
}
|
|
5467
5497
|
var USAGE_PROBE_TIMEOUT_MS = 1e4;
|
|
@@ -5525,7 +5555,6 @@ var init_emoji = __esm(() => {
|
|
|
5525
5555
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5526
5556
|
import * as path4 from "path";
|
|
5527
5557
|
import * as fs from "fs/promises";
|
|
5528
|
-
import { homedir as homedir6 } from "os";
|
|
5529
5558
|
async function execGit(args, cwd) {
|
|
5530
5559
|
const cmd = `git ${args.join(" ")}`;
|
|
5531
5560
|
log10.debug(`Executing: ${cmd}`);
|
|
@@ -5834,10 +5863,11 @@ async function removeWorktreeMetadata(worktreePath) {
|
|
|
5834
5863
|
var log10, WORKTREES_DIR, METADATA_STORE_PATH;
|
|
5835
5864
|
var init_worktree = __esm(() => {
|
|
5836
5865
|
init_spawn();
|
|
5866
|
+
init_state_home();
|
|
5837
5867
|
init_logger();
|
|
5838
5868
|
log10 = createLogger("git-wt");
|
|
5839
|
-
WORKTREES_DIR = path4.join(
|
|
5840
|
-
METADATA_STORE_PATH = path4.join(
|
|
5869
|
+
WORKTREES_DIR = path4.join(stateHome(), ".claude-threads", "worktrees");
|
|
5870
|
+
METADATA_STORE_PATH = path4.join(stateHome(), ".claude-threads", "worktree-metadata.json");
|
|
5841
5871
|
});
|
|
5842
5872
|
|
|
5843
5873
|
// node_modules/graceful-fs/polyfills.js
|
|
@@ -47494,17 +47524,17 @@ function resolveAckReaction(configured) {
|
|
|
47494
47524
|
}
|
|
47495
47525
|
|
|
47496
47526
|
// src/persistence/audit-log.ts
|
|
47527
|
+
init_state_home();
|
|
47497
47528
|
init_logger();
|
|
47498
47529
|
import { chmodSync, closeSync, constants as fsConstants, fchmodSync, lstatSync, mkdirSync, openSync, writeSync } from "fs";
|
|
47499
47530
|
import { join } from "path";
|
|
47500
|
-
import { homedir } from "os";
|
|
47501
47531
|
var log = createLogger("audit");
|
|
47502
47532
|
var DETAIL_MAX = 500;
|
|
47503
47533
|
var enabledPlatforms = new Set;
|
|
47504
47534
|
var preparedDirs = new Set;
|
|
47505
47535
|
var openFds = new Map;
|
|
47506
47536
|
function auditDir() {
|
|
47507
|
-
return process.env.CLAUDE_THREADS_AUDIT_DIR || join(
|
|
47537
|
+
return process.env.CLAUDE_THREADS_AUDIT_DIR || join(stateHome(), ".claude-threads", "audit");
|
|
47508
47538
|
}
|
|
47509
47539
|
function configureAuditLog(platformId, enabled) {
|
|
47510
47540
|
if (enabled)
|
|
@@ -47612,6 +47642,20 @@ function deriveDmPlatformConfig(parent, channelId, partnerUsernames) {
|
|
|
47612
47642
|
};
|
|
47613
47643
|
}
|
|
47614
47644
|
|
|
47645
|
+
// src/session/lifecycle-visibility.ts
|
|
47646
|
+
function shouldPostLifecycle(visibility, kind) {
|
|
47647
|
+
if (kind === "abnormal-exit")
|
|
47648
|
+
return true;
|
|
47649
|
+
switch (visibility) {
|
|
47650
|
+
case "full":
|
|
47651
|
+
return true;
|
|
47652
|
+
case "minimal":
|
|
47653
|
+
return kind !== "idle-warning";
|
|
47654
|
+
case "hidden":
|
|
47655
|
+
return false;
|
|
47656
|
+
}
|
|
47657
|
+
}
|
|
47658
|
+
|
|
47615
47659
|
// src/session/lifecycle-fsm.ts
|
|
47616
47660
|
init_logger();
|
|
47617
47661
|
var log2 = createLogger("fsm");
|
|
@@ -47718,9 +47762,9 @@ function getSessionStatus(session) {
|
|
|
47718
47762
|
}
|
|
47719
47763
|
|
|
47720
47764
|
// src/config/index.ts
|
|
47765
|
+
init_state_home();
|
|
47721
47766
|
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync as mkdirSync2, chmodSync as chmodSync2 } from "fs";
|
|
47722
|
-
import { resolve, dirname } from "path";
|
|
47723
|
-
import { homedir as homedir2 } from "os";
|
|
47767
|
+
import { resolve as resolve2, dirname } from "path";
|
|
47724
47768
|
|
|
47725
47769
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
47726
47770
|
function getDefaultExportFromCjs(x) {
|
|
@@ -50889,7 +50933,7 @@ function resolvePlatformMcpPosture(platforms, globalMcpServers, managedPresent =
|
|
|
50889
50933
|
}
|
|
50890
50934
|
|
|
50891
50935
|
// src/config/index.ts
|
|
50892
|
-
var CONFIG_PATH =
|
|
50936
|
+
var CONFIG_PATH = resolve2(stateHome(), ".config", "claude-threads", "config.yaml");
|
|
50893
50937
|
function loadConfigWithMigration() {
|
|
50894
50938
|
if (existsSync2(CONFIG_PATH)) {
|
|
50895
50939
|
const content = readFileSync(CONFIG_PATH, "utf-8");
|
|
@@ -51072,7 +51116,6 @@ function writeFileAtomic(file, content) {
|
|
|
51072
51116
|
|
|
51073
51117
|
// src/persistence/session-store.ts
|
|
51074
51118
|
init_logger();
|
|
51075
|
-
import { homedir as homedir3 } from "os";
|
|
51076
51119
|
import { join as join5 } from "path";
|
|
51077
51120
|
|
|
51078
51121
|
// src/sponsor.ts
|
|
@@ -51097,6 +51140,7 @@ function formatMilestoneLine(formatter, milestone) {
|
|
|
51097
51140
|
}
|
|
51098
51141
|
|
|
51099
51142
|
// src/persistence/session-store.ts
|
|
51143
|
+
init_state_home();
|
|
51100
51144
|
var log4 = createLogger("persist");
|
|
51101
51145
|
function resolveEndReason(session) {
|
|
51102
51146
|
if (!session.cleanedAt)
|
|
@@ -51107,7 +51151,7 @@ function isRevivable(session) {
|
|
|
51107
51151
|
return resolveEndReason(session) !== "stopped";
|
|
51108
51152
|
}
|
|
51109
51153
|
var STORE_VERSION = 2;
|
|
51110
|
-
var DEFAULT_CONFIG_DIR = join5(
|
|
51154
|
+
var DEFAULT_CONFIG_DIR = join5(stateHome(), ".config", "claude-threads");
|
|
51111
51155
|
var DEFAULT_SESSIONS_FILE = join5(DEFAULT_CONFIG_DIR, "sessions.json");
|
|
51112
51156
|
|
|
51113
51157
|
class SessionStore {
|
|
@@ -51384,12 +51428,12 @@ class SessionStore {
|
|
|
51384
51428
|
}
|
|
51385
51429
|
|
|
51386
51430
|
// src/persistence/thread-logger.ts
|
|
51431
|
+
init_state_home();
|
|
51387
51432
|
init_logger();
|
|
51388
51433
|
import { existsSync as existsSync6, mkdirSync as mkdirSync4, appendFileSync, readdirSync as readdirSync2, statSync as statSync2, unlinkSync as unlinkSync2, rmdirSync, readFileSync as readFileSync4, chmodSync as chmodSync4 } from "fs";
|
|
51389
|
-
import { homedir as homedir4 } from "os";
|
|
51390
51434
|
import { join as join6, dirname as dirname3 } from "path";
|
|
51391
51435
|
var log5 = createLogger("thread-log");
|
|
51392
|
-
var LOGS_BASE_DIR = join6(
|
|
51436
|
+
var LOGS_BASE_DIR = join6(stateHome(), ".claude-threads", "logs");
|
|
51393
51437
|
|
|
51394
51438
|
class ThreadLoggerImpl {
|
|
51395
51439
|
platformId;
|
|
@@ -51661,14 +51705,14 @@ function readRecentLogEntries(platformId, sessionId, maxLines = 50) {
|
|
|
51661
51705
|
|
|
51662
51706
|
// src/version.ts
|
|
51663
51707
|
import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
|
|
51664
|
-
import { dirname as dirname4, resolve as
|
|
51708
|
+
import { dirname as dirname4, resolve as resolve4 } from "path";
|
|
51665
51709
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
51666
51710
|
var __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
51667
51711
|
function loadPackageJson() {
|
|
51668
51712
|
const candidates = [
|
|
51669
|
-
|
|
51670
|
-
|
|
51671
|
-
|
|
51713
|
+
resolve4(__dirname2, "..", "package.json"),
|
|
51714
|
+
resolve4(__dirname2, "..", "..", "package.json"),
|
|
51715
|
+
resolve4(process.cwd(), "package.json")
|
|
51672
51716
|
];
|
|
51673
51717
|
for (const candidate of candidates) {
|
|
51674
51718
|
if (existsSync7(candidate)) {
|
|
@@ -52136,13 +52180,13 @@ ${formatter.formatBold("Reactions:")}
|
|
|
52136
52180
|
|
|
52137
52181
|
// src/changelog.ts
|
|
52138
52182
|
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
|
|
52139
|
-
import { dirname as dirname5, resolve as
|
|
52183
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
52140
52184
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
52141
52185
|
var __dirname3 = dirname5(fileURLToPath3(import.meta.url));
|
|
52142
52186
|
function getReleaseNotes(version) {
|
|
52143
52187
|
const possiblePaths = [
|
|
52144
|
-
|
|
52145
|
-
|
|
52188
|
+
resolve5(__dirname3, "..", "CHANGELOG.md"),
|
|
52189
|
+
resolve5(__dirname3, "..", "..", "CHANGELOG.md")
|
|
52146
52190
|
];
|
|
52147
52191
|
let changelogPath = null;
|
|
52148
52192
|
for (const p of possiblePaths) {
|
|
@@ -53278,15 +53322,21 @@ async function postError(session, message, addBugReaction = true) {
|
|
|
53278
53322
|
}
|
|
53279
53323
|
return result;
|
|
53280
53324
|
}
|
|
53281
|
-
async function postInteractive(session, message, reactions) {
|
|
53282
|
-
const
|
|
53283
|
-
|
|
53284
|
-
|
|
53325
|
+
async function postInteractive(session, message, reactions, onPostCreated) {
|
|
53326
|
+
const doneInFlight = typeof session.messageManager?.markInteractivePostInFlight === "function" ? session.messageManager.markInteractivePostInFlight() : () => {};
|
|
53327
|
+
try {
|
|
53328
|
+
const post = await session.platform.createInteractivePost(message, reactions, session.threadId, (created) => {
|
|
53329
|
+
onPostCreated?.(created);
|
|
53330
|
+
doneInFlight();
|
|
53331
|
+
});
|
|
53332
|
+
updateLastMessage(session, post);
|
|
53333
|
+
return post;
|
|
53334
|
+
} finally {
|
|
53335
|
+
doneInFlight();
|
|
53336
|
+
}
|
|
53285
53337
|
}
|
|
53286
53338
|
async function postInteractiveAndRegister(session, message, reactions, registerPost) {
|
|
53287
|
-
|
|
53288
|
-
registerPost(post.id, session.threadId);
|
|
53289
|
-
return post;
|
|
53339
|
+
return postInteractive(session, message, reactions, (created) => registerPost(created.id, session.threadId));
|
|
53290
53340
|
}
|
|
53291
53341
|
async function updatePost(session, postId, message) {
|
|
53292
53342
|
await withErrorHandling(() => session.platform.updatePost(postId, message), { action: "Update post", session });
|
|
@@ -53326,6 +53376,8 @@ function updateLastMessage(session, post) {
|
|
|
53326
53376
|
init_cli();
|
|
53327
53377
|
|
|
53328
53378
|
// src/operations/streaming/handler.ts
|
|
53379
|
+
init_state_home();
|
|
53380
|
+
import { createHash } from "crypto";
|
|
53329
53381
|
import { lstat, mkdir as mkdir2, mkdtemp, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
53330
53382
|
import { tmpdir as tmpdir3 } from "os";
|
|
53331
53383
|
import { join as join8 } from "path";
|
|
@@ -53462,7 +53514,12 @@ function safeIdSegment(id) {
|
|
|
53462
53514
|
return id.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
53463
53515
|
}
|
|
53464
53516
|
function getSessionUploadDir(platformId, threadId) {
|
|
53465
|
-
return join8(tmpdir3(), UPLOAD_ROOT_DIR, `${safeIdSegment(platformId)}-${safeIdSegment(threadId)}`);
|
|
53517
|
+
return join8(tmpdir3(), UPLOAD_ROOT_DIR, `${instancePrefix()}${safeIdSegment(platformId)}-${safeIdSegment(threadId)}`);
|
|
53518
|
+
}
|
|
53519
|
+
function instancePrefix() {
|
|
53520
|
+
if (!hasStateHomeOverride())
|
|
53521
|
+
return "";
|
|
53522
|
+
return createHash("sha1").update(stateHome()).digest("hex").slice(0, 12) + "-";
|
|
53466
53523
|
}
|
|
53467
53524
|
async function cleanupSessionUploads(platformId, threadId) {
|
|
53468
53525
|
if (!platformId || !threadId)
|
|
@@ -53670,7 +53727,7 @@ function buildRestartCliOptions(session, ctx) {
|
|
|
53670
53727
|
|
|
53671
53728
|
// src/operations/commands/handler.ts
|
|
53672
53729
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
53673
|
-
import { resolve as
|
|
53730
|
+
import { resolve as resolve7 } from "path";
|
|
53674
53731
|
import { existsSync as existsSync12, statSync as statSync4 } from "fs";
|
|
53675
53732
|
|
|
53676
53733
|
// node_modules/update-notifier/update-notifier.js
|
|
@@ -57680,8 +57737,8 @@ function checkGitHubCli(exec = execSync2) {
|
|
|
57680
57737
|
}
|
|
57681
57738
|
return { installed: true, authenticated: true };
|
|
57682
57739
|
}
|
|
57683
|
-
async function createGitHubIssue(title, body, workingDir) {
|
|
57684
|
-
const ghStatus = checkGitHubCli();
|
|
57740
|
+
async function createGitHubIssue(title, body, workingDir, exec = execSync2) {
|
|
57741
|
+
const ghStatus = checkGitHubCli(exec);
|
|
57685
57742
|
if (!ghStatus.installed || !ghStatus.authenticated) {
|
|
57686
57743
|
throw new Error(ghStatus.error);
|
|
57687
57744
|
}
|
|
@@ -57689,7 +57746,7 @@ async function createGitHubIssue(title, body, workingDir) {
|
|
|
57689
57746
|
try {
|
|
57690
57747
|
writeFileSync5(bodyFile, body, "utf-8");
|
|
57691
57748
|
const cmd = `gh issue create --repo "${GITHUB_REPO}" --title "${escapeShell(title)}" --body-file "${bodyFile}"`;
|
|
57692
|
-
const result =
|
|
57749
|
+
const result = exec(cmd, {
|
|
57693
57750
|
cwd: workingDir,
|
|
57694
57751
|
encoding: "utf-8",
|
|
57695
57752
|
timeout: 30000,
|
|
@@ -59621,12 +59678,13 @@ function createAppendContentOp(sessionId, content, isToolOutput) {
|
|
|
59621
59678
|
isToolOutput
|
|
59622
59679
|
};
|
|
59623
59680
|
}
|
|
59624
|
-
function createFlushOp(sessionId, reason) {
|
|
59681
|
+
function createFlushOp(sessionId, reason, resultOk) {
|
|
59625
59682
|
return {
|
|
59626
59683
|
type: "flush",
|
|
59627
59684
|
sessionId,
|
|
59628
59685
|
timestamp: Date.now(),
|
|
59629
|
-
reason
|
|
59686
|
+
reason,
|
|
59687
|
+
...resultOk === undefined ? {} : { resultOk }
|
|
59630
59688
|
};
|
|
59631
59689
|
}
|
|
59632
59690
|
function createTaskListOp(sessionId, action, tasks, toolUseId) {
|
|
@@ -59681,6 +59739,7 @@ function createStatusUpdateOp(sessionId, options) {
|
|
|
59681
59739
|
};
|
|
59682
59740
|
}
|
|
59683
59741
|
// src/operations/transformer.ts
|
|
59742
|
+
init_cli();
|
|
59684
59743
|
function transformEvent(event, ctx) {
|
|
59685
59744
|
if (event.parent_tool_use_id) {
|
|
59686
59745
|
return [];
|
|
@@ -59843,7 +59902,7 @@ function transformToolResult(event, ctx) {
|
|
|
59843
59902
|
}
|
|
59844
59903
|
function transformResult(event, ctx) {
|
|
59845
59904
|
const operations = [];
|
|
59846
|
-
operations.push(createFlushOp(ctx.sessionId, "result"));
|
|
59905
|
+
operations.push(createFlushOp(ctx.sessionId, "result", !isErrorResultEvent(event)));
|
|
59847
59906
|
const result = event;
|
|
59848
59907
|
const r = result.result;
|
|
59849
59908
|
operations.push(createStatusUpdateOp(ctx.sessionId, {
|
|
@@ -59926,6 +59985,9 @@ function truncateAtWord2(text, maxLength) {
|
|
|
59926
59985
|
}
|
|
59927
59986
|
return truncated + "...";
|
|
59928
59987
|
}
|
|
59988
|
+
// src/operations/message-manager.ts
|
|
59989
|
+
init_types();
|
|
59990
|
+
|
|
59929
59991
|
// src/operations/task-tracker.ts
|
|
59930
59992
|
var VALID_STATUSES = new Set(["pending", "in_progress", "completed"]);
|
|
59931
59993
|
var CREATED_RESULT_RE = /Task #(\S+) created/;
|
|
@@ -61156,16 +61218,26 @@ class QuestionApprovalExecutor extends BaseExecutor {
|
|
|
61156
61218
|
|
|
61157
61219
|
` + ctx.formatter.formatItalic("React to respond");
|
|
61158
61220
|
}
|
|
61221
|
+
let claimed = false;
|
|
61159
61222
|
const post = await ctx.createInteractivePost(message, [APPROVAL_EMOJIS[0], DENIAL_EMOJIS[0]], {
|
|
61160
61223
|
type: "plan_approval",
|
|
61161
61224
|
interactionType: "plan_approval",
|
|
61162
61225
|
toolUseId: op.toolUseId
|
|
61226
|
+
}, (created) => {
|
|
61227
|
+
claimed = true;
|
|
61228
|
+
this.state.pendingApproval = {
|
|
61229
|
+
postId: created.id,
|
|
61230
|
+
type: op.approvalType,
|
|
61231
|
+
toolUseId: op.toolUseId
|
|
61232
|
+
};
|
|
61163
61233
|
});
|
|
61164
|
-
|
|
61165
|
-
|
|
61166
|
-
|
|
61167
|
-
|
|
61168
|
-
|
|
61234
|
+
if (!claimed) {
|
|
61235
|
+
this.state.pendingApproval = {
|
|
61236
|
+
postId: post.id,
|
|
61237
|
+
type: op.approvalType,
|
|
61238
|
+
toolUseId: op.toolUseId
|
|
61239
|
+
};
|
|
61240
|
+
}
|
|
61169
61241
|
ctx.logger.debug(`Created ${op.approvalType} approval post ${formatShortId(post.id)}`);
|
|
61170
61242
|
}
|
|
61171
61243
|
async postCurrentQuestion(ctx) {
|
|
@@ -61191,13 +61263,21 @@ class QuestionApprovalExecutor extends BaseExecutor {
|
|
|
61191
61263
|
message += `
|
|
61192
61264
|
`;
|
|
61193
61265
|
}
|
|
61266
|
+
let claimed = false;
|
|
61194
61267
|
const reactionOptions = NUMBER_EMOJIS.slice(0, q.options.length);
|
|
61195
61268
|
const post = await ctx.createInteractivePost(message, reactionOptions, {
|
|
61196
61269
|
type: "question",
|
|
61197
61270
|
interactionType: "question",
|
|
61198
61271
|
toolUseId: this.state.pendingQuestionSet.toolUseId
|
|
61272
|
+
}, (created) => {
|
|
61273
|
+
claimed = true;
|
|
61274
|
+
if (this.state.pendingQuestionSet) {
|
|
61275
|
+
this.state.pendingQuestionSet.currentPostId = created.id;
|
|
61276
|
+
}
|
|
61199
61277
|
});
|
|
61200
|
-
this.state.pendingQuestionSet
|
|
61278
|
+
if (!claimed && this.state.pendingQuestionSet) {
|
|
61279
|
+
this.state.pendingQuestionSet.currentPostId = post.id;
|
|
61280
|
+
}
|
|
61201
61281
|
}
|
|
61202
61282
|
async handleQuestionAnswer(postId, optionIndex, ctx) {
|
|
61203
61283
|
if (!this.state.pendingQuestionSet)
|
|
@@ -61867,6 +61947,9 @@ class MessageManager {
|
|
|
61867
61947
|
platform;
|
|
61868
61948
|
postTracker;
|
|
61869
61949
|
contentBreaker;
|
|
61950
|
+
turnMarker;
|
|
61951
|
+
flushInFlight = null;
|
|
61952
|
+
turn = 0;
|
|
61870
61953
|
session;
|
|
61871
61954
|
contentExecutor;
|
|
61872
61955
|
taskListExecutor;
|
|
@@ -61881,6 +61964,7 @@ class MessageManager {
|
|
|
61881
61964
|
worktreePath;
|
|
61882
61965
|
worktreeBranch;
|
|
61883
61966
|
registerPost;
|
|
61967
|
+
beginInteractivePost;
|
|
61884
61968
|
updateLastMessage;
|
|
61885
61969
|
buildMessageContentCallback;
|
|
61886
61970
|
startTypingCallback;
|
|
@@ -61902,11 +61986,13 @@ class MessageManager {
|
|
|
61902
61986
|
this.worktreePath = options.worktreePath;
|
|
61903
61987
|
this.worktreeBranch = options.worktreeBranch;
|
|
61904
61988
|
this.registerPost = options.registerPost;
|
|
61989
|
+
this.beginInteractivePost = options.beginInteractivePost;
|
|
61905
61990
|
this.updateLastMessage = options.updateLastMessage;
|
|
61906
61991
|
this.buildMessageContentCallback = options.buildMessageContent;
|
|
61907
61992
|
this.startTypingCallback = options.startTyping;
|
|
61908
61993
|
this.emitSessionUpdateCallback = options.emitSessionUpdate;
|
|
61909
61994
|
this.flushDelayMs = options.flushDelayMs ?? MessageManager.DEFAULT_FLUSH_DELAY_MS;
|
|
61995
|
+
this.turnMarker = options.turnMarker ?? { mode: "off" };
|
|
61910
61996
|
this.events = createMessageManagerEvents();
|
|
61911
61997
|
this.contentBreaker = new DefaultContentBreaker;
|
|
61912
61998
|
this.contentExecutor = new ContentExecutor({
|
|
@@ -62048,15 +62134,58 @@ class MessageManager {
|
|
|
62048
62134
|
}
|
|
62049
62135
|
async handleFlushOp(op, ctx) {
|
|
62050
62136
|
this.cancelScheduledFlush();
|
|
62051
|
-
|
|
62137
|
+
if (this.flushInFlight)
|
|
62138
|
+
await this.flushInFlight.catch(() => {
|
|
62139
|
+
return;
|
|
62140
|
+
});
|
|
62141
|
+
if (op.reason === "result")
|
|
62142
|
+
this.turn++;
|
|
62143
|
+
await this.runTrackedFlush(op, ctx);
|
|
62144
|
+
if (op.reason === "result") {
|
|
62145
|
+
await this.markTurnComplete(ctx, op.resultOk !== false);
|
|
62146
|
+
}
|
|
62147
|
+
}
|
|
62148
|
+
async markTurnComplete(ctx, ok) {
|
|
62149
|
+
if (this.turnMarker.mode === "off")
|
|
62150
|
+
return;
|
|
62151
|
+
const { currentPostId, currentPostContent } = this.contentExecutor.getState();
|
|
62152
|
+
if (!currentPostId)
|
|
62153
|
+
return;
|
|
62154
|
+
try {
|
|
62155
|
+
if (this.turnMarker.mode === "metadata") {
|
|
62156
|
+
await this.platform.updatePost(currentPostId, currentPostContent, {
|
|
62157
|
+
metadata: {
|
|
62158
|
+
event_type: TURN_COMPLETE_EVENT_TYPE,
|
|
62159
|
+
event_payload: { v: TURN_COMPLETE_PAYLOAD_VERSION, session: this.sessionId, turn: this.turn, ok }
|
|
62160
|
+
}
|
|
62161
|
+
});
|
|
62162
|
+
} else {
|
|
62163
|
+
await this.platform.addReaction(currentPostId, this.turnMarker.emoji ?? "checkered_flag");
|
|
62164
|
+
}
|
|
62165
|
+
} catch (err) {
|
|
62166
|
+
const message = err.message ?? String(err);
|
|
62167
|
+
if (this.turnMarker.mode === "reaction" && message.includes("already_reacted"))
|
|
62168
|
+
return;
|
|
62169
|
+
ctx.logger.warn(`turn marker (${this.turnMarker.mode}) failed on ${currentPostId}: ${message}`);
|
|
62170
|
+
}
|
|
62171
|
+
}
|
|
62172
|
+
async runTrackedFlush(op, ctx) {
|
|
62173
|
+
const running = this.contentExecutor.executeFlush(op, ctx).finally(() => {
|
|
62174
|
+
if (this.flushInFlight === running)
|
|
62175
|
+
this.flushInFlight = null;
|
|
62176
|
+
});
|
|
62177
|
+
this.flushInFlight = running;
|
|
62178
|
+
await running;
|
|
62052
62179
|
}
|
|
62053
62180
|
scheduleFlush(ctx) {
|
|
62054
62181
|
if (this.flushTimer)
|
|
62055
62182
|
return;
|
|
62056
|
-
this.flushTimer = setTimeout(
|
|
62183
|
+
this.flushTimer = setTimeout(() => {
|
|
62057
62184
|
this.flushTimer = null;
|
|
62058
62185
|
const flushOp = createFlushOp(this.sessionId, "soft_threshold");
|
|
62059
|
-
|
|
62186
|
+
this.runTrackedFlush(flushOp, ctx).catch(() => {
|
|
62187
|
+
return;
|
|
62188
|
+
});
|
|
62060
62189
|
}, this.flushDelayMs);
|
|
62061
62190
|
}
|
|
62062
62191
|
cancelScheduledFlush() {
|
|
@@ -62067,8 +62196,12 @@ class MessageManager {
|
|
|
62067
62196
|
}
|
|
62068
62197
|
async flush() {
|
|
62069
62198
|
this.cancelScheduledFlush();
|
|
62199
|
+
if (this.flushInFlight)
|
|
62200
|
+
await this.flushInFlight.catch(() => {
|
|
62201
|
+
return;
|
|
62202
|
+
});
|
|
62070
62203
|
const flushOp = createFlushOp(this.sessionId, "explicit");
|
|
62071
|
-
await this.
|
|
62204
|
+
await this.runTrackedFlush(flushOp, this.getExecutorContext());
|
|
62072
62205
|
}
|
|
62073
62206
|
getExecutorContext() {
|
|
62074
62207
|
return {
|
|
@@ -62086,14 +62219,25 @@ class MessageManager {
|
|
|
62086
62219
|
this.updateLastMessage(post);
|
|
62087
62220
|
return post;
|
|
62088
62221
|
},
|
|
62089
|
-
createInteractivePost: async (content, reactions, options) => {
|
|
62090
|
-
const
|
|
62091
|
-
|
|
62092
|
-
|
|
62093
|
-
|
|
62222
|
+
createInteractivePost: async (content, reactions, options, onPostCreated) => {
|
|
62223
|
+
const doneInFlight = this.beginInteractivePost?.(this.threadId);
|
|
62224
|
+
try {
|
|
62225
|
+
const post = await this.platform.createInteractivePost(content, reactions, this.threadId, (created) => {
|
|
62226
|
+
this.registerPost(created.id, options);
|
|
62227
|
+
doneInFlight?.();
|
|
62228
|
+
onPostCreated?.(created);
|
|
62229
|
+
});
|
|
62230
|
+
this.updateLastMessage(post);
|
|
62231
|
+
return post;
|
|
62232
|
+
} finally {
|
|
62233
|
+
doneInFlight?.();
|
|
62234
|
+
}
|
|
62094
62235
|
}
|
|
62095
62236
|
};
|
|
62096
62237
|
}
|
|
62238
|
+
markInteractivePostInFlight() {
|
|
62239
|
+
return this.beginInteractivePost?.(this.threadId) ?? (() => {});
|
|
62240
|
+
}
|
|
62097
62241
|
setWorktreeInfo(path, branch) {
|
|
62098
62242
|
this.worktreePath = path;
|
|
62099
62243
|
this.worktreeBranch = branch;
|
|
@@ -62602,12 +62746,12 @@ function formatHistoryEntry(session, formatter, getThreadLink) {
|
|
|
62602
62746
|
const topic = getHistorySessionTopic(session, formatter);
|
|
62603
62747
|
const threadLink = formatter.formatLink(topic, getThreadLink(session.threadId));
|
|
62604
62748
|
const displayName = session.startedByDisplayName || session.startedBy;
|
|
62605
|
-
const isTimedOut = isRevivable(session)
|
|
62749
|
+
const isTimedOut = isRevivable(session);
|
|
62606
62750
|
const lastActivity = new Date(session.lastActivityAt);
|
|
62607
62751
|
const time = formatRelativeTimeShort(lastActivity);
|
|
62608
62752
|
const prStr = session.pullRequestUrl ? ` · ${formatPullRequestLink(session.pullRequestUrl, formatter)}` : "";
|
|
62609
62753
|
const indicator = isTimedOut ? "⏸️" : "✓";
|
|
62610
|
-
const resumeHint = isTimedOut ? ` · ${formatter.formatItalic("react \uD83D\uDD04 to resume")}` : "";
|
|
62754
|
+
const resumeHint = isTimedOut ? ` · ${formatter.formatItalic(session.lifecyclePostId ? "react \uD83D\uDD04 to resume" : "send a message to resume")}` : "";
|
|
62611
62755
|
const lines = [];
|
|
62612
62756
|
lines.push(` ${indicator} ${threadLink} · ${formatter.formatBold(displayName)}${prStr} · ${time}${resumeHint}`);
|
|
62613
62757
|
if (session.sessionDescription) {
|
|
@@ -63064,19 +63208,19 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
|
|
|
63064
63208
|
}
|
|
63065
63209
|
}
|
|
63066
63210
|
// src/memory/store.ts
|
|
63067
|
-
|
|
63211
|
+
init_state_home();
|
|
63212
|
+
import { createHash as createHash2 } from "crypto";
|
|
63068
63213
|
import {
|
|
63069
63214
|
existsSync as existsSync9,
|
|
63070
63215
|
mkdirSync as mkdirSync5,
|
|
63071
63216
|
readFileSync as readFileSync7,
|
|
63072
63217
|
realpathSync
|
|
63073
63218
|
} from "fs";
|
|
63074
|
-
import { homedir as homedir7 } from "os";
|
|
63075
63219
|
import { basename as basename3, dirname as dirname7, join as join10, sep as sep2 } from "path";
|
|
63076
63220
|
init_logger();
|
|
63077
63221
|
init_worktree();
|
|
63078
63222
|
var log18 = createLogger("memory");
|
|
63079
|
-
var DEFAULT_ROOT = join10(
|
|
63223
|
+
var DEFAULT_ROOT = join10(stateHome(), ".config", "claude-threads", "memory");
|
|
63080
63224
|
var CHANNEL_BLOCK_MAX_LINES = 200;
|
|
63081
63225
|
var CHANNEL_BLOCK_MAX_BYTES = 25 * 1024;
|
|
63082
63226
|
var CHANNEL_FILE_MAX_ENTRIES = 400;
|
|
@@ -63087,7 +63231,7 @@ function safeIdSegment2(id) {
|
|
|
63087
63231
|
return id.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
63088
63232
|
}
|
|
63089
63233
|
function shortHash(value, length) {
|
|
63090
|
-
return
|
|
63234
|
+
return createHash2("sha256").update(value).digest("hex").slice(0, length);
|
|
63091
63235
|
}
|
|
63092
63236
|
function platformSegment(platformId) {
|
|
63093
63237
|
return `${safeIdSegment2(platformId) || "platform"}-${shortHash(platformId, 6)}`;
|
|
@@ -63467,10 +63611,10 @@ import { join as join12 } from "path";
|
|
|
63467
63611
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
63468
63612
|
|
|
63469
63613
|
// src/persistence/platform-list-store.ts
|
|
63614
|
+
init_state_home();
|
|
63470
63615
|
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
63471
|
-
import { homedir as homedir8 } from "os";
|
|
63472
63616
|
import { join as join11 } from "path";
|
|
63473
|
-
var STORES_CONFIG_DIR = join11(
|
|
63617
|
+
var STORES_CONFIG_DIR = join11(stateHome(), ".config", "claude-threads");
|
|
63474
63618
|
var STORE_VERSION2 = 1;
|
|
63475
63619
|
|
|
63476
63620
|
class PlatformListStore {
|
|
@@ -65658,12 +65802,12 @@ async function suggestSessionMetadata(context) {
|
|
|
65658
65802
|
init_quick_query();
|
|
65659
65803
|
|
|
65660
65804
|
// src/persistence/github-emails-store.ts
|
|
65805
|
+
init_state_home();
|
|
65661
65806
|
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync9 } from "fs";
|
|
65662
|
-
import { homedir as homedir9 } from "os";
|
|
65663
65807
|
import { join as join14 } from "path";
|
|
65664
65808
|
init_logger();
|
|
65665
65809
|
var log33 = createLogger("gh-emails");
|
|
65666
|
-
var DEFAULT_CONFIG_DIR2 = join14(
|
|
65810
|
+
var DEFAULT_CONFIG_DIR2 = join14(stateHome(), ".config", "claude-threads");
|
|
65667
65811
|
var DEFAULT_FILE3 = join14(DEFAULT_CONFIG_DIR2, "github-emails.yaml");
|
|
65668
65812
|
var NOREPLY_REGEX = /^\d+\+[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})@users\.noreply\.github\.com$/;
|
|
65669
65813
|
var STORE_VERSION3 = 1;
|
|
@@ -65923,7 +66067,7 @@ async function changeDirectory(session, newDir, username, ctx) {
|
|
|
65923
66067
|
return;
|
|
65924
66068
|
}
|
|
65925
66069
|
const expandedDir = newDir.startsWith("~") ? newDir.replace("~", process.env.HOME || "") : newDir;
|
|
65926
|
-
const absoluteDir =
|
|
66070
|
+
const absoluteDir = resolve7(expandedDir);
|
|
65927
66071
|
const formatter = session.platform.getFormatter();
|
|
65928
66072
|
if (!existsSync12(absoluteDir)) {
|
|
65929
66073
|
await postError(session, `Directory does not exist: ${formatter.formatCode(newDir)}`);
|
|
@@ -66414,7 +66558,7 @@ async function reportBug(session, description, username, ctx, errorContext, atta
|
|
|
66414
66558
|
});
|
|
66415
66559
|
sessionLog8(session).info(`\uD83D\uDC1B Bug report preview created by @${username}: ${title}`);
|
|
66416
66560
|
}
|
|
66417
|
-
async function handleBugReportApproval(session, isApproved, username, ctx) {
|
|
66561
|
+
async function handleBugReportApproval(session, isApproved, username, ctx, exec) {
|
|
66418
66562
|
const pending = session.messageManager?.getPendingBugReport();
|
|
66419
66563
|
if (!pending)
|
|
66420
66564
|
return;
|
|
@@ -66424,7 +66568,7 @@ async function handleBugReportApproval(session, isApproved, username, ctx) {
|
|
|
66424
66568
|
const formatter = session.platform.getFormatter();
|
|
66425
66569
|
if (isApproved) {
|
|
66426
66570
|
try {
|
|
66427
|
-
const issueUrl = await createGitHubIssue(pending.title, pending.body, session.workingDir);
|
|
66571
|
+
const issueUrl = await createGitHubIssue(pending.title, pending.body, session.workingDir, exec);
|
|
66428
66572
|
await updatePostSuccess(session, pending.postId, `${formatter.formatBold("Bug report submitted")}: ${issueUrl}`);
|
|
66429
66573
|
sessionLog8(session).info(`\uD83D\uDC1B Bug report created by @${username}: ${issueUrl}`);
|
|
66430
66574
|
} catch (err) {
|
|
@@ -66727,6 +66871,60 @@ class SessionRegistry {
|
|
|
66727
66871
|
}
|
|
66728
66872
|
registerPost(postId, threadId) {
|
|
66729
66873
|
this.postIndex.set(postId, threadId);
|
|
66874
|
+
const waiters = this.pendingPostWaiters.get(postId);
|
|
66875
|
+
if (waiters) {
|
|
66876
|
+
this.pendingPostWaiters.delete(postId);
|
|
66877
|
+
for (const resolve of waiters)
|
|
66878
|
+
resolve();
|
|
66879
|
+
}
|
|
66880
|
+
}
|
|
66881
|
+
inFlightInteractivePosts = new Map;
|
|
66882
|
+
pendingPostWaiters = new Map;
|
|
66883
|
+
hasInFlightInteractivePost() {
|
|
66884
|
+
return this.inFlightInteractivePosts.size > 0;
|
|
66885
|
+
}
|
|
66886
|
+
beginInteractivePost(threadId) {
|
|
66887
|
+
this.inFlightInteractivePosts.set(threadId, (this.inFlightInteractivePosts.get(threadId) ?? 0) + 1);
|
|
66888
|
+
let done = false;
|
|
66889
|
+
return () => {
|
|
66890
|
+
if (done)
|
|
66891
|
+
return;
|
|
66892
|
+
done = true;
|
|
66893
|
+
const depth = (this.inFlightInteractivePosts.get(threadId) ?? 1) - 1;
|
|
66894
|
+
if (depth <= 0)
|
|
66895
|
+
this.inFlightInteractivePosts.delete(threadId);
|
|
66896
|
+
else
|
|
66897
|
+
this.inFlightInteractivePosts.set(threadId, depth);
|
|
66898
|
+
};
|
|
66899
|
+
}
|
|
66900
|
+
async awaitPendingPost(postId, timeoutMs) {
|
|
66901
|
+
if (this.postIndex.has(postId))
|
|
66902
|
+
return;
|
|
66903
|
+
if (!this.hasInFlightInteractivePost())
|
|
66904
|
+
return;
|
|
66905
|
+
await new Promise((resolve) => {
|
|
66906
|
+
const waiters = this.pendingPostWaiters.get(postId) ?? [];
|
|
66907
|
+
let settled = false;
|
|
66908
|
+
const finish = () => {
|
|
66909
|
+
if (settled)
|
|
66910
|
+
return;
|
|
66911
|
+
settled = true;
|
|
66912
|
+
clearTimeout(timer);
|
|
66913
|
+
const list = this.pendingPostWaiters.get(postId);
|
|
66914
|
+
if (list) {
|
|
66915
|
+
const idx = list.indexOf(finish);
|
|
66916
|
+
if (idx >= 0)
|
|
66917
|
+
list.splice(idx, 1);
|
|
66918
|
+
if (list.length === 0)
|
|
66919
|
+
this.pendingPostWaiters.delete(postId);
|
|
66920
|
+
}
|
|
66921
|
+
resolve();
|
|
66922
|
+
};
|
|
66923
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
66924
|
+
timer.unref?.();
|
|
66925
|
+
waiters.push(finish);
|
|
66926
|
+
this.pendingPostWaiters.set(postId, waiters);
|
|
66927
|
+
});
|
|
66730
66928
|
}
|
|
66731
66929
|
unregisterPost(postId) {
|
|
66732
66930
|
this.postIndex.delete(postId);
|
|
@@ -67244,10 +67442,12 @@ function createMessageManager(session, ctx) {
|
|
|
67244
67442
|
sessionId: session.sessionId,
|
|
67245
67443
|
worktreePath: session.worktreeInfo?.worktreePath,
|
|
67246
67444
|
worktreeBranch: session.worktreeInfo?.branch,
|
|
67445
|
+
turnMarker: ctx.ops.getPlatformOverhead(session.platformId).turnMarker,
|
|
67247
67446
|
registerPost: (postId, options) => {
|
|
67248
67447
|
ctx.ops.registerPost(postId, session.threadId);
|
|
67249
67448
|
postTracker.register(postId, session.threadId, session.sessionId, options);
|
|
67250
67449
|
},
|
|
67450
|
+
beginInteractivePost: (threadId) => ctx.ops.beginInteractivePost(threadId),
|
|
67251
67451
|
updateLastMessage: (post) => {
|
|
67252
67452
|
updateLastMessage(session, post);
|
|
67253
67453
|
},
|
|
@@ -67885,7 +68085,7 @@ ${sessionFormatter.formatItalic(outcome)}`;
|
|
|
67885
68085
|
await withErrorHandling(() => session.platform.updatePost(postId, resumeMsg), { action: "Update timeout/shutdown post for resume", session });
|
|
67886
68086
|
session.lifecyclePostId = undefined;
|
|
67887
68087
|
transitionTo(session, "active");
|
|
67888
|
-
} else {
|
|
68088
|
+
} else if (shouldPostLifecycle(ctx.ops.getPlatformOverhead(session.platformId).lifecycle, "resumed")) {
|
|
67889
68089
|
const suffix = trigger === "platform-enabled" ? " (platform re-enabled)" : ` after bot restart (v${VERSION})`;
|
|
67890
68090
|
const restartMsg = `${sessionFormatter.formatBold("Session resumed")}${suffix}
|
|
67891
68091
|
${sessionFormatter.formatItalic(outcome)}`;
|
|
@@ -68022,7 +68222,7 @@ async function handleExit(sessionId, code, ctx, source) {
|
|
|
68022
68222
|
cleanupSessionTimers(session);
|
|
68023
68223
|
await closeThreadLogger(session, "interrupt", { exitCode: code }, "pause");
|
|
68024
68224
|
const message = session.lifecycle.hasClaudeResponded ? `ℹ️ Session paused. Send a new message to continue.` : `ℹ️ Session ended before Claude could respond. Send a new message to start fresh.`;
|
|
68025
|
-
const pausePost = await withErrorHandling(() => post(session, "info", message), { action: "Post session pause notification", session });
|
|
68225
|
+
const pausePost = shouldPostLifecycle(ctx.ops.getPlatformOverhead(session.platformId).lifecycle, "paused") ? await withErrorHandling(() => post(session, "info", message), { action: "Post session pause notification", session }) : null;
|
|
68026
68226
|
if (session.lifecycle.hasClaudeResponded) {
|
|
68027
68227
|
transitionTo(session, "paused");
|
|
68028
68228
|
if (pausePost) {
|
|
@@ -68101,7 +68301,7 @@ Please start a new session.`), { action: "Post session permanent failure", sessi
|
|
|
68101
68301
|
await session.platform.unpinPost(exitTaskState.postId).catch(() => {});
|
|
68102
68302
|
}
|
|
68103
68303
|
await ctx.ops.flush(session);
|
|
68104
|
-
if (code !== 0 && code !== null) {
|
|
68304
|
+
if (code !== 0 && code !== null && shouldPostLifecycle(ctx.ops.getPlatformOverhead(session.platformId).lifecycle, "abnormal-exit")) {
|
|
68105
68305
|
const exitFormatter = session.platform.getFormatter();
|
|
68106
68306
|
await post(session, "info", exitFormatter.formatBold(`[Exited: ${code}]`));
|
|
68107
68307
|
}
|
|
@@ -68175,7 +68375,7 @@ async function cleanupIdleSessions(timeoutMs, warningMs, ctx) {
|
|
|
68175
68375
|
const postId = session.lifecyclePostId;
|
|
68176
68376
|
await withErrorHandling(() => session.platform.updatePost(postId, `⏱️ ${timeoutMessage}`), { action: "Update timeout post", session });
|
|
68177
68377
|
} else {
|
|
68178
|
-
const timeoutPost = await withErrorHandling(() => post(session, "timeout", timeoutMessage), { action: "Post session timeout", session });
|
|
68378
|
+
const timeoutPost = shouldPostLifecycle(ctx.ops.getPlatformOverhead(session.platformId).lifecycle, "timed-out") ? await withErrorHandling(() => post(session, "timeout", timeoutMessage), { action: "Post session timeout", session }) : null;
|
|
68179
68379
|
if (timeoutPost) {
|
|
68180
68380
|
session.lifecyclePostId = timeoutPost.id;
|
|
68181
68381
|
ctx.ops.registerPost(timeoutPost.id, session.threadId);
|
|
@@ -68188,7 +68388,8 @@ async function cleanupIdleSessions(timeoutMs, warningMs, ctx) {
|
|
|
68188
68388
|
continue;
|
|
68189
68389
|
}
|
|
68190
68390
|
const warningThresholdMs = timeoutMs - warningMs;
|
|
68191
|
-
|
|
68391
|
+
const idleWarningWanted = shouldPostLifecycle(ctx.ops.getPlatformOverhead(session.platformId).lifecycle, "idle-warning");
|
|
68392
|
+
if (idleWarningWanted && idleMs > warningThresholdMs && !session.timeoutWarningPosted) {
|
|
68192
68393
|
const remainingMins = Math.max(0, Math.round((timeoutMs - idleMs) / 60000));
|
|
68193
68394
|
const warningFormatter = session.platform.getFormatter();
|
|
68194
68395
|
const warnWaiting = session.isProcessing && (session.messageManager?.hasPendingApproval() === true || session.messageManager?.hasPendingQuestions() === true);
|
|
@@ -69846,8 +70047,9 @@ class BasePlatformClient extends EventEmitter3 {
|
|
|
69846
70047
|
getBotName() {
|
|
69847
70048
|
return this.botName;
|
|
69848
70049
|
}
|
|
69849
|
-
async createInteractivePost(message, reactions, threadId) {
|
|
70050
|
+
async createInteractivePost(message, reactions, threadId, onPostCreated) {
|
|
69850
70051
|
const post = await this.createPost(message, threadId);
|
|
70052
|
+
onPostCreated?.(post);
|
|
69851
70053
|
for (const emoji of reactions) {
|
|
69852
70054
|
try {
|
|
69853
70055
|
await this.addReaction(post.id, emoji);
|
|
@@ -70323,7 +70525,7 @@ class MattermostClient extends BasePlatformClient {
|
|
|
70323
70525
|
const post = await this.api("POST", "/posts", request);
|
|
70324
70526
|
return this.normalizePlatformPost(post);
|
|
70325
70527
|
}
|
|
70326
|
-
async updatePost(postId, message) {
|
|
70528
|
+
async updatePost(postId, message, _options) {
|
|
70327
70529
|
const request = {
|
|
70328
70530
|
id: postId,
|
|
70329
70531
|
message
|
|
@@ -71371,6 +71573,9 @@ class SlackClient extends BasePlatformClient {
|
|
|
71371
71573
|
if (resolvedThreadId) {
|
|
71372
71574
|
body.thread_ts = resolvedThreadId;
|
|
71373
71575
|
}
|
|
71576
|
+
if (options?.metadata) {
|
|
71577
|
+
body.metadata = options.metadata;
|
|
71578
|
+
}
|
|
71374
71579
|
const response = await this.api("POST", "chat.postMessage", body);
|
|
71375
71580
|
return {
|
|
71376
71581
|
id: response.ts,
|
|
@@ -71382,13 +71587,16 @@ class SlackClient extends BasePlatformClient {
|
|
|
71382
71587
|
createAt: Math.floor(parseFloat(response.ts) * 1000)
|
|
71383
71588
|
};
|
|
71384
71589
|
}
|
|
71385
|
-
async updatePost(postId, message) {
|
|
71590
|
+
async updatePost(postId, message, options) {
|
|
71386
71591
|
const truncatedMessage = this.truncateMessageIfNeeded(message);
|
|
71387
|
-
const
|
|
71592
|
+
const body = {
|
|
71388
71593
|
channel: this.channelId,
|
|
71389
71594
|
ts: postId,
|
|
71390
71595
|
text: truncatedMessage
|
|
71391
|
-
}
|
|
71596
|
+
};
|
|
71597
|
+
if (options?.metadata)
|
|
71598
|
+
body.metadata = options.metadata;
|
|
71599
|
+
const response = await this.api("POST", "chat.update", body);
|
|
71392
71600
|
return {
|
|
71393
71601
|
id: response.ts,
|
|
71394
71602
|
platformId: this.platformId,
|
|
@@ -72662,6 +72870,7 @@ function shouldPostResumeRefusal(platformId, threadId, username, now = Date.now(
|
|
|
72662
72870
|
// src/session/reaction-router.ts
|
|
72663
72871
|
init_logger();
|
|
72664
72872
|
var log52 = createLogger("manager");
|
|
72873
|
+
var UNKNOWN_POST_GRACE_MS = 5000;
|
|
72665
72874
|
async function handleReaction(deps, platformId, postId, emojiName, username, action) {
|
|
72666
72875
|
const normalizedEmoji = normalizeEmojiName(emojiName);
|
|
72667
72876
|
if (action === "added" && isResumeEmoji(normalizedEmoji)) {
|
|
@@ -72669,9 +72878,13 @@ async function handleReaction(deps, platformId, postId, emojiName, username, act
|
|
|
72669
72878
|
if (resumed)
|
|
72670
72879
|
return;
|
|
72671
72880
|
}
|
|
72672
|
-
|
|
72673
|
-
if (!session)
|
|
72674
|
-
|
|
72881
|
+
let session = deps.registry.findByPost(postId);
|
|
72882
|
+
if (!session) {
|
|
72883
|
+
await deps.registry.awaitPendingPost(postId, UNKNOWN_POST_GRACE_MS);
|
|
72884
|
+
session = deps.registry.findByPost(postId);
|
|
72885
|
+
if (!session)
|
|
72886
|
+
return;
|
|
72887
|
+
}
|
|
72675
72888
|
if (session.platformId !== platformId)
|
|
72676
72889
|
return;
|
|
72677
72890
|
const ownerScoped = resolveApprovals(session.platform.approvals, isDcmThreadId(session.threadId)) === "owner";
|
|
@@ -72875,7 +73088,9 @@ class SessionManager extends EventEmitter4 {
|
|
|
72875
73088
|
this.platforms.set(platformId, client);
|
|
72876
73089
|
this.platformOverhead.set(platformId, {
|
|
72877
73090
|
sessionHeader: options?.overhead?.sessionHeader ?? DEFAULT_OVERHEAD_VISIBILITY,
|
|
72878
|
-
stickyMessage: options?.overhead?.stickyMessage ?? DEFAULT_OVERHEAD_VISIBILITY
|
|
73091
|
+
stickyMessage: options?.overhead?.stickyMessage ?? DEFAULT_OVERHEAD_VISIBILITY,
|
|
73092
|
+
lifecycle: options?.overhead?.lifecycle ?? DEFAULT_OVERHEAD_VISIBILITY,
|
|
73093
|
+
turnMarker: options?.overhead?.turnMarker ?? DEFAULT_TURN_MARKER
|
|
72879
73094
|
});
|
|
72880
73095
|
this.platformMemory.set(platformId, options?.memory ?? DEFAULT_MEMORY_CONFIG);
|
|
72881
73096
|
this.platformRoutines.set(platformId, options?.routinesEnabled ?? true);
|
|
@@ -72975,6 +73190,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
72975
73190
|
getSessionId: (pid, tid) => this.getSessionId(pid, tid),
|
|
72976
73191
|
findSessionByThreadId: (tid) => this.findSessionByThreadId(tid),
|
|
72977
73192
|
registerPost: (pid, tid) => this.registerPost(pid, tid),
|
|
73193
|
+
beginInteractivePost: (tid) => this.registry.beginInteractivePost(tid),
|
|
72978
73194
|
flush: async (s) => {
|
|
72979
73195
|
if (s.messageManager) {
|
|
72980
73196
|
await s.messageManager.flush();
|
|
@@ -73012,7 +73228,9 @@ class SessionManager extends EventEmitter4 {
|
|
|
73012
73228
|
getClaudeAccountPoolStatus: () => this.accountPool.status(),
|
|
73013
73229
|
getPlatformOverhead: (pid) => this.platformOverhead.get(pid) ?? {
|
|
73014
73230
|
sessionHeader: DEFAULT_OVERHEAD_VISIBILITY,
|
|
73015
|
-
stickyMessage: DEFAULT_OVERHEAD_VISIBILITY
|
|
73231
|
+
stickyMessage: DEFAULT_OVERHEAD_VISIBILITY,
|
|
73232
|
+
lifecycle: DEFAULT_OVERHEAD_VISIBILITY,
|
|
73233
|
+
turnMarker: DEFAULT_TURN_MARKER
|
|
73016
73234
|
},
|
|
73017
73235
|
getPlatformMemoryConfig: (pid) => this.platformMemory.get(pid) ?? DEFAULT_MEMORY_CONFIG,
|
|
73018
73236
|
isRoutinesEnabled: (pid) => this.platformRoutines.get(pid) ?? true,
|
|
@@ -73305,7 +73523,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
73305
73523
|
const pauseMessage = `⏸️ ${fmt.formatBold("Platform disabled")} - session paused. Re-enable platform to resume.`;
|
|
73306
73524
|
if (session.lifecyclePostId) {
|
|
73307
73525
|
await session.platform.updatePost(session.lifecyclePostId, pauseMessage);
|
|
73308
|
-
} else {
|
|
73526
|
+
} else if (shouldPostLifecycle(this.platformOverhead.get(session.platformId)?.lifecycle ?? DEFAULT_OVERHEAD_VISIBILITY, "paused")) {
|
|
73309
73527
|
const post = await session.platform.createPost(pauseMessage, session.threadId);
|
|
73310
73528
|
session.lifecyclePostId = post.id;
|
|
73311
73529
|
}
|
|
@@ -73797,7 +74015,7 @@ Mention me to start a session in this worktree.`, threadId);
|
|
|
73797
74015
|
const shutdownMessage = `⏸️ ${fmt.formatBold("Bot shutting down")} - session will resume on restart`;
|
|
73798
74016
|
if (session.lifecyclePostId) {
|
|
73799
74017
|
await session.platform.updatePost(session.lifecyclePostId, shutdownMessage);
|
|
73800
|
-
} else {
|
|
74018
|
+
} else if (shouldPostLifecycle(this.platformOverhead.get(session.platformId)?.lifecycle ?? DEFAULT_OVERHEAD_VISIBILITY, "shutdown")) {
|
|
73801
74019
|
const post = await session.platform.createPost(shutdownMessage, session.threadId);
|
|
73802
74020
|
session.lifecyclePostId = post.id;
|
|
73803
74021
|
}
|
|
@@ -86393,10 +86611,11 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
86393
86611
|
}
|
|
86394
86612
|
|
|
86395
86613
|
// src/auto-update/installer.ts
|
|
86614
|
+
init_state_home();
|
|
86396
86615
|
import { spawn as spawn4, spawnSync } from "child_process";
|
|
86397
86616
|
import { existsSync as existsSync17, readFileSync as readFileSync12, mkdirSync as mkdirSync8 } from "fs";
|
|
86398
|
-
import { dirname as dirname9, resolve as
|
|
86399
|
-
import { homedir as
|
|
86617
|
+
import { dirname as dirname9, resolve as resolve8 } from "path";
|
|
86618
|
+
import { homedir as homedir3 } from "os";
|
|
86400
86619
|
init_logger();
|
|
86401
86620
|
var log56 = createLogger("installer");
|
|
86402
86621
|
function detectPackageManager() {
|
|
@@ -86437,7 +86656,7 @@ function normalizePath(p) {
|
|
|
86437
86656
|
function detectOriginalInstaller() {
|
|
86438
86657
|
try {
|
|
86439
86658
|
const scriptPath = normalizePath(process.argv[1] || "");
|
|
86440
|
-
const bunGlobalDir = normalizePath(process.env.BUN_INSTALL ||
|
|
86659
|
+
const bunGlobalDir = normalizePath(process.env.BUN_INSTALL || resolve8(homedir3(), ".bun"));
|
|
86441
86660
|
if (scriptPath.startsWith(bunGlobalDir)) {
|
|
86442
86661
|
return "bun";
|
|
86443
86662
|
}
|
|
@@ -86457,7 +86676,7 @@ function detectOriginalInstaller() {
|
|
|
86457
86676
|
return null;
|
|
86458
86677
|
}
|
|
86459
86678
|
}
|
|
86460
|
-
var STATE_PATH =
|
|
86679
|
+
var STATE_PATH = resolve8(stateHome(), ".config", "claude-threads", UPDATE_STATE_FILENAME);
|
|
86461
86680
|
var PACKAGE_NAME2 = "claude-threads";
|
|
86462
86681
|
function loadUpdateState() {
|
|
86463
86682
|
try {
|
|
@@ -86879,6 +87098,102 @@ ${getRollbackInstructions(VERSION)}`).catch(() => {});
|
|
|
86879
87098
|
this.callbacks.refreshUI().catch(() => {});
|
|
86880
87099
|
}
|
|
86881
87100
|
}
|
|
87101
|
+
// src/utils/instance-lock.ts
|
|
87102
|
+
init_state_home();
|
|
87103
|
+
init_logger();
|
|
87104
|
+
import { closeSync as closeSync2, fstatSync, linkSync, mkdirSync as mkdirSync9, openSync as openSync2, readFileSync as readFileSync13, renameSync as renameSync2, statSync as statSync6, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
87105
|
+
import { dirname as dirname10, join as join19 } from "path";
|
|
87106
|
+
var log59 = createLogger("lock");
|
|
87107
|
+
var LOCKED_EXIT_CODE = 3;
|
|
87108
|
+
function acquireInstanceLock() {
|
|
87109
|
+
const path = join19(stateHome(), ".config", "claude-threads", "instance.lock");
|
|
87110
|
+
mkdirSync9(dirname10(path), { recursive: true, mode: 448 });
|
|
87111
|
+
const tmp = `${path}.${process.pid}`;
|
|
87112
|
+
writeFileSync6(tmp, String(process.pid), { mode: 384 });
|
|
87113
|
+
try {
|
|
87114
|
+
for (let attempt = 0;attempt < 5; attempt++) {
|
|
87115
|
+
let linked;
|
|
87116
|
+
try {
|
|
87117
|
+
linked = tryLink(tmp, path);
|
|
87118
|
+
} catch (err) {
|
|
87119
|
+
log59.warn(`instance lock unavailable on this filesystem (${err.code ?? String(err)}); running without it`);
|
|
87120
|
+
return () => {};
|
|
87121
|
+
}
|
|
87122
|
+
if (linked)
|
|
87123
|
+
return () => release(path);
|
|
87124
|
+
const seen = inspect(path);
|
|
87125
|
+
if (!seen)
|
|
87126
|
+
continue;
|
|
87127
|
+
if (seen.pid === process.pid)
|
|
87128
|
+
return () => release(path);
|
|
87129
|
+
if (seen.pid && isAlive(seen.pid)) {
|
|
87130
|
+
throw new Error(`another claude-threads instance (pid ${seen.pid}) already uses ${dirname10(path)} — ` + `set CLAUDE_THREADS_HOME to run a second bot; if pid ${seen.pid} is not a claude-threads process, delete ${path}`);
|
|
87131
|
+
}
|
|
87132
|
+
const aside = `${path}.stale.${process.pid}`;
|
|
87133
|
+
if (!tryRename(path, aside))
|
|
87134
|
+
continue;
|
|
87135
|
+
if (statSync6(aside).ino !== seen.ino) {
|
|
87136
|
+
tryLink(aside, path);
|
|
87137
|
+
unlinkSync4(aside);
|
|
87138
|
+
continue;
|
|
87139
|
+
}
|
|
87140
|
+
unlinkSync4(aside);
|
|
87141
|
+
}
|
|
87142
|
+
throw new Error(`could not acquire ${path}: lost the race five times`);
|
|
87143
|
+
} finally {
|
|
87144
|
+
try {
|
|
87145
|
+
unlinkSync4(tmp);
|
|
87146
|
+
} catch {}
|
|
87147
|
+
}
|
|
87148
|
+
}
|
|
87149
|
+
function inspect(path) {
|
|
87150
|
+
let fd;
|
|
87151
|
+
try {
|
|
87152
|
+
fd = openSync2(path, "r");
|
|
87153
|
+
} catch {
|
|
87154
|
+
return;
|
|
87155
|
+
}
|
|
87156
|
+
try {
|
|
87157
|
+
return { pid: Number(readFileSync13(fd, "utf8").trim()) || undefined, ino: fstatSync(fd).ino };
|
|
87158
|
+
} finally {
|
|
87159
|
+
closeSync2(fd);
|
|
87160
|
+
}
|
|
87161
|
+
}
|
|
87162
|
+
function tryLink(src, path) {
|
|
87163
|
+
try {
|
|
87164
|
+
linkSync(src, path);
|
|
87165
|
+
return true;
|
|
87166
|
+
} catch (err) {
|
|
87167
|
+
if (err.code === "EEXIST")
|
|
87168
|
+
return false;
|
|
87169
|
+
throw err;
|
|
87170
|
+
}
|
|
87171
|
+
}
|
|
87172
|
+
function tryRename(from, to) {
|
|
87173
|
+
try {
|
|
87174
|
+
renameSync2(from, to);
|
|
87175
|
+
return true;
|
|
87176
|
+
} catch (err) {
|
|
87177
|
+
if (err.code === "ENOENT")
|
|
87178
|
+
return false;
|
|
87179
|
+
throw err;
|
|
87180
|
+
}
|
|
87181
|
+
}
|
|
87182
|
+
function release(path) {
|
|
87183
|
+
try {
|
|
87184
|
+
if (inspect(path)?.pid === process.pid)
|
|
87185
|
+
unlinkSync4(path);
|
|
87186
|
+
} catch {}
|
|
87187
|
+
}
|
|
87188
|
+
function isAlive(pid) {
|
|
87189
|
+
try {
|
|
87190
|
+
process.kill(pid, 0);
|
|
87191
|
+
return true;
|
|
87192
|
+
} catch (err) {
|
|
87193
|
+
return err.code === "EPERM";
|
|
87194
|
+
}
|
|
87195
|
+
}
|
|
87196
|
+
|
|
86882
87197
|
// src/index.ts
|
|
86883
87198
|
function createPlatformClient(config) {
|
|
86884
87199
|
switch (config.type) {
|
|
@@ -87108,6 +87423,15 @@ async function startWithoutDaemon() {
|
|
|
87108
87423
|
console.error(yellow(` ⚠️ --skip-version-check: ${prefix}${claudeValidation.message}`));
|
|
87109
87424
|
console.error("");
|
|
87110
87425
|
}
|
|
87426
|
+
let releaseInstanceLock;
|
|
87427
|
+
try {
|
|
87428
|
+
releaseInstanceLock = acquireInstanceLock();
|
|
87429
|
+
} catch (err) {
|
|
87430
|
+
console.error(red(` ❌ ${err instanceof Error ? err.message : String(err)}`));
|
|
87431
|
+
console.error("");
|
|
87432
|
+
process.exit(LOCKED_EXIT_CODE);
|
|
87433
|
+
}
|
|
87434
|
+
process.on("exit", () => releaseInstanceLock());
|
|
87111
87435
|
if (process.env.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB === "1") {
|
|
87112
87436
|
const hasSkipPermissionPlatform = config.platforms.some((p) => p.skipPermissions === true);
|
|
87113
87437
|
if (hasSkipPermissionPlatform) {
|
|
@@ -87286,7 +87610,9 @@ async function startWithoutDaemon() {
|
|
|
87286
87610
|
session.addPlatform(platformConfig.id, client, {
|
|
87287
87611
|
overhead: {
|
|
87288
87612
|
sessionHeader: resolveOverheadVisibility(platformConfig.sessionHeader, `platforms[${platformConfig.id}].sessionHeader`),
|
|
87289
|
-
stickyMessage: resolveOverheadVisibility(platformConfig.stickyMessage, `platforms[${platformConfig.id}].stickyMessage`)
|
|
87613
|
+
stickyMessage: resolveOverheadVisibility(platformConfig.stickyMessage, `platforms[${platformConfig.id}].stickyMessage`),
|
|
87614
|
+
lifecycle: resolveOverheadVisibility(platformConfig.lifecycle, `platforms[${platformConfig.id}].lifecycle`),
|
|
87615
|
+
turnMarker: resolveTurnMarker(platformConfig.turnMarker, platformConfig.turnMarkerEmoji, platformConfig.type, `platforms[${platformConfig.id}]`)
|
|
87290
87616
|
},
|
|
87291
87617
|
memory: resolveMemoryConfig(platformConfig.memory, `platforms[${platformConfig.id}].memory`),
|
|
87292
87618
|
routinesEnabled: resolveRoutinesEnabled(platformConfig.routines, `platforms[${platformConfig.id}].routines`),
|
|
@@ -87313,7 +87639,9 @@ async function startWithoutDaemon() {
|
|
|
87313
87639
|
session.addPlatform(dmConfig.id, dmClient, {
|
|
87314
87640
|
overhead: {
|
|
87315
87641
|
sessionHeader: resolveOverheadVisibility(dmConfig.sessionHeader, `dm[${dmConfig.id}].sessionHeader`),
|
|
87316
|
-
stickyMessage: "hidden"
|
|
87642
|
+
stickyMessage: "hidden",
|
|
87643
|
+
lifecycle: resolveOverheadVisibility(dmConfig.lifecycle, `dm[${dmConfig.id}].lifecycle`),
|
|
87644
|
+
turnMarker: resolveTurnMarker(dmConfig.turnMarker, dmConfig.turnMarkerEmoji, dmConfig.type, `dm[${dmConfig.id}]`)
|
|
87317
87645
|
},
|
|
87318
87646
|
memory: resolveMemoryConfig(dmConfig.memory, `dm[${dmConfig.id}].memory`),
|
|
87319
87647
|
routinesEnabled: resolveRoutinesEnabled(dmConfig.routines, `dm[${dmConfig.id}].routines`),
|