claude-threads 1.9.2 → 1.9.4
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 +14 -0
- package/dist/index.js +484 -431
- package/dist/mcp/permission-server.js +75 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11747,76 +11747,6 @@ var require_ws = __commonJS((exports, module) => {
|
|
|
11747
11747
|
module.exports = WebSocket;
|
|
11748
11748
|
});
|
|
11749
11749
|
|
|
11750
|
-
// src/utils/emoji.ts
|
|
11751
|
-
var exports_emoji = {};
|
|
11752
|
-
__export(exports_emoji, {
|
|
11753
|
-
isResumeEmoji: () => isResumeEmoji,
|
|
11754
|
-
isMinimizeToggleEmoji: () => isMinimizeToggleEmoji,
|
|
11755
|
-
isEscapeEmoji: () => isEscapeEmoji,
|
|
11756
|
-
isDenialEmoji: () => isDenialEmoji,
|
|
11757
|
-
isCancelEmoji: () => isCancelEmoji,
|
|
11758
|
-
isBugReportEmoji: () => isBugReportEmoji,
|
|
11759
|
-
isApprovalEmoji: () => isApprovalEmoji,
|
|
11760
|
-
isAllowAllEmoji: () => isAllowAllEmoji,
|
|
11761
|
-
getNumberEmojiIndex: () => getNumberEmojiIndex,
|
|
11762
|
-
RESUME_EMOJIS: () => RESUME_EMOJIS,
|
|
11763
|
-
NUMBER_EMOJIS: () => NUMBER_EMOJIS,
|
|
11764
|
-
MINIMIZE_TOGGLE_EMOJIS: () => MINIMIZE_TOGGLE_EMOJIS,
|
|
11765
|
-
ESCAPE_EMOJIS: () => ESCAPE_EMOJIS,
|
|
11766
|
-
DENIAL_EMOJIS: () => DENIAL_EMOJIS,
|
|
11767
|
-
CANCEL_EMOJIS: () => CANCEL_EMOJIS,
|
|
11768
|
-
BUG_REPORT_EMOJI: () => BUG_REPORT_EMOJI,
|
|
11769
|
-
APPROVAL_EMOJIS: () => APPROVAL_EMOJIS,
|
|
11770
|
-
ALLOW_ALL_EMOJIS: () => ALLOW_ALL_EMOJIS
|
|
11771
|
-
});
|
|
11772
|
-
function isApprovalEmoji(emoji) {
|
|
11773
|
-
return APPROVAL_EMOJIS.includes(emoji);
|
|
11774
|
-
}
|
|
11775
|
-
function isDenialEmoji(emoji) {
|
|
11776
|
-
return DENIAL_EMOJIS.includes(emoji);
|
|
11777
|
-
}
|
|
11778
|
-
function isAllowAllEmoji(emoji) {
|
|
11779
|
-
return ALLOW_ALL_EMOJIS.includes(emoji);
|
|
11780
|
-
}
|
|
11781
|
-
function isCancelEmoji(emoji) {
|
|
11782
|
-
return CANCEL_EMOJIS.includes(emoji);
|
|
11783
|
-
}
|
|
11784
|
-
function isEscapeEmoji(emoji) {
|
|
11785
|
-
return ESCAPE_EMOJIS.includes(emoji);
|
|
11786
|
-
}
|
|
11787
|
-
function isResumeEmoji(emoji) {
|
|
11788
|
-
return RESUME_EMOJIS.includes(emoji);
|
|
11789
|
-
}
|
|
11790
|
-
function isMinimizeToggleEmoji(emoji) {
|
|
11791
|
-
return MINIMIZE_TOGGLE_EMOJIS.includes(emoji);
|
|
11792
|
-
}
|
|
11793
|
-
function isBugReportEmoji(emoji) {
|
|
11794
|
-
return emoji === BUG_REPORT_EMOJI || emoji === "\uD83D\uDC1B";
|
|
11795
|
-
}
|
|
11796
|
-
function getNumberEmojiIndex(emoji) {
|
|
11797
|
-
const textIndex = NUMBER_EMOJIS.indexOf(emoji);
|
|
11798
|
-
if (textIndex >= 0)
|
|
11799
|
-
return textIndex;
|
|
11800
|
-
return UNICODE_NUMBER_EMOJIS[emoji] ?? -1;
|
|
11801
|
-
}
|
|
11802
|
-
var APPROVAL_EMOJIS, DENIAL_EMOJIS, ALLOW_ALL_EMOJIS, NUMBER_EMOJIS, CANCEL_EMOJIS, ESCAPE_EMOJIS, RESUME_EMOJIS, MINIMIZE_TOGGLE_EMOJIS, BUG_REPORT_EMOJI = "bug", UNICODE_NUMBER_EMOJIS;
|
|
11803
|
-
var init_emoji = __esm(() => {
|
|
11804
|
-
APPROVAL_EMOJIS = ["+1", "thumbsup"];
|
|
11805
|
-
DENIAL_EMOJIS = ["-1", "thumbsdown"];
|
|
11806
|
-
ALLOW_ALL_EMOJIS = ["white_check_mark", "heavy_check_mark"];
|
|
11807
|
-
NUMBER_EMOJIS = ["one", "two", "three", "four"];
|
|
11808
|
-
CANCEL_EMOJIS = ["x", "octagonal_sign", "stop_sign", "stop"];
|
|
11809
|
-
ESCAPE_EMOJIS = ["double_vertical_bar", "pause_button", "pause"];
|
|
11810
|
-
RESUME_EMOJIS = ["arrows_counterclockwise", "arrow_forward", "repeat"];
|
|
11811
|
-
MINIMIZE_TOGGLE_EMOJIS = ["arrow_down_small", "small_red_triangle_down"];
|
|
11812
|
-
UNICODE_NUMBER_EMOJIS = {
|
|
11813
|
-
"1️⃣": 0,
|
|
11814
|
-
"2️⃣": 1,
|
|
11815
|
-
"3️⃣": 2,
|
|
11816
|
-
"4️⃣": 3
|
|
11817
|
-
};
|
|
11818
|
-
});
|
|
11819
|
-
|
|
11820
11750
|
// src/utils/spawn.ts
|
|
11821
11751
|
import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "child_process";
|
|
11822
11752
|
function addWindowsShell(options2) {
|
|
@@ -12161,6 +12091,76 @@ var init_worktree = __esm(() => {
|
|
|
12161
12091
|
METADATA_STORE_PATH = path.join(homedir4(), ".claude-threads", "worktree-metadata.json");
|
|
12162
12092
|
});
|
|
12163
12093
|
|
|
12094
|
+
// src/utils/emoji.ts
|
|
12095
|
+
var exports_emoji = {};
|
|
12096
|
+
__export(exports_emoji, {
|
|
12097
|
+
isResumeEmoji: () => isResumeEmoji,
|
|
12098
|
+
isMinimizeToggleEmoji: () => isMinimizeToggleEmoji,
|
|
12099
|
+
isEscapeEmoji: () => isEscapeEmoji,
|
|
12100
|
+
isDenialEmoji: () => isDenialEmoji,
|
|
12101
|
+
isCancelEmoji: () => isCancelEmoji,
|
|
12102
|
+
isBugReportEmoji: () => isBugReportEmoji,
|
|
12103
|
+
isApprovalEmoji: () => isApprovalEmoji,
|
|
12104
|
+
isAllowAllEmoji: () => isAllowAllEmoji,
|
|
12105
|
+
getNumberEmojiIndex: () => getNumberEmojiIndex,
|
|
12106
|
+
RESUME_EMOJIS: () => RESUME_EMOJIS,
|
|
12107
|
+
NUMBER_EMOJIS: () => NUMBER_EMOJIS,
|
|
12108
|
+
MINIMIZE_TOGGLE_EMOJIS: () => MINIMIZE_TOGGLE_EMOJIS,
|
|
12109
|
+
ESCAPE_EMOJIS: () => ESCAPE_EMOJIS,
|
|
12110
|
+
DENIAL_EMOJIS: () => DENIAL_EMOJIS,
|
|
12111
|
+
CANCEL_EMOJIS: () => CANCEL_EMOJIS,
|
|
12112
|
+
BUG_REPORT_EMOJI: () => BUG_REPORT_EMOJI,
|
|
12113
|
+
APPROVAL_EMOJIS: () => APPROVAL_EMOJIS,
|
|
12114
|
+
ALLOW_ALL_EMOJIS: () => ALLOW_ALL_EMOJIS
|
|
12115
|
+
});
|
|
12116
|
+
function isApprovalEmoji(emoji) {
|
|
12117
|
+
return APPROVAL_EMOJIS.includes(emoji);
|
|
12118
|
+
}
|
|
12119
|
+
function isDenialEmoji(emoji) {
|
|
12120
|
+
return DENIAL_EMOJIS.includes(emoji);
|
|
12121
|
+
}
|
|
12122
|
+
function isAllowAllEmoji(emoji) {
|
|
12123
|
+
return ALLOW_ALL_EMOJIS.includes(emoji);
|
|
12124
|
+
}
|
|
12125
|
+
function isCancelEmoji(emoji) {
|
|
12126
|
+
return CANCEL_EMOJIS.includes(emoji);
|
|
12127
|
+
}
|
|
12128
|
+
function isEscapeEmoji(emoji) {
|
|
12129
|
+
return ESCAPE_EMOJIS.includes(emoji);
|
|
12130
|
+
}
|
|
12131
|
+
function isResumeEmoji(emoji) {
|
|
12132
|
+
return RESUME_EMOJIS.includes(emoji);
|
|
12133
|
+
}
|
|
12134
|
+
function isMinimizeToggleEmoji(emoji) {
|
|
12135
|
+
return MINIMIZE_TOGGLE_EMOJIS.includes(emoji);
|
|
12136
|
+
}
|
|
12137
|
+
function isBugReportEmoji(emoji) {
|
|
12138
|
+
return emoji === BUG_REPORT_EMOJI || emoji === "\uD83D\uDC1B";
|
|
12139
|
+
}
|
|
12140
|
+
function getNumberEmojiIndex(emoji) {
|
|
12141
|
+
const textIndex = NUMBER_EMOJIS.indexOf(emoji);
|
|
12142
|
+
if (textIndex >= 0)
|
|
12143
|
+
return textIndex;
|
|
12144
|
+
return UNICODE_NUMBER_EMOJIS[emoji] ?? -1;
|
|
12145
|
+
}
|
|
12146
|
+
var APPROVAL_EMOJIS, DENIAL_EMOJIS, ALLOW_ALL_EMOJIS, NUMBER_EMOJIS, CANCEL_EMOJIS, ESCAPE_EMOJIS, RESUME_EMOJIS, MINIMIZE_TOGGLE_EMOJIS, BUG_REPORT_EMOJI = "bug", UNICODE_NUMBER_EMOJIS;
|
|
12147
|
+
var init_emoji = __esm(() => {
|
|
12148
|
+
APPROVAL_EMOJIS = ["+1", "thumbsup"];
|
|
12149
|
+
DENIAL_EMOJIS = ["-1", "thumbsdown"];
|
|
12150
|
+
ALLOW_ALL_EMOJIS = ["white_check_mark", "heavy_check_mark"];
|
|
12151
|
+
NUMBER_EMOJIS = ["one", "two", "three", "four"];
|
|
12152
|
+
CANCEL_EMOJIS = ["x", "octagonal_sign", "stop_sign", "stop"];
|
|
12153
|
+
ESCAPE_EMOJIS = ["double_vertical_bar", "pause_button", "pause"];
|
|
12154
|
+
RESUME_EMOJIS = ["arrows_counterclockwise", "arrow_forward", "repeat"];
|
|
12155
|
+
MINIMIZE_TOGGLE_EMOJIS = ["arrow_down_small", "small_red_triangle_down"];
|
|
12156
|
+
UNICODE_NUMBER_EMOJIS = {
|
|
12157
|
+
"1️⃣": 0,
|
|
12158
|
+
"2️⃣": 1,
|
|
12159
|
+
"3️⃣": 2,
|
|
12160
|
+
"4️⃣": 3
|
|
12161
|
+
};
|
|
12162
|
+
});
|
|
12163
|
+
|
|
12164
12164
|
// node_modules/pend/index.js
|
|
12165
12165
|
var require_pend = __commonJS((exports, module) => {
|
|
12166
12166
|
module.exports = Pend;
|
|
@@ -19496,7 +19496,7 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
|
|
|
19496
19496
|
return hook.checkDCE ? true : false;
|
|
19497
19497
|
}
|
|
19498
19498
|
function setIsStrictModeForDevtools(newIsStrictMode) {
|
|
19499
|
-
typeof
|
|
19499
|
+
typeof log32 === "function" && unstable_setDisableYieldValue2(newIsStrictMode);
|
|
19500
19500
|
if (injectedHook && typeof injectedHook.setStrictMode === "function")
|
|
19501
19501
|
try {
|
|
19502
19502
|
injectedHook.setStrictMode(rendererID, newIsStrictMode);
|
|
@@ -22381,7 +22381,7 @@ Incoming: %s`, currentHookNameInDev, "[" + prevDeps.join(", ") + "]", "[" + next
|
|
|
22381
22381
|
if (queue === null)
|
|
22382
22382
|
throw Error("Should have a queue. You are likely calling Hooks conditionally, which is not allowed. (https://react.dev/link/invalid-hook-call)");
|
|
22383
22383
|
queue.lastRenderedReducer = reducer;
|
|
22384
|
-
var { dispatch, pending: lastRenderPhaseUpdate } = queue, newState = hook.memoizedState;
|
|
22384
|
+
var { dispatch: dispatch2, pending: lastRenderPhaseUpdate } = queue, newState = hook.memoizedState;
|
|
22385
22385
|
if (lastRenderPhaseUpdate !== null) {
|
|
22386
22386
|
queue.pending = null;
|
|
22387
22387
|
var update = lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
|
|
@@ -22393,7 +22393,7 @@ Incoming: %s`, currentHookNameInDev, "[" + prevDeps.join(", ") + "]", "[" + next
|
|
|
22393
22393
|
hook.baseQueue === null && (hook.baseState = newState);
|
|
22394
22394
|
queue.lastRenderedState = newState;
|
|
22395
22395
|
}
|
|
22396
|
-
return [newState,
|
|
22396
|
+
return [newState, dispatch2];
|
|
22397
22397
|
}
|
|
22398
22398
|
function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
|
|
22399
22399
|
var fiber = currentlyRenderingFiber, hook = mountWorkInProgressHook();
|
|
@@ -22497,9 +22497,9 @@ Incoming: %s`, currentHookNameInDev, "[" + prevDeps.join(", ") + "]", "[" + next
|
|
|
22497
22497
|
}
|
|
22498
22498
|
function mountState(initialState) {
|
|
22499
22499
|
initialState = mountStateImpl(initialState);
|
|
22500
|
-
var queue = initialState.queue,
|
|
22501
|
-
queue.dispatch =
|
|
22502
|
-
return [initialState.memoizedState,
|
|
22500
|
+
var queue = initialState.queue, dispatch2 = dispatchSetState.bind(null, currentlyRenderingFiber, queue);
|
|
22501
|
+
queue.dispatch = dispatch2;
|
|
22502
|
+
return [initialState.memoizedState, dispatch2];
|
|
22503
22503
|
}
|
|
22504
22504
|
function mountOptimistic(passthrough) {
|
|
22505
22505
|
var hook = mountWorkInProgressHook();
|
|
@@ -22678,9 +22678,9 @@ Incoming: %s`, currentHookNameInDev, "[" + prevDeps.join(", ") + "]", "[" + next
|
|
|
22678
22678
|
else
|
|
22679
22679
|
state = currentStateHook;
|
|
22680
22680
|
currentStateHook = updateWorkInProgressHook();
|
|
22681
|
-
var actionQueue = currentStateHook.queue,
|
|
22681
|
+
var actionQueue = currentStateHook.queue, dispatch2 = actionQueue.dispatch;
|
|
22682
22682
|
action !== currentStateHook.memoizedState && (currentlyRenderingFiber.flags |= 2048, pushSimpleEffect(HasEffect | Passive, { destroy: undefined }, actionStateActionEffect.bind(null, actionQueue, action), null));
|
|
22683
|
-
return [state,
|
|
22683
|
+
return [state, dispatch2, stateHook];
|
|
22684
22684
|
}
|
|
22685
22685
|
function actionStateActionEffect(actionQueue, action) {
|
|
22686
22686
|
actionQueue.action = action;
|
|
@@ -22692,9 +22692,9 @@ Incoming: %s`, currentHookNameInDev, "[" + prevDeps.join(", ") + "]", "[" + next
|
|
|
22692
22692
|
updateWorkInProgressHook();
|
|
22693
22693
|
stateHook = stateHook.memoizedState;
|
|
22694
22694
|
currentStateHook = updateWorkInProgressHook();
|
|
22695
|
-
var
|
|
22695
|
+
var dispatch2 = currentStateHook.queue.dispatch;
|
|
22696
22696
|
currentStateHook.memoizedState = action;
|
|
22697
|
-
return [stateHook,
|
|
22697
|
+
return [stateHook, dispatch2, false];
|
|
22698
22698
|
}
|
|
22699
22699
|
function pushSimpleEffect(tag, inst, create, deps) {
|
|
22700
22700
|
tag = { tag, create, deps, inst, next: null };
|
|
@@ -27580,7 +27580,7 @@ Check the render method of %s.`, getComponentNameFromFiber(current) || "Unknown"
|
|
|
27580
27580
|
var fiberStack = [];
|
|
27581
27581
|
var index$jscomp$0 = -1, emptyContextObject = {};
|
|
27582
27582
|
Object.freeze(emptyContextObject);
|
|
27583
|
-
var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, log$1 = Math.log, LN2 = Math.LN2, nextTransitionUpdateLane = 256, nextTransitionDeferredLane = 262144, nextRetryLane = 4194304, scheduleCallback$3 = Scheduler.unstable_scheduleCallback, cancelCallback$1 = Scheduler.unstable_cancelCallback, shouldYield = Scheduler.unstable_shouldYield, requestPaint = Scheduler.unstable_requestPaint, now$1 = Scheduler.unstable_now, ImmediatePriority = Scheduler.unstable_ImmediatePriority, UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, NormalPriority$1 = Scheduler.unstable_NormalPriority, IdlePriority = Scheduler.unstable_IdlePriority,
|
|
27583
|
+
var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, log$1 = Math.log, LN2 = Math.LN2, nextTransitionUpdateLane = 256, nextTransitionDeferredLane = 262144, nextRetryLane = 4194304, scheduleCallback$3 = Scheduler.unstable_scheduleCallback, cancelCallback$1 = Scheduler.unstable_cancelCallback, shouldYield = Scheduler.unstable_shouldYield, requestPaint = Scheduler.unstable_requestPaint, now$1 = Scheduler.unstable_now, ImmediatePriority = Scheduler.unstable_ImmediatePriority, UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, NormalPriority$1 = Scheduler.unstable_NormalPriority, IdlePriority = Scheduler.unstable_IdlePriority, log32 = Scheduler.log, unstable_setDisableYieldValue2 = Scheduler.unstable_setDisableYieldValue, rendererID = null, injectedHook = null, hasLoggedError = false, isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined", lastResetTime = 0;
|
|
27584
27584
|
if (typeof performance === "object" && typeof performance.now === "function") {
|
|
27585
27585
|
var localPerformance = performance;
|
|
27586
27586
|
var getCurrentTime = function() {
|
|
@@ -53750,9 +53750,6 @@ class AccountPool {
|
|
|
53750
53750
|
}
|
|
53751
53751
|
}
|
|
53752
53752
|
|
|
53753
|
-
// src/session/manager.ts
|
|
53754
|
-
init_emoji();
|
|
53755
|
-
|
|
53756
53753
|
// src/cleanup/scheduler.ts
|
|
53757
53754
|
init_logger();
|
|
53758
53755
|
import { existsSync as existsSync7 } from "fs";
|
|
@@ -54213,6 +54210,50 @@ class CleanupScheduler {
|
|
|
54213
54210
|
// src/operations/monitor/handler.ts
|
|
54214
54211
|
init_logger();
|
|
54215
54212
|
|
|
54213
|
+
// src/session/lifecycle-fsm.ts
|
|
54214
|
+
init_logger();
|
|
54215
|
+
var log9 = createLogger("fsm");
|
|
54216
|
+
var ALLOWED_TRANSITIONS = {
|
|
54217
|
+
starting: new Set(["active", "paused", "interrupted", "cancelling", "restarting"]),
|
|
54218
|
+
active: new Set([
|
|
54219
|
+
"active",
|
|
54220
|
+
"processing",
|
|
54221
|
+
"paused",
|
|
54222
|
+
"interrupted",
|
|
54223
|
+
"restarting",
|
|
54224
|
+
"cancelling",
|
|
54225
|
+
"ending"
|
|
54226
|
+
]),
|
|
54227
|
+
processing: new Set([
|
|
54228
|
+
"active",
|
|
54229
|
+
"paused",
|
|
54230
|
+
"interrupted",
|
|
54231
|
+
"restarting",
|
|
54232
|
+
"cancelling"
|
|
54233
|
+
]),
|
|
54234
|
+
paused: new Set(["active", "cancelling", "restarting"]),
|
|
54235
|
+
interrupted: new Set(["active", "cancelling", "restarting", "paused"]),
|
|
54236
|
+
restarting: new Set(["active", "paused", "cancelling"]),
|
|
54237
|
+
cancelling: new Set(["ending"]),
|
|
54238
|
+
ending: new Set
|
|
54239
|
+
};
|
|
54240
|
+
function checkTransition(from, to, sessionId) {
|
|
54241
|
+
const allowed = ALLOWED_TRANSITIONS[from];
|
|
54242
|
+
if (allowed.has(to))
|
|
54243
|
+
return;
|
|
54244
|
+
const msg = `illegal lifecycle transition ${from} -> ${to}`;
|
|
54245
|
+
const payload = {
|
|
54246
|
+
event: "fsm.illegal_transition",
|
|
54247
|
+
from,
|
|
54248
|
+
to,
|
|
54249
|
+
sessionId
|
|
54250
|
+
};
|
|
54251
|
+
if (process.env.CLAUDE_THREADS_FSM_STRICT === "1") {
|
|
54252
|
+
throw new Error(`${msg} (sessionId=${sessionId})`);
|
|
54253
|
+
}
|
|
54254
|
+
log9.warn(msg, payload);
|
|
54255
|
+
}
|
|
54256
|
+
|
|
54216
54257
|
// src/session/timer-manager.ts
|
|
54217
54258
|
function createSessionTimers() {
|
|
54218
54259
|
return {
|
|
@@ -54258,6 +54299,7 @@ function isSessionCancelled(session) {
|
|
|
54258
54299
|
return session.lifecycle.state === "cancelling";
|
|
54259
54300
|
}
|
|
54260
54301
|
function transitionTo(session, newState) {
|
|
54302
|
+
checkTransition(session.lifecycle.state, newState, session.sessionId);
|
|
54261
54303
|
session.lifecycle.state = newState;
|
|
54262
54304
|
}
|
|
54263
54305
|
function markClaudeResponded(session) {
|
|
@@ -54345,7 +54387,7 @@ function extractResetAt(text, now) {
|
|
|
54345
54387
|
}
|
|
54346
54388
|
|
|
54347
54389
|
// src/claude/cli.ts
|
|
54348
|
-
var
|
|
54390
|
+
var log10 = createLogger("claude");
|
|
54349
54391
|
function cleanupBrowserBridgeSockets() {
|
|
54350
54392
|
try {
|
|
54351
54393
|
const tempDir = tmpdir();
|
|
@@ -54357,13 +54399,13 @@ function cleanupBrowserBridgeSockets() {
|
|
|
54357
54399
|
const stats = statSync2(filePath);
|
|
54358
54400
|
if (stats.isSocket()) {
|
|
54359
54401
|
unlinkSync2(filePath);
|
|
54360
|
-
|
|
54402
|
+
log10.debug(`Removed stale browser bridge socket: ${file}`);
|
|
54361
54403
|
}
|
|
54362
54404
|
} catch {}
|
|
54363
54405
|
}
|
|
54364
54406
|
}
|
|
54365
54407
|
} catch (err) {
|
|
54366
|
-
|
|
54408
|
+
log10.debug(`Browser bridge cleanup failed: ${err}`);
|
|
54367
54409
|
}
|
|
54368
54410
|
}
|
|
54369
54411
|
function buildClaudeChildEnv(parentEnv, account) {
|
|
@@ -54394,7 +54436,7 @@ function isErrorResultEvent(event) {
|
|
|
54394
54436
|
return false;
|
|
54395
54437
|
}
|
|
54396
54438
|
function materializeMcpConfig(config, sessionId, opts = {}) {
|
|
54397
|
-
if (opts.inline
|
|
54439
|
+
if (opts.inline) {
|
|
54398
54440
|
return { mode: "inline", value: JSON.stringify(config) };
|
|
54399
54441
|
}
|
|
54400
54442
|
const dir = opts.tmpDirOverride ?? tmpdir();
|
|
@@ -55599,7 +55641,7 @@ import { existsSync as existsSync11 } from "fs";
|
|
|
55599
55641
|
// src/utils/keep-alive.ts
|
|
55600
55642
|
init_logger();
|
|
55601
55643
|
import { spawn as spawn2 } from "child_process";
|
|
55602
|
-
var
|
|
55644
|
+
var log11 = createLogger("keepalive");
|
|
55603
55645
|
|
|
55604
55646
|
class KeepAliveManager {
|
|
55605
55647
|
activeSessionCount = 0;
|
|
@@ -55614,7 +55656,7 @@ class KeepAliveManager {
|
|
|
55614
55656
|
if (!enabled && this.keepAliveProcess) {
|
|
55615
55657
|
this.stopKeepAlive();
|
|
55616
55658
|
}
|
|
55617
|
-
|
|
55659
|
+
log11.debug(`Keep-alive ${enabled ? "enabled" : "disabled"}`);
|
|
55618
55660
|
}
|
|
55619
55661
|
isEnabled() {
|
|
55620
55662
|
return this.enabled;
|
|
@@ -55624,7 +55666,7 @@ class KeepAliveManager {
|
|
|
55624
55666
|
}
|
|
55625
55667
|
sessionStarted() {
|
|
55626
55668
|
this.activeSessionCount++;
|
|
55627
|
-
|
|
55669
|
+
log11.debug(`Session started (${this.activeSessionCount} active)`);
|
|
55628
55670
|
if (this.activeSessionCount === 1) {
|
|
55629
55671
|
this.startKeepAlive();
|
|
55630
55672
|
}
|
|
@@ -55633,7 +55675,7 @@ class KeepAliveManager {
|
|
|
55633
55675
|
if (this.activeSessionCount > 0) {
|
|
55634
55676
|
this.activeSessionCount--;
|
|
55635
55677
|
}
|
|
55636
|
-
|
|
55678
|
+
log11.debug(`Session ended (${this.activeSessionCount} active)`);
|
|
55637
55679
|
if (this.activeSessionCount === 0) {
|
|
55638
55680
|
this.stopKeepAlive();
|
|
55639
55681
|
}
|
|
@@ -55647,11 +55689,11 @@ class KeepAliveManager {
|
|
|
55647
55689
|
}
|
|
55648
55690
|
startKeepAlive() {
|
|
55649
55691
|
if (!this.enabled) {
|
|
55650
|
-
|
|
55692
|
+
log11.debug("Keep-alive disabled, skipping");
|
|
55651
55693
|
return;
|
|
55652
55694
|
}
|
|
55653
55695
|
if (this.keepAliveProcess) {
|
|
55654
|
-
|
|
55696
|
+
log11.debug("Keep-alive already running");
|
|
55655
55697
|
return;
|
|
55656
55698
|
}
|
|
55657
55699
|
switch (this.platform) {
|
|
@@ -55665,12 +55707,12 @@ class KeepAliveManager {
|
|
|
55665
55707
|
this.startWindowsKeepAlive();
|
|
55666
55708
|
break;
|
|
55667
55709
|
default:
|
|
55668
|
-
|
|
55710
|
+
log11.warn(`Keep-alive not supported on ${this.platform}`);
|
|
55669
55711
|
}
|
|
55670
55712
|
}
|
|
55671
55713
|
stopKeepAlive() {
|
|
55672
55714
|
if (this.keepAliveProcess) {
|
|
55673
|
-
|
|
55715
|
+
log11.debug("Stopping keep-alive");
|
|
55674
55716
|
this.keepAliveProcess.kill();
|
|
55675
55717
|
this.keepAliveProcess = null;
|
|
55676
55718
|
}
|
|
@@ -55682,18 +55724,18 @@ class KeepAliveManager {
|
|
|
55682
55724
|
detached: false
|
|
55683
55725
|
});
|
|
55684
55726
|
this.keepAliveProcess.on("error", (err) => {
|
|
55685
|
-
|
|
55727
|
+
log11.error(`Failed to start caffeinate: ${err.message}`);
|
|
55686
55728
|
this.keepAliveProcess = null;
|
|
55687
55729
|
});
|
|
55688
55730
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55689
55731
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55690
|
-
|
|
55732
|
+
log11.debug(`caffeinate exited with code ${code}`);
|
|
55691
55733
|
}
|
|
55692
55734
|
this.keepAliveProcess = null;
|
|
55693
55735
|
});
|
|
55694
|
-
|
|
55736
|
+
log11.info("Sleep prevention active (caffeinate)");
|
|
55695
55737
|
} catch (err) {
|
|
55696
|
-
|
|
55738
|
+
log11.error(`Failed to start caffeinate: ${err}`);
|
|
55697
55739
|
}
|
|
55698
55740
|
}
|
|
55699
55741
|
startLinuxKeepAlive() {
|
|
@@ -55709,19 +55751,19 @@ class KeepAliveManager {
|
|
|
55709
55751
|
detached: false
|
|
55710
55752
|
});
|
|
55711
55753
|
this.keepAliveProcess.on("error", (err) => {
|
|
55712
|
-
|
|
55754
|
+
log11.debug(`systemd-inhibit not available: ${err.message}`);
|
|
55713
55755
|
this.keepAliveProcess = null;
|
|
55714
55756
|
this.startLinuxKeepAliveFallback();
|
|
55715
55757
|
});
|
|
55716
55758
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55717
55759
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55718
|
-
|
|
55760
|
+
log11.debug(`systemd-inhibit exited with code ${code}`);
|
|
55719
55761
|
}
|
|
55720
55762
|
this.keepAliveProcess = null;
|
|
55721
55763
|
});
|
|
55722
|
-
|
|
55764
|
+
log11.info("Sleep prevention active (systemd-inhibit)");
|
|
55723
55765
|
} catch (err) {
|
|
55724
|
-
|
|
55766
|
+
log11.debug(`Failed to start systemd-inhibit: ${err}`);
|
|
55725
55767
|
this.startLinuxKeepAliveFallback();
|
|
55726
55768
|
}
|
|
55727
55769
|
}
|
|
@@ -55735,15 +55777,15 @@ class KeepAliveManager {
|
|
|
55735
55777
|
detached: false
|
|
55736
55778
|
});
|
|
55737
55779
|
this.keepAliveProcess.on("error", (err) => {
|
|
55738
|
-
|
|
55780
|
+
log11.warn(`Linux keep-alive fallback not available: ${err.message}`);
|
|
55739
55781
|
this.keepAliveProcess = null;
|
|
55740
55782
|
});
|
|
55741
55783
|
this.keepAliveProcess.on("exit", () => {
|
|
55742
55784
|
this.keepAliveProcess = null;
|
|
55743
55785
|
});
|
|
55744
|
-
|
|
55786
|
+
log11.info("Sleep prevention active (xdg-screensaver)");
|
|
55745
55787
|
} catch (err) {
|
|
55746
|
-
|
|
55788
|
+
log11.warn(`Linux keep-alive not available: ${err}`);
|
|
55747
55789
|
}
|
|
55748
55790
|
}
|
|
55749
55791
|
startWindowsKeepAlive() {
|
|
@@ -55768,18 +55810,18 @@ class KeepAliveManager {
|
|
|
55768
55810
|
windowsHide: true
|
|
55769
55811
|
});
|
|
55770
55812
|
this.keepAliveProcess.on("error", (err) => {
|
|
55771
|
-
|
|
55813
|
+
log11.warn(`Windows keep-alive not available: ${err.message}`);
|
|
55772
55814
|
this.keepAliveProcess = null;
|
|
55773
55815
|
});
|
|
55774
55816
|
this.keepAliveProcess.on("exit", (code) => {
|
|
55775
55817
|
if (code !== null && code !== 0 && this.activeSessionCount > 0) {
|
|
55776
|
-
|
|
55818
|
+
log11.debug(`PowerShell keep-alive exited with code ${code}`);
|
|
55777
55819
|
}
|
|
55778
55820
|
this.keepAliveProcess = null;
|
|
55779
55821
|
});
|
|
55780
|
-
|
|
55822
|
+
log11.info("Sleep prevention active (SetThreadExecutionState)");
|
|
55781
55823
|
} catch (err) {
|
|
55782
|
-
|
|
55824
|
+
log11.warn(`Windows keep-alive not available: ${err}`);
|
|
55783
55825
|
}
|
|
55784
55826
|
}
|
|
55785
55827
|
}
|
|
@@ -55787,7 +55829,7 @@ var keepAlive = new KeepAliveManager;
|
|
|
55787
55829
|
|
|
55788
55830
|
// src/utils/error-handler/index.ts
|
|
55789
55831
|
init_logger();
|
|
55790
|
-
var
|
|
55832
|
+
var log12 = createLogger("error");
|
|
55791
55833
|
|
|
55792
55834
|
class SessionError extends Error {
|
|
55793
55835
|
sessionId;
|
|
@@ -55813,19 +55855,19 @@ async function handleError(error, context, severity = "recoverable") {
|
|
|
55813
55855
|
const sessionPart = sessionId ? ` (${formatShortId(sessionId)})` : "";
|
|
55814
55856
|
const logMessage = `${context.action}${sessionPart}: ${message}`;
|
|
55815
55857
|
if (severity === "recoverable") {
|
|
55816
|
-
|
|
55858
|
+
log12.warn(logMessage);
|
|
55817
55859
|
} else {
|
|
55818
|
-
|
|
55860
|
+
log12.error(logMessage, error instanceof Error ? error : undefined);
|
|
55819
55861
|
}
|
|
55820
55862
|
if (context.details) {
|
|
55821
|
-
|
|
55863
|
+
log12.debugJson("Error details", context.details);
|
|
55822
55864
|
}
|
|
55823
55865
|
if (context.notifyUser && context.session) {
|
|
55824
55866
|
try {
|
|
55825
55867
|
const fmt = context.session.platform.getFormatter();
|
|
55826
55868
|
await context.session.platform.createPost(`⚠️ ${fmt.formatBold("Error")}: ${context.action} failed - ${message}`, context.session.threadId);
|
|
55827
55869
|
} catch (notifyError) {
|
|
55828
|
-
|
|
55870
|
+
log12.warn(`Could not notify user: ${notifyError}`);
|
|
55829
55871
|
}
|
|
55830
55872
|
}
|
|
55831
55873
|
if (severity === "session-fatal" || severity === "system-fatal") {
|
|
@@ -55852,7 +55894,7 @@ async function logAndNotify(error, context) {
|
|
|
55852
55894
|
}
|
|
55853
55895
|
function logSilentError(context, error) {
|
|
55854
55896
|
const message = error instanceof Error ? error.message : String(error);
|
|
55855
|
-
|
|
55897
|
+
log12.debug(`[${context}] Silently caught: ${message}`);
|
|
55856
55898
|
}
|
|
55857
55899
|
|
|
55858
55900
|
// src/session/lifecycle.ts
|
|
@@ -55872,8 +55914,8 @@ function createSessionLog(baseLog) {
|
|
|
55872
55914
|
init_logger();
|
|
55873
55915
|
init_emoji();
|
|
55874
55916
|
init_worktree();
|
|
55875
|
-
var
|
|
55876
|
-
var sessionLog = createSessionLog(
|
|
55917
|
+
var log13 = createLogger("helpers");
|
|
55918
|
+
var sessionLog = createSessionLog(log13);
|
|
55877
55919
|
var POST_TYPES = {
|
|
55878
55920
|
info: "",
|
|
55879
55921
|
success: "✅",
|
|
@@ -55957,7 +55999,7 @@ function updateLastMessage(session, post2) {
|
|
|
55957
55999
|
// src/claude/quick-query.ts
|
|
55958
56000
|
init_spawn();
|
|
55959
56001
|
init_logger();
|
|
55960
|
-
var
|
|
56002
|
+
var log14 = createLogger("query");
|
|
55961
56003
|
async function quickQuery(options2) {
|
|
55962
56004
|
const {
|
|
55963
56005
|
prompt,
|
|
@@ -55973,7 +56015,7 @@ async function quickQuery(options2) {
|
|
|
55973
56015
|
args.push("--system-prompt", systemPrompt);
|
|
55974
56016
|
}
|
|
55975
56017
|
args.push(prompt);
|
|
55976
|
-
|
|
56018
|
+
log14.debug(`Quick query: model=${model}, timeout=${timeout}ms, prompt="${prompt.substring(0, 50)}..."`);
|
|
55977
56019
|
return new Promise((resolve5) => {
|
|
55978
56020
|
let stdout = "";
|
|
55979
56021
|
let stderr = "";
|
|
@@ -55987,7 +56029,7 @@ async function quickQuery(options2) {
|
|
|
55987
56029
|
if (!resolved) {
|
|
55988
56030
|
resolved = true;
|
|
55989
56031
|
proc.kill("SIGTERM");
|
|
55990
|
-
|
|
56032
|
+
log14.debug(`Quick query timed out after ${timeout}ms`);
|
|
55991
56033
|
resolve5({
|
|
55992
56034
|
success: false,
|
|
55993
56035
|
error: "timeout",
|
|
@@ -56005,7 +56047,7 @@ async function quickQuery(options2) {
|
|
|
56005
56047
|
if (!resolved) {
|
|
56006
56048
|
resolved = true;
|
|
56007
56049
|
clearTimeout(timeoutId);
|
|
56008
|
-
|
|
56050
|
+
log14.debug(`Quick query error: ${err.message}`);
|
|
56009
56051
|
resolve5({
|
|
56010
56052
|
success: false,
|
|
56011
56053
|
error: err.message,
|
|
@@ -56019,14 +56061,14 @@ async function quickQuery(options2) {
|
|
|
56019
56061
|
clearTimeout(timeoutId);
|
|
56020
56062
|
const durationMs = Date.now() - startTime;
|
|
56021
56063
|
if (code === 0 && stdout.trim()) {
|
|
56022
|
-
|
|
56064
|
+
log14.debug(`Quick query success: ${durationMs}ms, ${stdout.length} chars`);
|
|
56023
56065
|
resolve5({
|
|
56024
56066
|
success: true,
|
|
56025
56067
|
response: stdout.trim(),
|
|
56026
56068
|
durationMs
|
|
56027
56069
|
});
|
|
56028
56070
|
} else {
|
|
56029
|
-
|
|
56071
|
+
log14.debug(`Quick query failed: code=${code}, stderr=${stderr.substring(0, 100)}`);
|
|
56030
56072
|
resolve5({
|
|
56031
56073
|
success: false,
|
|
56032
56074
|
error: stderr || `exit code ${code}`,
|
|
@@ -56041,7 +56083,7 @@ async function quickQuery(options2) {
|
|
|
56041
56083
|
|
|
56042
56084
|
// src/operations/suggestions/title.ts
|
|
56043
56085
|
init_logger();
|
|
56044
|
-
var
|
|
56086
|
+
var log15 = createLogger("title");
|
|
56045
56087
|
var SUGGESTION_TIMEOUT = 15000;
|
|
56046
56088
|
var MIN_TITLE_LENGTH = 3;
|
|
56047
56089
|
var MAX_TITLE_LENGTH = 50;
|
|
@@ -56105,32 +56147,32 @@ function parseMetadata(response) {
|
|
|
56105
56147
|
const titleMatch = response.match(/TITLE:\s*(.+)/i);
|
|
56106
56148
|
const descMatch = response.match(/DESC:\s*(.+)/i);
|
|
56107
56149
|
if (!titleMatch || !descMatch) {
|
|
56108
|
-
|
|
56150
|
+
log15.debug("Failed to parse title/description from response");
|
|
56109
56151
|
return null;
|
|
56110
56152
|
}
|
|
56111
56153
|
let title = titleMatch[1].trim();
|
|
56112
56154
|
let description = descMatch[1].trim();
|
|
56113
56155
|
if (title.length < MIN_TITLE_LENGTH) {
|
|
56114
|
-
|
|
56156
|
+
log15.debug(`Title too short: ${title.length} chars`);
|
|
56115
56157
|
return null;
|
|
56116
56158
|
}
|
|
56117
56159
|
if (title.length > MAX_TITLE_LENGTH) {
|
|
56118
|
-
|
|
56160
|
+
log15.debug(`Title too long (${title.length} chars), truncating`);
|
|
56119
56161
|
title = truncateAtWord(title, MAX_TITLE_LENGTH);
|
|
56120
56162
|
}
|
|
56121
56163
|
if (description.length < MIN_DESC_LENGTH) {
|
|
56122
|
-
|
|
56164
|
+
log15.debug(`Description too short: ${description.length} chars`);
|
|
56123
56165
|
return null;
|
|
56124
56166
|
}
|
|
56125
56167
|
if (description.length > MAX_DESC_LENGTH) {
|
|
56126
|
-
|
|
56168
|
+
log15.debug(`Description too long (${description.length} chars), truncating`);
|
|
56127
56169
|
description = truncateAtWord(description, MAX_DESC_LENGTH);
|
|
56128
56170
|
}
|
|
56129
56171
|
return { title, description };
|
|
56130
56172
|
}
|
|
56131
56173
|
async function suggestSessionMetadata(context) {
|
|
56132
56174
|
const logContext = typeof context === "string" ? context.substring(0, 50) : context.originalTask.substring(0, 50);
|
|
56133
|
-
|
|
56175
|
+
log15.debug(`Suggesting title for: "${logContext}..."`);
|
|
56134
56176
|
try {
|
|
56135
56177
|
const result = await quickQuery({
|
|
56136
56178
|
prompt: buildTitlePrompt(context),
|
|
@@ -56138,23 +56180,23 @@ async function suggestSessionMetadata(context) {
|
|
|
56138
56180
|
timeout: SUGGESTION_TIMEOUT
|
|
56139
56181
|
});
|
|
56140
56182
|
if (!result.success || !result.response) {
|
|
56141
|
-
|
|
56183
|
+
log15.debug(`Title suggestion failed: ${result.error || "no response"}`);
|
|
56142
56184
|
return null;
|
|
56143
56185
|
}
|
|
56144
56186
|
const metadata = parseMetadata(result.response);
|
|
56145
56187
|
if (metadata) {
|
|
56146
|
-
|
|
56188
|
+
log15.debug(`Got title: "${metadata.title}" (${result.durationMs}ms)`);
|
|
56147
56189
|
}
|
|
56148
56190
|
return metadata;
|
|
56149
56191
|
} catch (err) {
|
|
56150
|
-
|
|
56192
|
+
log15.debug(`Title suggestion error: ${err}`);
|
|
56151
56193
|
return null;
|
|
56152
56194
|
}
|
|
56153
56195
|
}
|
|
56154
56196
|
|
|
56155
56197
|
// src/operations/suggestions/tag.ts
|
|
56156
56198
|
init_logger();
|
|
56157
|
-
var
|
|
56199
|
+
var log16 = createLogger("tags");
|
|
56158
56200
|
var SUGGESTION_TIMEOUT2 = 15000;
|
|
56159
56201
|
var MAX_TAGS = 3;
|
|
56160
56202
|
var VALID_TAGS = [
|
|
@@ -56186,7 +56228,7 @@ function parseTags(response) {
|
|
|
56186
56228
|
return [...new Set(tags)].slice(0, MAX_TAGS);
|
|
56187
56229
|
}
|
|
56188
56230
|
async function suggestSessionTags(userMessage) {
|
|
56189
|
-
|
|
56231
|
+
log16.debug(`Suggesting tags for: "${userMessage.substring(0, 50)}..."`);
|
|
56190
56232
|
try {
|
|
56191
56233
|
const result = await quickQuery({
|
|
56192
56234
|
prompt: buildTagPrompt(userMessage),
|
|
@@ -56194,14 +56236,14 @@ async function suggestSessionTags(userMessage) {
|
|
|
56194
56236
|
timeout: SUGGESTION_TIMEOUT2
|
|
56195
56237
|
});
|
|
56196
56238
|
if (!result.success || !result.response) {
|
|
56197
|
-
|
|
56239
|
+
log16.debug(`Tag suggestion failed: ${result.error || "no response"}`);
|
|
56198
56240
|
return [];
|
|
56199
56241
|
}
|
|
56200
56242
|
const tags = parseTags(result.response);
|
|
56201
|
-
|
|
56243
|
+
log16.debug(`Got tags: ${tags.join(", ")} (${result.durationMs}ms)`);
|
|
56202
56244
|
return tags;
|
|
56203
56245
|
} catch (err) {
|
|
56204
|
-
|
|
56246
|
+
log16.debug(`Tag suggestion error: ${err}`);
|
|
56205
56247
|
return [];
|
|
56206
56248
|
}
|
|
56207
56249
|
}
|
|
@@ -59721,7 +59763,7 @@ class BugReportExecutor extends BaseExecutor {
|
|
|
59721
59763
|
// src/operations/executors/worktree-prompt.ts
|
|
59722
59764
|
init_emoji();
|
|
59723
59765
|
init_logger();
|
|
59724
|
-
var
|
|
59766
|
+
var log17 = createLogger("wt-prompt");
|
|
59725
59767
|
// src/operations/message-manager.ts
|
|
59726
59768
|
init_logger();
|
|
59727
59769
|
|
|
@@ -59758,7 +59800,7 @@ var import_yauzl = __toESM(require_yauzl(), 1);
|
|
|
59758
59800
|
import { createGunzip } from "zlib";
|
|
59759
59801
|
import { pipeline } from "stream/promises";
|
|
59760
59802
|
import { Readable, Writable } from "stream";
|
|
59761
|
-
var
|
|
59803
|
+
var log18 = createLogger("streaming");
|
|
59762
59804
|
var MAX_PDF_SIZE = 32 * 1024 * 1024;
|
|
59763
59805
|
var MAX_TEXT_FILE_SIZE = 1 * 1024 * 1024;
|
|
59764
59806
|
var MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024;
|
|
@@ -59884,7 +59926,7 @@ async function processImageFile(file, platform, debug = false) {
|
|
|
59884
59926
|
const buffer = await platform.downloadFile(file.id);
|
|
59885
59927
|
const base64 = buffer.toString("base64");
|
|
59886
59928
|
if (debug) {
|
|
59887
|
-
|
|
59929
|
+
log18.debug(`Attached image: ${file.name} (${file.mimeType}, ${Math.round(buffer.length / 1024)}KB)`);
|
|
59888
59930
|
}
|
|
59889
59931
|
return {
|
|
59890
59932
|
block: {
|
|
@@ -59897,7 +59939,7 @@ async function processImageFile(file, platform, debug = false) {
|
|
|
59897
59939
|
}
|
|
59898
59940
|
};
|
|
59899
59941
|
} catch (err) {
|
|
59900
|
-
|
|
59942
|
+
log18.error(`Failed to download image ${file.name}: ${err}`);
|
|
59901
59943
|
return {
|
|
59902
59944
|
skipped: {
|
|
59903
59945
|
name: file.name,
|
|
@@ -59928,7 +59970,7 @@ async function processPdfFile(file, platform, debug = false) {
|
|
|
59928
59970
|
}
|
|
59929
59971
|
const base64 = buffer.toString("base64");
|
|
59930
59972
|
if (debug) {
|
|
59931
|
-
|
|
59973
|
+
log18.debug(`Attached PDF: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
|
|
59932
59974
|
}
|
|
59933
59975
|
return {
|
|
59934
59976
|
block: {
|
|
@@ -59942,7 +59984,7 @@ async function processPdfFile(file, platform, debug = false) {
|
|
|
59942
59984
|
}
|
|
59943
59985
|
};
|
|
59944
59986
|
} catch (err) {
|
|
59945
|
-
|
|
59987
|
+
log18.error(`Failed to process PDF ${file.name}: ${err}`);
|
|
59946
59988
|
return {
|
|
59947
59989
|
skipped: {
|
|
59948
59990
|
name: file.name,
|
|
@@ -59973,7 +60015,7 @@ async function processTextFile(file, platform, debug = false) {
|
|
|
59973
60015
|
}
|
|
59974
60016
|
const content = buffer.toString("utf-8");
|
|
59975
60017
|
if (debug) {
|
|
59976
|
-
|
|
60018
|
+
log18.debug(`Attached text file: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
|
|
59977
60019
|
}
|
|
59978
60020
|
const wrappedContent = formatTextFileContent(file.name, content);
|
|
59979
60021
|
return {
|
|
@@ -59983,7 +60025,7 @@ async function processTextFile(file, platform, debug = false) {
|
|
|
59983
60025
|
}
|
|
59984
60026
|
};
|
|
59985
60027
|
} catch (err) {
|
|
59986
|
-
|
|
60028
|
+
log18.error(`Failed to process text file ${file.name}: ${err}`);
|
|
59987
60029
|
return {
|
|
59988
60030
|
skipped: {
|
|
59989
60031
|
name: file.name,
|
|
@@ -60041,7 +60083,7 @@ async function processGzipFile(file, platform, debug = false) {
|
|
|
60041
60083
|
compressedBuffer = await platform.downloadFile(file.id);
|
|
60042
60084
|
} catch (err) {
|
|
60043
60085
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
60044
|
-
|
|
60086
|
+
log18.error(`Failed to download gzip file ${file.name}: ${errorMessage}`);
|
|
60045
60087
|
return {
|
|
60046
60088
|
skipped: {
|
|
60047
60089
|
name: file.name,
|
|
@@ -60051,7 +60093,7 @@ async function processGzipFile(file, platform, debug = false) {
|
|
|
60051
60093
|
};
|
|
60052
60094
|
}
|
|
60053
60095
|
if (file.size && compressedBuffer.length !== file.size) {
|
|
60054
|
-
|
|
60096
|
+
log18.warn(`Downloaded size mismatch for ${file.name}: expected ${file.size}, got ${compressedBuffer.length}`);
|
|
60055
60097
|
}
|
|
60056
60098
|
let decompressedBuffer;
|
|
60057
60099
|
try {
|
|
@@ -60087,7 +60129,7 @@ async function processGzipFile(file, platform, debug = false) {
|
|
|
60087
60129
|
const innerFilename = file.name.toLowerCase().endsWith(".gz") ? file.name.slice(0, -3) : file.name;
|
|
60088
60130
|
const contentType = detectDecompressedContentType(decompressedBuffer, innerFilename);
|
|
60089
60131
|
if (debug) {
|
|
60090
|
-
|
|
60132
|
+
log18.debug(`Decompressed ${file.name}: ${Math.round(decompressedBuffer.length / 1024)}KB, detected type: ${contentType}`);
|
|
60091
60133
|
}
|
|
60092
60134
|
if (contentType === "pdf") {
|
|
60093
60135
|
const base64 = decompressedBuffer.toString("base64");
|
|
@@ -60122,7 +60164,7 @@ async function processGzipFile(file, platform, debug = false) {
|
|
|
60122
60164
|
}
|
|
60123
60165
|
} catch (err) {
|
|
60124
60166
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
60125
|
-
|
|
60167
|
+
log18.error(`Failed to process gzip file ${file.name}: ${errorMessage}`);
|
|
60126
60168
|
return {
|
|
60127
60169
|
skipped: {
|
|
60128
60170
|
name: file.name,
|
|
@@ -60174,7 +60216,7 @@ async function processZipFile(file, platform, debug = false) {
|
|
|
60174
60216
|
}
|
|
60175
60217
|
const zipBuffer = await platform.downloadFile(file.id);
|
|
60176
60218
|
if (debug) {
|
|
60177
|
-
|
|
60219
|
+
log18.debug(`Processing zip file ${file.name}: ${Math.round(zipBuffer.length / 1024)}KB`);
|
|
60178
60220
|
}
|
|
60179
60221
|
const zipfile = await new Promise((resolve5, reject) => {
|
|
60180
60222
|
import_yauzl.default.fromBuffer(zipBuffer, { lazyEntries: true }, (err, zf) => {
|
|
@@ -60248,7 +60290,7 @@ async function processZipFile(file, platform, debug = false) {
|
|
|
60248
60290
|
const buffer = await extractZipEntry(zipfile2, entry);
|
|
60249
60291
|
const contentType = detectDecompressedContentType(buffer, entry.fileName);
|
|
60250
60292
|
if (debug) {
|
|
60251
|
-
|
|
60293
|
+
log18.debug(`Extracted ${entry.fileName}: ${Math.round(buffer.length / 1024)}KB, type: ${contentType}`);
|
|
60252
60294
|
}
|
|
60253
60295
|
if (contentType === "pdf") {
|
|
60254
60296
|
const base64 = buffer.toString("base64");
|
|
@@ -60291,11 +60333,11 @@ async function processZipFile(file, platform, debug = false) {
|
|
|
60291
60333
|
});
|
|
60292
60334
|
zipfile2.close();
|
|
60293
60335
|
if (debug) {
|
|
60294
|
-
|
|
60336
|
+
log18.debug(`Zip ${file.name}: processed ${processedCount} files, skipped ${skipped.length}`);
|
|
60295
60337
|
}
|
|
60296
60338
|
return { blocks, skipped };
|
|
60297
60339
|
} catch (err) {
|
|
60298
|
-
|
|
60340
|
+
log18.error(`Failed to process zip file ${file.name}: ${err}`);
|
|
60299
60341
|
return {
|
|
60300
60342
|
blocks: [],
|
|
60301
60343
|
skipped: [{
|
|
@@ -60392,7 +60434,7 @@ async function processFiles(platform, files, debug = false) {
|
|
|
60392
60434
|
blocks.push(...zipResult.blocks);
|
|
60393
60435
|
for (const s of zipResult.skipped) {
|
|
60394
60436
|
skipped.push(s);
|
|
60395
|
-
|
|
60437
|
+
log18.warn(`Skipped file ${s.name}: ${s.reason}`);
|
|
60396
60438
|
}
|
|
60397
60439
|
continue;
|
|
60398
60440
|
}
|
|
@@ -60426,7 +60468,7 @@ async function processFiles(platform, files, debug = false) {
|
|
|
60426
60468
|
}
|
|
60427
60469
|
if (result.skipped) {
|
|
60428
60470
|
skipped.push(result.skipped);
|
|
60429
|
-
|
|
60471
|
+
log18.warn(`Skipped file ${result.skipped.name}: ${result.skipped.reason}`);
|
|
60430
60472
|
}
|
|
60431
60473
|
}
|
|
60432
60474
|
return { blocks, skipped };
|
|
@@ -60459,7 +60501,7 @@ function stopTyping(session) {
|
|
|
60459
60501
|
}
|
|
60460
60502
|
|
|
60461
60503
|
// src/operations/message-manager.ts
|
|
60462
|
-
var
|
|
60504
|
+
var log19 = createLogger("msg-mgr");
|
|
60463
60505
|
|
|
60464
60506
|
class MessageManager {
|
|
60465
60507
|
platform;
|
|
@@ -60549,7 +60591,7 @@ class MessageManager {
|
|
|
60549
60591
|
});
|
|
60550
60592
|
}
|
|
60551
60593
|
async handleEvent(event) {
|
|
60552
|
-
const logger =
|
|
60594
|
+
const logger = log19.forSession(this.sessionId);
|
|
60553
60595
|
const transformCtx = {
|
|
60554
60596
|
sessionId: this.sessionId,
|
|
60555
60597
|
formatter: this.platform.getFormatter(),
|
|
@@ -60599,7 +60641,7 @@ class MessageManager {
|
|
|
60599
60641
|
}
|
|
60600
60642
|
}
|
|
60601
60643
|
async executeOperation(op) {
|
|
60602
|
-
const logger =
|
|
60644
|
+
const logger = log19.forSession(this.sessionId);
|
|
60603
60645
|
const ctx = this.getExecutorContext();
|
|
60604
60646
|
try {
|
|
60605
60647
|
if (isContentOp(op)) {
|
|
@@ -60667,7 +60709,7 @@ class MessageManager {
|
|
|
60667
60709
|
threadId: this.threadId,
|
|
60668
60710
|
platform: this.platform,
|
|
60669
60711
|
formatter: this.platform.getFormatter(),
|
|
60670
|
-
logger:
|
|
60712
|
+
logger: log19.forSession(this.sessionId),
|
|
60671
60713
|
postTracker: this.postTracker,
|
|
60672
60714
|
contentBreaker: this.contentBreaker,
|
|
60673
60715
|
threadLogger: this.session.threadLogger,
|
|
@@ -60878,13 +60920,13 @@ class MessageManager {
|
|
|
60878
60920
|
return this.systemExecutor.postSuccess(message, this.getExecutorContext());
|
|
60879
60921
|
}
|
|
60880
60922
|
async prepareForUserMessage() {
|
|
60881
|
-
const logger =
|
|
60923
|
+
const logger = log19.forSession(this.sessionId);
|
|
60882
60924
|
logger.debug("Preparing for new user message");
|
|
60883
60925
|
await this.closeCurrentPost();
|
|
60884
60926
|
await this.bumpTaskList();
|
|
60885
60927
|
}
|
|
60886
60928
|
async handleUserMessage(message, files, username, displayName) {
|
|
60887
|
-
const logger =
|
|
60929
|
+
const logger = log19.forSession(this.sessionId);
|
|
60888
60930
|
if (!this.session.claude.isRunning()) {
|
|
60889
60931
|
logger.debug("Claude not running, ignoring user message");
|
|
60890
60932
|
return false;
|
|
@@ -60921,7 +60963,7 @@ class MessageManager {
|
|
|
60921
60963
|
];
|
|
60922
60964
|
}
|
|
60923
60965
|
async handleReaction(postId, emoji, user, action) {
|
|
60924
|
-
const logger =
|
|
60966
|
+
const logger = log19.forSession(this.sessionId);
|
|
60925
60967
|
const ctx = this.getExecutorContext();
|
|
60926
60968
|
logger.debug(`Routing reaction: postId=${postId}, emoji=${emoji}, user=${user}, action=${action}`);
|
|
60927
60969
|
for (const { name, executor } of this.reactionDispatchList()) {
|
|
@@ -60949,6 +60991,7 @@ class MessageManager {
|
|
|
60949
60991
|
}
|
|
60950
60992
|
dispose() {
|
|
60951
60993
|
this.cancelScheduledFlush();
|
|
60994
|
+
this.postTracker.clearSession(this.sessionId);
|
|
60952
60995
|
this.reset();
|
|
60953
60996
|
}
|
|
60954
60997
|
}
|
|
@@ -61101,7 +61144,7 @@ function formatPullRequestLink(url, formatter) {
|
|
|
61101
61144
|
}
|
|
61102
61145
|
|
|
61103
61146
|
// src/operations/sticky-message/handler.ts
|
|
61104
|
-
var
|
|
61147
|
+
var log20 = createLogger("sticky");
|
|
61105
61148
|
var botStartedAt = new Date;
|
|
61106
61149
|
function getPendingPrompts(session) {
|
|
61107
61150
|
const prompts2 = [];
|
|
@@ -61176,21 +61219,21 @@ function initialize(store) {
|
|
|
61176
61219
|
stickyPostIds.set(platformId, postId);
|
|
61177
61220
|
}
|
|
61178
61221
|
if (persistedIds.size > 0) {
|
|
61179
|
-
|
|
61222
|
+
log20.info(`\uD83D\uDCCC Restored ${persistedIds.size} sticky post ID(s) from persistence`);
|
|
61180
61223
|
}
|
|
61181
61224
|
}
|
|
61182
61225
|
function setPlatformPaused(platformId, paused) {
|
|
61183
61226
|
if (paused) {
|
|
61184
61227
|
pausedPlatforms.set(platformId, true);
|
|
61185
|
-
|
|
61228
|
+
log20.debug(`Platform ${platformId} marked as paused`);
|
|
61186
61229
|
} else {
|
|
61187
61230
|
pausedPlatforms.delete(platformId);
|
|
61188
|
-
|
|
61231
|
+
log20.debug(`Platform ${platformId} marked as active`);
|
|
61189
61232
|
}
|
|
61190
61233
|
}
|
|
61191
61234
|
function setShuttingDown(shuttingDown) {
|
|
61192
61235
|
isShuttingDown = shuttingDown;
|
|
61193
|
-
|
|
61236
|
+
log20.debug(`Bot shutdown state: ${shuttingDown}`);
|
|
61194
61237
|
}
|
|
61195
61238
|
function getTaskContent(session) {
|
|
61196
61239
|
const taskState = session.messageManager?.getTaskListState();
|
|
@@ -61501,12 +61544,12 @@ async function validateLastMessageIds(platform, sessions) {
|
|
|
61501
61544
|
try {
|
|
61502
61545
|
const post2 = await platform.getPost(lastMessageId);
|
|
61503
61546
|
if (!post2) {
|
|
61504
|
-
|
|
61547
|
+
log20.debug(`lastMessageId ${lastMessageId.substring(0, 8)} for session ${session.sessionId} was deleted, clearing`);
|
|
61505
61548
|
session.lastMessageId = undefined;
|
|
61506
61549
|
session.lastMessageTs = undefined;
|
|
61507
61550
|
}
|
|
61508
61551
|
} catch (err) {
|
|
61509
|
-
|
|
61552
|
+
log20.debug(`Failed to validate lastMessageId for session ${session.sessionId}, clearing: ${err}`);
|
|
61510
61553
|
session.lastMessageId = undefined;
|
|
61511
61554
|
session.lastMessageTs = undefined;
|
|
61512
61555
|
}
|
|
@@ -61515,63 +61558,63 @@ async function validateLastMessageIds(platform, sessions) {
|
|
|
61515
61558
|
}
|
|
61516
61559
|
async function updateStickyMessageImpl(platform, sessions, config) {
|
|
61517
61560
|
const platformSessions = [...sessions.values()].filter((s) => s.platformId === platform.platformId);
|
|
61518
|
-
|
|
61561
|
+
log20.debug(`updateStickyMessage for ${platform.platformId}, ${platformSessions.length} sessions`);
|
|
61519
61562
|
for (const s of platformSessions) {
|
|
61520
|
-
|
|
61563
|
+
log20.debug(` - ${s.sessionId}: title="${s.sessionTitle}" firstPrompt="${s.firstPrompt?.substring(0, 30)}..."`);
|
|
61521
61564
|
}
|
|
61522
61565
|
await validateLastMessageIds(platform, platformSessions);
|
|
61523
61566
|
const formatter = platform.getFormatter();
|
|
61524
61567
|
const content = await buildStickyMessage(sessions, platform.platformId, config, formatter, (threadId) => platform.getThreadLink(threadId));
|
|
61525
61568
|
const existingPostId = stickyPostIds.get(platform.platformId);
|
|
61526
61569
|
const shouldBump = needsBump.get(platform.platformId) ?? false;
|
|
61527
|
-
|
|
61570
|
+
log20.debug(`existingPostId: ${existingPostId || "(none)"}, needsBump: ${shouldBump}`);
|
|
61528
61571
|
try {
|
|
61529
61572
|
if (existingPostId && !shouldBump) {
|
|
61530
|
-
|
|
61573
|
+
log20.debug(`Updating existing post in place...`);
|
|
61531
61574
|
try {
|
|
61532
61575
|
await platform.updatePost(existingPostId, content);
|
|
61533
61576
|
try {
|
|
61534
61577
|
await platform.pinPost(existingPostId);
|
|
61535
|
-
|
|
61578
|
+
log20.debug(`Re-pinned post`);
|
|
61536
61579
|
} catch (pinErr) {
|
|
61537
|
-
|
|
61580
|
+
log20.debug(`Re-pin failed (might already be pinned): ${pinErr}`);
|
|
61538
61581
|
}
|
|
61539
|
-
|
|
61582
|
+
log20.debug(`Updated successfully`);
|
|
61540
61583
|
return;
|
|
61541
61584
|
} catch (err) {
|
|
61542
|
-
|
|
61585
|
+
log20.debug(`Update failed, will create new: ${err}`);
|
|
61543
61586
|
}
|
|
61544
61587
|
}
|
|
61545
61588
|
needsBump.set(platform.platformId, false);
|
|
61546
61589
|
if (existingPostId) {
|
|
61547
|
-
|
|
61590
|
+
log20.debug(`Unpinning and deleting existing post ${existingPostId.substring(0, 8)}...`);
|
|
61548
61591
|
try {
|
|
61549
61592
|
await platform.unpinPost(existingPostId);
|
|
61550
|
-
|
|
61593
|
+
log20.debug(`Unpinned successfully`);
|
|
61551
61594
|
} catch (err) {
|
|
61552
|
-
|
|
61595
|
+
log20.debug(`Unpin failed (probably already unpinned): ${err}`);
|
|
61553
61596
|
}
|
|
61554
61597
|
try {
|
|
61555
61598
|
await platform.deletePost(existingPostId);
|
|
61556
|
-
|
|
61599
|
+
log20.debug(`Deleted successfully`);
|
|
61557
61600
|
} catch (err) {
|
|
61558
|
-
|
|
61601
|
+
log20.debug(`Delete failed (probably already deleted): ${err}`);
|
|
61559
61602
|
}
|
|
61560
61603
|
stickyPostIds.delete(platform.platformId);
|
|
61561
61604
|
}
|
|
61562
|
-
|
|
61605
|
+
log20.debug(`Creating new post...`);
|
|
61563
61606
|
const post2 = await platform.createPost(content);
|
|
61564
61607
|
stickyPostIds.set(platform.platformId, post2.id);
|
|
61565
61608
|
try {
|
|
61566
61609
|
await platform.pinPost(post2.id);
|
|
61567
|
-
|
|
61610
|
+
log20.debug(`Pinned post successfully`);
|
|
61568
61611
|
} catch (err) {
|
|
61569
|
-
|
|
61612
|
+
log20.debug(`Failed to pin post: ${err}`);
|
|
61570
61613
|
}
|
|
61571
61614
|
if (sessionStore) {
|
|
61572
61615
|
sessionStore.saveStickyPostId(platform.platformId, post2.id);
|
|
61573
61616
|
}
|
|
61574
|
-
|
|
61617
|
+
log20.info(`\uD83D\uDCCC Created sticky message for ${platform.platformId}: ${formatShortId(post2.id)}`);
|
|
61575
61618
|
const excludePostIds = new Set;
|
|
61576
61619
|
if (sessionStore) {
|
|
61577
61620
|
for (const session of sessionStore.load().values()) {
|
|
@@ -61587,10 +61630,10 @@ async function updateStickyMessageImpl(platform, sessions, config) {
|
|
|
61587
61630
|
}
|
|
61588
61631
|
const botUser = await platform.getBotUser();
|
|
61589
61632
|
cleanupOldStickyMessages(platform, botUser.id, false, excludePostIds).catch((err) => {
|
|
61590
|
-
|
|
61633
|
+
log20.debug(`Background cleanup failed: ${err}`);
|
|
61591
61634
|
});
|
|
61592
61635
|
} catch (err) {
|
|
61593
|
-
|
|
61636
|
+
log20.error(`Failed to update sticky message for ${platform.platformId}`, err instanceof Error ? err : undefined);
|
|
61594
61637
|
}
|
|
61595
61638
|
}
|
|
61596
61639
|
async function updateAllStickyMessages(platforms, sessions, config) {
|
|
@@ -61615,7 +61658,7 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
|
|
|
61615
61658
|
if (!forceRun) {
|
|
61616
61659
|
const lastRun = lastCleanupTime.get(platformId) || 0;
|
|
61617
61660
|
if (now - lastRun < CLEANUP_THROTTLE_MS) {
|
|
61618
|
-
|
|
61661
|
+
log20.debug(`Cleanup throttled for ${platformId} (last run ${Math.round((now - lastRun) / 1000)}s ago)`);
|
|
61619
61662
|
return;
|
|
61620
61663
|
}
|
|
61621
61664
|
}
|
|
@@ -61625,31 +61668,31 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
|
|
|
61625
61668
|
const pinnedPostIds = await platform.getPinnedPosts();
|
|
61626
61669
|
const recentPinnedIds = pinnedPostIds.filter((id) => id !== currentStickyId && !excludePostIds?.has(id) && isRecentPost(id));
|
|
61627
61670
|
if (recentPinnedIds.length === 0) {
|
|
61628
|
-
|
|
61671
|
+
log20.debug(`No recent pinned posts to check (${pinnedPostIds.length} total, current: ${currentStickyId?.substring(0, 8) || "(none)"})`);
|
|
61629
61672
|
return;
|
|
61630
61673
|
}
|
|
61631
|
-
|
|
61674
|
+
log20.debug(`Checking ${recentPinnedIds.length} recent pinned posts (of ${pinnedPostIds.length} total)`);
|
|
61632
61675
|
for (const postId of recentPinnedIds) {
|
|
61633
61676
|
try {
|
|
61634
61677
|
const post2 = await platform.getPost(postId);
|
|
61635
61678
|
if (!post2)
|
|
61636
61679
|
continue;
|
|
61637
61680
|
if (post2.userId === botUserId) {
|
|
61638
|
-
|
|
61681
|
+
log20.debug(`Cleaning up old sticky: ${postId.substring(0, 8)}...`);
|
|
61639
61682
|
try {
|
|
61640
61683
|
await platform.unpinPost(postId);
|
|
61641
61684
|
await platform.deletePost(postId);
|
|
61642
|
-
|
|
61685
|
+
log20.info(`\uD83E\uDDF9 Cleaned up old sticky message: ${postId.substring(0, 8)}...`);
|
|
61643
61686
|
} catch (err) {
|
|
61644
|
-
|
|
61687
|
+
log20.debug(`Failed to cleanup ${postId}: ${err}`);
|
|
61645
61688
|
}
|
|
61646
61689
|
}
|
|
61647
61690
|
} catch (err) {
|
|
61648
|
-
|
|
61691
|
+
log20.debug(`Could not check post ${postId}: ${err}`);
|
|
61649
61692
|
}
|
|
61650
61693
|
}
|
|
61651
61694
|
} catch (err) {
|
|
61652
|
-
|
|
61695
|
+
log20.error(`Failed to cleanup old sticky messages`, err instanceof Error ? err : undefined);
|
|
61653
61696
|
}
|
|
61654
61697
|
}
|
|
61655
61698
|
// src/operations/bug-report/handler.ts
|
|
@@ -65712,8 +65755,8 @@ function getUpdateInfo() {
|
|
|
65712
65755
|
init_emoji();
|
|
65713
65756
|
init_logger();
|
|
65714
65757
|
init_worktree();
|
|
65715
|
-
var
|
|
65716
|
-
var sessionLog2 = createSessionLog(
|
|
65758
|
+
var log21 = createLogger("commands");
|
|
65759
|
+
var sessionLog2 = createSessionLog(log21);
|
|
65717
65760
|
function sessionAccountOption(session, ctx) {
|
|
65718
65761
|
if (!session.claudeAccountId)
|
|
65719
65762
|
return;
|
|
@@ -66247,7 +66290,7 @@ init_logger();
|
|
|
66247
66290
|
import { exec as exec3 } from "child_process";
|
|
66248
66291
|
import { promisify as promisify3 } from "util";
|
|
66249
66292
|
var execAsync2 = promisify3(exec3);
|
|
66250
|
-
var
|
|
66293
|
+
var log22 = createLogger("branch");
|
|
66251
66294
|
var SUGGESTION_TIMEOUT3 = 15000;
|
|
66252
66295
|
var MAX_SUGGESTIONS = 3;
|
|
66253
66296
|
async function getCurrentBranch3(workingDir) {
|
|
@@ -66296,7 +66339,7 @@ function parseBranchSuggestions(response) {
|
|
|
66296
66339
|
return lines.slice(0, MAX_SUGGESTIONS);
|
|
66297
66340
|
}
|
|
66298
66341
|
async function suggestBranchNames(workingDir, userMessage) {
|
|
66299
|
-
|
|
66342
|
+
log22.debug(`Suggesting branch names for: "${userMessage.substring(0, 50)}..."`);
|
|
66300
66343
|
try {
|
|
66301
66344
|
const [currentBranch, recentCommits] = await Promise.all([
|
|
66302
66345
|
getCurrentBranch3(workingDir),
|
|
@@ -66310,14 +66353,14 @@ async function suggestBranchNames(workingDir, userMessage) {
|
|
|
66310
66353
|
workingDir
|
|
66311
66354
|
});
|
|
66312
66355
|
if (!result.success || !result.response) {
|
|
66313
|
-
|
|
66356
|
+
log22.debug(`Branch suggestion failed: ${result.error || "no response"}`);
|
|
66314
66357
|
return [];
|
|
66315
66358
|
}
|
|
66316
66359
|
const suggestions = parseBranchSuggestions(result.response);
|
|
66317
|
-
|
|
66360
|
+
log22.debug(`Got ${suggestions.length} branch suggestions: ${suggestions.join(", ")}`);
|
|
66318
66361
|
return suggestions;
|
|
66319
66362
|
} catch (err) {
|
|
66320
|
-
|
|
66363
|
+
log22.debug(`Branch suggestion error: ${err}`);
|
|
66321
66364
|
return [];
|
|
66322
66365
|
}
|
|
66323
66366
|
}
|
|
@@ -66326,8 +66369,8 @@ async function suggestBranchNames(workingDir, userMessage) {
|
|
|
66326
66369
|
init_worktree();
|
|
66327
66370
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
66328
66371
|
init_logger();
|
|
66329
|
-
var
|
|
66330
|
-
var sessionLog3 = createSessionLog(
|
|
66372
|
+
var log23 = createLogger("worktree");
|
|
66373
|
+
var sessionLog3 = createSessionLog(log23);
|
|
66331
66374
|
function parseWorktreeError(error) {
|
|
66332
66375
|
const message = error instanceof Error ? error.message : String(error);
|
|
66333
66376
|
const lowerMessage = message.toLowerCase();
|
|
@@ -66895,8 +66938,8 @@ async function cleanupWorktreeCommand(session, username, hasOtherSessionsUsingWo
|
|
|
66895
66938
|
}
|
|
66896
66939
|
// src/operations/events/handler.ts
|
|
66897
66940
|
init_logger();
|
|
66898
|
-
var
|
|
66899
|
-
var sessionLog4 = createSessionLog(
|
|
66941
|
+
var log24 = createLogger("events");
|
|
66942
|
+
var sessionLog4 = createSessionLog(log24);
|
|
66900
66943
|
function detectAndExecuteClaudeCommands(text, session, ctx) {
|
|
66901
66944
|
const parsed = parseClaudeCommand(text);
|
|
66902
66945
|
if (parsed && isClaudeAllowedCommand(parsed.command)) {
|
|
@@ -67144,8 +67187,8 @@ function createSessionContext(config, state, ops) {
|
|
|
67144
67187
|
// src/operations/context-prompt/handler.ts
|
|
67145
67188
|
init_emoji();
|
|
67146
67189
|
init_logger();
|
|
67147
|
-
var
|
|
67148
|
-
var sessionLog5 = createSessionLog(
|
|
67190
|
+
var log25 = createLogger("context");
|
|
67191
|
+
var sessionLog5 = createSessionLog(log25);
|
|
67149
67192
|
var CONTEXT_PROMPT_TIMEOUT_MS = 30000;
|
|
67150
67193
|
var CONTEXT_OPTIONS = [3, 5, 10];
|
|
67151
67194
|
var contextPromptTimeouts = new Map;
|
|
@@ -67395,8 +67438,8 @@ function formatRelativeTime(date) {
|
|
|
67395
67438
|
}
|
|
67396
67439
|
// src/session/lifecycle.ts
|
|
67397
67440
|
init_worktree();
|
|
67398
|
-
var
|
|
67399
|
-
var sessionLog6 = createSessionLog(
|
|
67441
|
+
var log26 = createLogger("lifecycle");
|
|
67442
|
+
var sessionLog6 = createSessionLog(log26);
|
|
67400
67443
|
function mutableSessions(ctx) {
|
|
67401
67444
|
return ctx.state.sessions;
|
|
67402
67445
|
}
|
|
@@ -67443,6 +67486,7 @@ async function cleanupSession(session, ctx, options2 = {}) {
|
|
|
67443
67486
|
if (doCloseLogger) {
|
|
67444
67487
|
await closeThreadLogger(session, action, details);
|
|
67445
67488
|
}
|
|
67489
|
+
session.messageManager?.dispose();
|
|
67446
67490
|
ctx.ops.emitSessionRemove(session.sessionId);
|
|
67447
67491
|
mutableSessions(ctx).delete(session.sessionId);
|
|
67448
67492
|
if (doCleanupPostIndex) {
|
|
@@ -67458,6 +67502,7 @@ function releaseAccountIfHeld(session, ctx) {
|
|
|
67458
67502
|
}
|
|
67459
67503
|
}
|
|
67460
67504
|
function removeFromRegistry(session, ctx) {
|
|
67505
|
+
session.messageManager?.dispose();
|
|
67461
67506
|
ctx.ops.emitSessionRemove(session.sessionId);
|
|
67462
67507
|
mutableSessions(ctx).delete(session.sessionId);
|
|
67463
67508
|
cleanupPostIndex(ctx, session.threadId);
|
|
@@ -67781,17 +67826,17 @@ async function startSession(options2, username, displayName, replyToPostId, plat
|
|
|
67781
67826
|
return;
|
|
67782
67827
|
}
|
|
67783
67828
|
workingDir = resolvedDir;
|
|
67784
|
-
|
|
67829
|
+
log26.info(`Starting session in directory: ${workingDir} (from !cd command)`);
|
|
67785
67830
|
}
|
|
67786
67831
|
if (initialOptions?.permissionMode) {
|
|
67787
67832
|
permissionMode = initialOptions.permissionMode;
|
|
67788
67833
|
forceInteractivePermissions = permissionMode === "default";
|
|
67789
67834
|
sessionPermissionModeOverride = permissionMode;
|
|
67790
|
-
|
|
67835
|
+
log26.info(`Starting session with permission mode "${permissionMode}" (from !permissions command)`);
|
|
67791
67836
|
} else if (initialOptions?.forceInteractivePermissions) {
|
|
67792
67837
|
forceInteractivePermissions = true;
|
|
67793
67838
|
permissionMode = "default";
|
|
67794
|
-
|
|
67839
|
+
log26.info(`Starting session with interactive permissions (from !permissions command)`);
|
|
67795
67840
|
}
|
|
67796
67841
|
const sessionContext = buildSessionContext(platform, workingDir);
|
|
67797
67842
|
const systemPrompt = `${sessionContext}
|
|
@@ -67800,7 +67845,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
67800
67845
|
const platformMcpConfig = platform.getMcpConfig();
|
|
67801
67846
|
const claudeAccount = ctx.ops.acquireClaudeAccount();
|
|
67802
67847
|
if (claudeAccount) {
|
|
67803
|
-
|
|
67848
|
+
log26.info(`Session ${sessionId.substring(0, 20)} reserved Claude account "${claudeAccount.id}"`);
|
|
67804
67849
|
}
|
|
67805
67850
|
const cliOptions = {
|
|
67806
67851
|
workingDir,
|
|
@@ -67869,6 +67914,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
67869
67914
|
} catch (err) {
|
|
67870
67915
|
await logAndNotify(err, { action: "Start Claude", session });
|
|
67871
67916
|
ctx.ops.stopTyping(session);
|
|
67917
|
+
session.messageManager?.dispose();
|
|
67872
67918
|
ctx.ops.emitSessionRemove(session.sessionId);
|
|
67873
67919
|
mutableSessions(ctx).delete(session.sessionId);
|
|
67874
67920
|
releaseAccountIfHeld(session, ctx);
|
|
@@ -67905,28 +67951,28 @@ async function resumeSession(state, ctx) {
|
|
|
67905
67951
|
!state.claudeSessionId && "claudeSessionId",
|
|
67906
67952
|
!state.workingDir && "workingDir"
|
|
67907
67953
|
].filter(Boolean).join(", ");
|
|
67908
|
-
|
|
67954
|
+
log26.warn(`Skipping session with missing required fields: ${missing}`);
|
|
67909
67955
|
return;
|
|
67910
67956
|
}
|
|
67911
67957
|
const shortId = state.threadId.substring(0, 8);
|
|
67912
67958
|
const platforms = ctx.state.platforms;
|
|
67913
67959
|
const platform = platforms.get(state.platformId);
|
|
67914
67960
|
if (!platform) {
|
|
67915
|
-
|
|
67961
|
+
log26.warn(`Platform ${state.platformId} not registered, skipping resume for ${shortId}...`);
|
|
67916
67962
|
return;
|
|
67917
67963
|
}
|
|
67918
67964
|
const threadPost = await platform.getPost(state.threadId);
|
|
67919
67965
|
if (!threadPost) {
|
|
67920
|
-
|
|
67966
|
+
log26.warn(`Thread ${shortId}... deleted, skipping resume`);
|
|
67921
67967
|
ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
|
|
67922
67968
|
return;
|
|
67923
67969
|
}
|
|
67924
67970
|
if (ctx.state.sessions.size >= ctx.config.maxSessions) {
|
|
67925
|
-
|
|
67971
|
+
log26.warn(`Max sessions reached, skipping resume for ${shortId}...`);
|
|
67926
67972
|
return;
|
|
67927
67973
|
}
|
|
67928
67974
|
if (!existsSync11(state.workingDir)) {
|
|
67929
|
-
|
|
67975
|
+
log26.warn(`Working directory ${state.workingDir} no longer exists, skipping resume for ${shortId}...`);
|
|
67930
67976
|
ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
|
|
67931
67977
|
const resumeFormatter = platform.getFormatter();
|
|
67932
67978
|
const tempSession = {
|
|
@@ -67950,7 +67996,7 @@ Please start a new session.`), { action: "Post resume failure notification" });
|
|
|
67950
67996
|
${CHAT_PLATFORM_PROMPT}`;
|
|
67951
67997
|
const claudeAccount = ctx.ops.acquireClaudeAccount(state.claudeAccountId);
|
|
67952
67998
|
if (state.claudeAccountId && !claudeAccount) {
|
|
67953
|
-
|
|
67999
|
+
log26.warn(`Persisted session referenced Claude account "${state.claudeAccountId}" ` + `which is no longer configured — resuming under default env`);
|
|
67954
68000
|
}
|
|
67955
68001
|
const cliOptions = {
|
|
67956
68002
|
workingDir: state.workingDir,
|
|
@@ -68015,7 +68061,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
68015
68061
|
worktreePath: detected.worktreePath,
|
|
68016
68062
|
branch: detected.branch
|
|
68017
68063
|
};
|
|
68018
|
-
|
|
68064
|
+
log26.info(`Auto-detected worktree info for resumed session: branch=${detected.branch}`);
|
|
68019
68065
|
}
|
|
68020
68066
|
}
|
|
68021
68067
|
session.messageManager = createMessageManager(session, ctx);
|
|
@@ -68071,7 +68117,8 @@ ${sessionFormatter.formatItalic("Reconnected to Claude session. You can continue
|
|
|
68071
68117
|
await ctx.ops.updateStickyMessage();
|
|
68072
68118
|
ctx.ops.persistSession(session);
|
|
68073
68119
|
} catch (err) {
|
|
68074
|
-
|
|
68120
|
+
log26.error(`Failed to resume session ${shortId}`, err instanceof Error ? err : undefined);
|
|
68121
|
+
session.messageManager?.dispose();
|
|
68075
68122
|
ctx.ops.emitSessionRemove(sessionId);
|
|
68076
68123
|
mutableSessions(ctx).delete(sessionId);
|
|
68077
68124
|
ctx.state.sessionStore.remove(sessionId);
|
|
@@ -68111,18 +68158,18 @@ async function resumePausedSession(threadId, message, files, ctx) {
|
|
|
68111
68158
|
const persisted = ctx.state.sessionStore.load();
|
|
68112
68159
|
const state = findPersistedByThreadId(persisted, threadId);
|
|
68113
68160
|
if (!state) {
|
|
68114
|
-
|
|
68161
|
+
log26.debug(`No persisted session found for ${threadId.substring(0, 8)}...`);
|
|
68115
68162
|
return;
|
|
68116
68163
|
}
|
|
68117
68164
|
const shortId = threadId.substring(0, 8);
|
|
68118
|
-
|
|
68165
|
+
log26.info(`\uD83D\uDD04 Resuming paused session ${shortId}... for new message`);
|
|
68119
68166
|
await resumeSession(state, ctx);
|
|
68120
68167
|
const session = ctx.ops.findSessionByThreadId(threadId);
|
|
68121
68168
|
if (session && session.claude.isRunning() && session.messageManager) {
|
|
68122
68169
|
session.messageCount++;
|
|
68123
68170
|
await session.messageManager.handleUserMessage(message, files, state.startedBy);
|
|
68124
68171
|
} else {
|
|
68125
|
-
|
|
68172
|
+
log26.warn(`Failed to resume session ${shortId}..., could not send message`);
|
|
68126
68173
|
}
|
|
68127
68174
|
}
|
|
68128
68175
|
async function handleExit(sessionId, code, ctx) {
|
|
@@ -68130,7 +68177,7 @@ async function handleExit(sessionId, code, ctx) {
|
|
|
68130
68177
|
const shortId = sessionId.substring(0, 8);
|
|
68131
68178
|
sessionLog6(session).debug(`handleExit called code=${code} isShuttingDown=${ctx.state.isShuttingDown}`);
|
|
68132
68179
|
if (!session) {
|
|
68133
|
-
|
|
68180
|
+
log26.debug(`Session ${shortId}... not found (already cleaned up)`);
|
|
68134
68181
|
return;
|
|
68135
68182
|
}
|
|
68136
68183
|
if (isSessionRestarting(session)) {
|
|
@@ -68323,7 +68370,7 @@ async function cleanupIdleSessions(timeoutMs, warningMs, ctx) {
|
|
|
68323
68370
|
}
|
|
68324
68371
|
|
|
68325
68372
|
// src/operations/monitor/handler.ts
|
|
68326
|
-
var
|
|
68373
|
+
var log27 = createLogger("monitor");
|
|
68327
68374
|
var DEFAULT_INTERVAL_MS = 60 * 1000;
|
|
68328
68375
|
|
|
68329
68376
|
class SessionMonitor {
|
|
@@ -68345,14 +68392,14 @@ class SessionMonitor {
|
|
|
68345
68392
|
}
|
|
68346
68393
|
start() {
|
|
68347
68394
|
if (this.isRunning) {
|
|
68348
|
-
|
|
68395
|
+
log27.debug("Session monitor already running");
|
|
68349
68396
|
return;
|
|
68350
68397
|
}
|
|
68351
68398
|
this.isRunning = true;
|
|
68352
|
-
|
|
68399
|
+
log27.debug(`Session monitor started (interval: ${this.intervalMs / 1000}s)`);
|
|
68353
68400
|
this.timer = setInterval(() => {
|
|
68354
68401
|
this.runCheck().catch((err) => {
|
|
68355
|
-
|
|
68402
|
+
log27.error(`Error during session monitoring: ${err}`);
|
|
68356
68403
|
});
|
|
68357
68404
|
}, this.intervalMs);
|
|
68358
68405
|
}
|
|
@@ -68362,7 +68409,7 @@ class SessionMonitor {
|
|
|
68362
68409
|
this.timer = null;
|
|
68363
68410
|
}
|
|
68364
68411
|
this.isRunning = false;
|
|
68365
|
-
|
|
68412
|
+
log27.debug("Session monitor stopped");
|
|
68366
68413
|
}
|
|
68367
68414
|
async runCheck() {
|
|
68368
68415
|
await cleanupIdleSessions(this.sessionTimeoutMs, this.sessionWarningMs, this.getContext());
|
|
@@ -68374,8 +68421,8 @@ class SessionMonitor {
|
|
|
68374
68421
|
// src/operations/plugin/handler.ts
|
|
68375
68422
|
init_spawn();
|
|
68376
68423
|
init_logger();
|
|
68377
|
-
var
|
|
68378
|
-
var sessionLog7 = createSessionLog(
|
|
68424
|
+
var log28 = createLogger("plugin");
|
|
68425
|
+
var sessionLog7 = createSessionLog(log28);
|
|
68379
68426
|
async function runPluginCommand(args, cwd, timeout2 = 60000) {
|
|
68380
68427
|
return new Promise((resolve6) => {
|
|
68381
68428
|
const claudePath = process.env.CLAUDE_PATH || "claude";
|
|
@@ -68396,7 +68443,7 @@ async function runPluginCommand(args, cwd, timeout2 = 60000) {
|
|
|
68396
68443
|
});
|
|
68397
68444
|
proc.on("error", (err) => {
|
|
68398
68445
|
resolve6({ stdout, stderr, exitCode: 1 });
|
|
68399
|
-
|
|
68446
|
+
log28.error(`Plugin command error: ${err.message}`);
|
|
68400
68447
|
});
|
|
68401
68448
|
});
|
|
68402
68449
|
}
|
|
@@ -68595,9 +68642,105 @@ class SessionRegistry {
|
|
|
68595
68642
|
}
|
|
68596
68643
|
}
|
|
68597
68644
|
|
|
68645
|
+
// src/session/reaction-router.ts
|
|
68646
|
+
init_emoji();
|
|
68647
|
+
init_logger();
|
|
68648
|
+
var log29 = createLogger("manager");
|
|
68649
|
+
async function handleReaction(deps, platformId, postId, emojiName, username, action) {
|
|
68650
|
+
const normalizedEmoji = normalizeEmojiName(emojiName);
|
|
68651
|
+
if (action === "added" && isResumeEmoji(normalizedEmoji)) {
|
|
68652
|
+
const resumed = await tryResumeFromReaction(deps, platformId, postId, username);
|
|
68653
|
+
if (resumed)
|
|
68654
|
+
return;
|
|
68655
|
+
}
|
|
68656
|
+
const session = deps.registry.findByPost(postId);
|
|
68657
|
+
if (!session)
|
|
68658
|
+
return;
|
|
68659
|
+
if (session.platformId !== platformId)
|
|
68660
|
+
return;
|
|
68661
|
+
if (!session.sessionAllowedUsers.has(username) && !session.platform.isUserAllowed(username)) {
|
|
68662
|
+
log29.info(`\uD83D\uDEAB rejected reaction from unauthorized user`, {
|
|
68663
|
+
event: "reaction.rejected",
|
|
68664
|
+
platformId,
|
|
68665
|
+
sessionId: session.sessionId,
|
|
68666
|
+
postId,
|
|
68667
|
+
emoji: normalizedEmoji,
|
|
68668
|
+
action,
|
|
68669
|
+
user: username
|
|
68670
|
+
});
|
|
68671
|
+
return;
|
|
68672
|
+
}
|
|
68673
|
+
await dispatch(deps, session, postId, normalizedEmoji, username, action);
|
|
68674
|
+
}
|
|
68675
|
+
async function tryResumeFromReaction(deps, platformId, postId, username) {
|
|
68676
|
+
const persistedSession = deps.sessionStore.findByPostId(platformId, postId);
|
|
68677
|
+
if (!persistedSession)
|
|
68678
|
+
return false;
|
|
68679
|
+
const sessionId = `${platformId}:${persistedSession.threadId}`;
|
|
68680
|
+
if (deps.registry.hasById(sessionId))
|
|
68681
|
+
return false;
|
|
68682
|
+
const allowedUsers = new Set(persistedSession.sessionAllowedUsers);
|
|
68683
|
+
const platform = deps.platforms.get(platformId);
|
|
68684
|
+
if (!allowedUsers.has(username) && !platform?.isUserAllowed(username)) {
|
|
68685
|
+
if (platform) {
|
|
68686
|
+
await platform.createPost(`⚠️ @${username} is not authorized to resume this session`, persistedSession.threadId);
|
|
68687
|
+
}
|
|
68688
|
+
return false;
|
|
68689
|
+
}
|
|
68690
|
+
if (deps.registry.size >= deps.limits.maxSessions) {
|
|
68691
|
+
if (platform) {
|
|
68692
|
+
const fmt = platform.getFormatter();
|
|
68693
|
+
await platform.createPost(`⚠️ ${fmt.formatBold("Too busy")} - ${deps.registry.size} sessions active. Please try again later.`, persistedSession.threadId);
|
|
68694
|
+
}
|
|
68695
|
+
return false;
|
|
68696
|
+
}
|
|
68697
|
+
const shortId = persistedSession.threadId.substring(0, 8);
|
|
68698
|
+
log29.info(`\uD83D\uDD04 Resuming session ${shortId}... via emoji reaction by @${username}`);
|
|
68699
|
+
await resumeSession(persistedSession, deps.getContext());
|
|
68700
|
+
return true;
|
|
68701
|
+
}
|
|
68702
|
+
async function dispatch(deps, session, postId, emojiName, username, action) {
|
|
68703
|
+
if (action === "added") {
|
|
68704
|
+
if (session.sessionStartPostId === postId) {
|
|
68705
|
+
if (isCancelEmoji(emojiName)) {
|
|
68706
|
+
await cancelSession(session, username, deps.getContext());
|
|
68707
|
+
return;
|
|
68708
|
+
}
|
|
68709
|
+
if (isEscapeEmoji(emojiName)) {
|
|
68710
|
+
await interruptSession(session, username);
|
|
68711
|
+
return;
|
|
68712
|
+
}
|
|
68713
|
+
}
|
|
68714
|
+
if (session.worktreePromptPostId === postId && emojiName === "x") {
|
|
68715
|
+
await handleWorktreeSkip(session, username, (s) => deps.persistSession(s), (s, q) => offerContextPrompt(s, q, undefined, deps.getContextPromptHandler()));
|
|
68716
|
+
return;
|
|
68717
|
+
}
|
|
68718
|
+
if (session.pendingWorktreeSuggestions?.postId === postId) {
|
|
68719
|
+
const emojiIndex = getNumberEmojiIndex(emojiName);
|
|
68720
|
+
if (emojiIndex >= 0) {
|
|
68721
|
+
const handled = await handleBranchSuggestionReaction(session, postId, emojiIndex, username, (tid, branch, user) => deps.createAndSwitchToWorktree(tid, branch, user));
|
|
68722
|
+
if (handled)
|
|
68723
|
+
return;
|
|
68724
|
+
}
|
|
68725
|
+
}
|
|
68726
|
+
if (session.lastError?.postId === postId && isBugReportEmoji(emojiName)) {
|
|
68727
|
+
if (session.startedBy === username || session.platform.isUserAllowed(username) || session.sessionAllowedUsers.has(username)) {
|
|
68728
|
+
log29.info(`\uD83D\uDC1B @${username} triggered bug report from error reaction`);
|
|
68729
|
+
await reportBug(session, undefined, username, deps.getContext(), session.lastError);
|
|
68730
|
+
return;
|
|
68731
|
+
}
|
|
68732
|
+
}
|
|
68733
|
+
}
|
|
68734
|
+
if (session.messageManager) {
|
|
68735
|
+
const handled = await session.messageManager.handleReaction(postId, emojiName, username, action);
|
|
68736
|
+
if (handled)
|
|
68737
|
+
return;
|
|
68738
|
+
}
|
|
68739
|
+
}
|
|
68740
|
+
|
|
68598
68741
|
// src/session/manager.ts
|
|
68599
68742
|
init_logger();
|
|
68600
|
-
var
|
|
68743
|
+
var log30 = createLogger("manager");
|
|
68601
68744
|
|
|
68602
68745
|
class SessionManager extends EventEmitter4 {
|
|
68603
68746
|
platforms = new Map;
|
|
@@ -68666,7 +68809,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
68666
68809
|
markNeedsBump(platformId);
|
|
68667
68810
|
this.updateStickyMessage();
|
|
68668
68811
|
});
|
|
68669
|
-
|
|
68812
|
+
log30.info(`\uD83D\uDCE1 Platform "${platformId}" registered`);
|
|
68670
68813
|
}
|
|
68671
68814
|
removePlatform(platformId) {
|
|
68672
68815
|
this.platforms.delete(platformId);
|
|
@@ -68682,7 +68825,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
68682
68825
|
if (users) {
|
|
68683
68826
|
users.add(sessionId);
|
|
68684
68827
|
}
|
|
68685
|
-
|
|
68828
|
+
log30.debug(`Registered session ${sessionId.substring(0, 20)} as worktree user for ${worktreePath}`);
|
|
68686
68829
|
}
|
|
68687
68830
|
unregisterWorktreeUser(worktreePath, sessionId) {
|
|
68688
68831
|
const users = this.worktreeUsers.get(worktreePath);
|
|
@@ -68796,95 +68939,19 @@ class SessionManager extends EventEmitter4 {
|
|
|
68796
68939
|
}
|
|
68797
68940
|
async handleMessage(_platformId, _post, _user) {}
|
|
68798
68941
|
async handleReaction(platformId, postId, emojiName, username, action) {
|
|
68799
|
-
|
|
68800
|
-
if (action === "added" && isResumeEmoji(normalizedEmoji)) {
|
|
68801
|
-
const resumed = await this.tryResumeFromReaction(platformId, postId, username);
|
|
68802
|
-
if (resumed)
|
|
68803
|
-
return;
|
|
68804
|
-
}
|
|
68805
|
-
const session = this.getSessionByPost(postId);
|
|
68806
|
-
if (!session)
|
|
68807
|
-
return;
|
|
68808
|
-
if (session.platformId !== platformId)
|
|
68809
|
-
return;
|
|
68810
|
-
if (!session.sessionAllowedUsers.has(username) && !session.platform.isUserAllowed(username)) {
|
|
68811
|
-
log28.info(`\uD83D\uDEAB rejected reaction from unauthorized user`, {
|
|
68812
|
-
event: "reaction.rejected",
|
|
68813
|
-
platformId,
|
|
68814
|
-
sessionId: session.sessionId,
|
|
68815
|
-
postId,
|
|
68816
|
-
emoji: normalizedEmoji,
|
|
68817
|
-
action,
|
|
68818
|
-
user: username
|
|
68819
|
-
});
|
|
68820
|
-
return;
|
|
68821
|
-
}
|
|
68822
|
-
await this.handleSessionReaction(session, postId, normalizedEmoji, username, action);
|
|
68823
|
-
}
|
|
68824
|
-
async tryResumeFromReaction(platformId, postId, username) {
|
|
68825
|
-
const persistedSession = this.sessionStore.findByPostId(platformId, postId);
|
|
68826
|
-
if (!persistedSession)
|
|
68827
|
-
return false;
|
|
68828
|
-
const sessionId = `${platformId}:${persistedSession.threadId}`;
|
|
68829
|
-
if (this.registry.hasById(sessionId))
|
|
68830
|
-
return false;
|
|
68831
|
-
const allowedUsers = new Set(persistedSession.sessionAllowedUsers);
|
|
68832
|
-
const platform = this.platforms.get(platformId);
|
|
68833
|
-
if (!allowedUsers.has(username) && !platform?.isUserAllowed(username)) {
|
|
68834
|
-
if (platform) {
|
|
68835
|
-
await platform.createPost(`⚠️ @${username} is not authorized to resume this session`, persistedSession.threadId);
|
|
68836
|
-
}
|
|
68837
|
-
return false;
|
|
68838
|
-
}
|
|
68839
|
-
if (this.registry.size >= this.limits.maxSessions) {
|
|
68840
|
-
if (platform) {
|
|
68841
|
-
const fmt = platform.getFormatter();
|
|
68842
|
-
await platform.createPost(`⚠️ ${fmt.formatBold("Too busy")} - ${this.registry.size} sessions active. Please try again later.`, persistedSession.threadId);
|
|
68843
|
-
}
|
|
68844
|
-
return false;
|
|
68845
|
-
}
|
|
68846
|
-
const shortId = persistedSession.threadId.substring(0, 8);
|
|
68847
|
-
log28.info(`\uD83D\uDD04 Resuming session ${shortId}... via emoji reaction by @${username}`);
|
|
68848
|
-
await resumeSession(persistedSession, this.getContext());
|
|
68849
|
-
return true;
|
|
68942
|
+
await handleReaction(this.getReactionRouterDeps(), platformId, postId, emojiName, username, action);
|
|
68850
68943
|
}
|
|
68851
|
-
|
|
68852
|
-
|
|
68853
|
-
|
|
68854
|
-
|
|
68855
|
-
|
|
68856
|
-
|
|
68857
|
-
|
|
68858
|
-
|
|
68859
|
-
|
|
68860
|
-
|
|
68861
|
-
|
|
68862
|
-
}
|
|
68863
|
-
if (session.worktreePromptPostId === postId && emojiName === "x") {
|
|
68864
|
-
await handleWorktreeSkip(session, username, (s) => this.persistSession(s), (s, q) => offerContextPrompt(s, q, undefined, this.getContextPromptHandler()));
|
|
68865
|
-
return;
|
|
68866
|
-
}
|
|
68867
|
-
if (session.pendingWorktreeSuggestions?.postId === postId) {
|
|
68868
|
-
const emojiIndex = getNumberEmojiIndex(emojiName);
|
|
68869
|
-
if (emojiIndex >= 0) {
|
|
68870
|
-
const handled = await handleBranchSuggestionReaction(session, postId, emojiIndex, username, (tid, branch, user) => this.createAndSwitchToWorktree(tid, branch, user));
|
|
68871
|
-
if (handled)
|
|
68872
|
-
return;
|
|
68873
|
-
}
|
|
68874
|
-
}
|
|
68875
|
-
if (session.lastError?.postId === postId && isBugReportEmoji(emojiName)) {
|
|
68876
|
-
if (session.startedBy === username || session.platform.isUserAllowed(username) || session.sessionAllowedUsers.has(username)) {
|
|
68877
|
-
log28.info(`\uD83D\uDC1B @${username} triggered bug report from error reaction`);
|
|
68878
|
-
await reportBug(session, undefined, username, this.getContext(), session.lastError);
|
|
68879
|
-
return;
|
|
68880
|
-
}
|
|
68881
|
-
}
|
|
68882
|
-
}
|
|
68883
|
-
if (session.messageManager) {
|
|
68884
|
-
const handled = await session.messageManager.handleReaction(postId, emojiName, username, action);
|
|
68885
|
-
if (handled)
|
|
68886
|
-
return;
|
|
68887
|
-
}
|
|
68944
|
+
getReactionRouterDeps() {
|
|
68945
|
+
return {
|
|
68946
|
+
registry: this.registry,
|
|
68947
|
+
sessionStore: this.sessionStore,
|
|
68948
|
+
platforms: this.platforms,
|
|
68949
|
+
limits: this.limits,
|
|
68950
|
+
getContext: () => this.getContext(),
|
|
68951
|
+
getContextPromptHandler: () => this.getContextPromptHandler(),
|
|
68952
|
+
persistSession: (s) => this.persistSession(s),
|
|
68953
|
+
createAndSwitchToWorktree: (tid, branch, user) => this.createAndSwitchToWorktree(tid, branch, user)
|
|
68954
|
+
};
|
|
68888
68955
|
}
|
|
68889
68956
|
getContextPromptHandler() {
|
|
68890
68957
|
return {
|
|
@@ -68943,28 +69010,14 @@ class SessionManager extends EventEmitter4 {
|
|
|
68943
69010
|
this.stopTyping(session);
|
|
68944
69011
|
}
|
|
68945
69012
|
persistSession(session) {
|
|
68946
|
-
const useSerializeV2 = process.env.CLAUDE_THREADS_SERIALIZE_V2 !== "0";
|
|
68947
69013
|
let taskListSnapshot;
|
|
68948
69014
|
let contextPromptSnapshot;
|
|
68949
|
-
if (
|
|
69015
|
+
if (session.messageManager) {
|
|
68950
69016
|
const serialized = session.messageManager.serialize();
|
|
68951
69017
|
taskListSnapshot = serialized.taskList;
|
|
68952
69018
|
if (serialized.contextPrompt) {
|
|
68953
69019
|
contextPromptSnapshot = serialized.contextPrompt;
|
|
68954
69020
|
}
|
|
68955
|
-
} else {
|
|
68956
|
-
const legacyPrompt = session.messageManager?.getPendingContextPrompt();
|
|
68957
|
-
if (legacyPrompt) {
|
|
68958
|
-
contextPromptSnapshot = {
|
|
68959
|
-
postId: legacyPrompt.postId,
|
|
68960
|
-
queuedPrompt: legacyPrompt.queuedPrompt,
|
|
68961
|
-
queuedFiles: legacyPrompt.queuedFiles,
|
|
68962
|
-
threadMessageCount: legacyPrompt.threadMessageCount,
|
|
68963
|
-
createdAt: legacyPrompt.createdAt,
|
|
68964
|
-
availableOptions: legacyPrompt.availableOptions
|
|
68965
|
-
};
|
|
68966
|
-
}
|
|
68967
|
-
taskListSnapshot = session.messageManager?.getTaskListState();
|
|
68968
69021
|
}
|
|
68969
69022
|
const state = {
|
|
68970
69023
|
platformId: session.platformId,
|
|
@@ -69058,11 +69111,11 @@ class SessionManager extends EventEmitter4 {
|
|
|
69058
69111
|
}
|
|
69059
69112
|
}
|
|
69060
69113
|
if (sessionsToKill.length === 0) {
|
|
69061
|
-
|
|
69114
|
+
log30.info(`No active sessions to pause for platform ${platformId}`);
|
|
69062
69115
|
await this.updateStickyMessage();
|
|
69063
69116
|
return;
|
|
69064
69117
|
}
|
|
69065
|
-
|
|
69118
|
+
log30.info(`⏸️ Pausing ${sessionsToKill.length} session(s) for platform ${platformId}`);
|
|
69066
69119
|
for (const session of sessionsToKill) {
|
|
69067
69120
|
try {
|
|
69068
69121
|
const fmt = session.platform.getFormatter();
|
|
@@ -69078,9 +69131,9 @@ class SessionManager extends EventEmitter4 {
|
|
|
69078
69131
|
session.claude.kill();
|
|
69079
69132
|
this.registry.unregister(session.sessionId);
|
|
69080
69133
|
this.emitSessionRemove(session.sessionId);
|
|
69081
|
-
|
|
69134
|
+
log30.info(`⏸️ Paused session ${session.threadId.substring(0, 8)}`);
|
|
69082
69135
|
} catch (err) {
|
|
69083
|
-
|
|
69136
|
+
log30.warn(`Failed to pause session ${session.threadId}: ${err}`);
|
|
69084
69137
|
}
|
|
69085
69138
|
}
|
|
69086
69139
|
for (const session of sessionsToKill) {
|
|
@@ -69101,17 +69154,17 @@ class SessionManager extends EventEmitter4 {
|
|
|
69101
69154
|
sessionsToResume.push(state);
|
|
69102
69155
|
}
|
|
69103
69156
|
if (sessionsToResume.length === 0) {
|
|
69104
|
-
|
|
69157
|
+
log30.info(`No paused sessions to resume for platform ${platformId}`);
|
|
69105
69158
|
await this.updateStickyMessage();
|
|
69106
69159
|
return;
|
|
69107
69160
|
}
|
|
69108
|
-
|
|
69161
|
+
log30.info(`▶️ Resuming ${sessionsToResume.length} paused session(s) for platform ${platformId}`);
|
|
69109
69162
|
for (const state of sessionsToResume) {
|
|
69110
69163
|
try {
|
|
69111
69164
|
await resumeSession(state, this.getContext());
|
|
69112
|
-
|
|
69165
|
+
log30.info(`▶️ Resumed session ${state.threadId.substring(0, 8)}`);
|
|
69113
69166
|
} catch (err) {
|
|
69114
|
-
|
|
69167
|
+
log30.warn(`Failed to resume session ${state.threadId}: ${err}`);
|
|
69115
69168
|
}
|
|
69116
69169
|
}
|
|
69117
69170
|
await this.updateStickyMessage();
|
|
@@ -69123,14 +69176,14 @@ class SessionManager extends EventEmitter4 {
|
|
|
69123
69176
|
const sessionTimeoutMs = this.limits.sessionTimeoutMinutes * 60 * 1000;
|
|
69124
69177
|
const staleIds = this.sessionStore.cleanStale(sessionTimeoutMs * 2);
|
|
69125
69178
|
if (staleIds.length > 0) {
|
|
69126
|
-
|
|
69179
|
+
log30.info(`\uD83E\uDDF9 Soft-deleted ${staleIds.length} stale session(s) (kept for history)`);
|
|
69127
69180
|
}
|
|
69128
69181
|
const removedCount = this.sessionStore.cleanHistory();
|
|
69129
69182
|
if (removedCount > 0) {
|
|
69130
|
-
|
|
69183
|
+
log30.info(`\uD83D\uDDD1️ Permanently removed ${removedCount} old session(s) from history`);
|
|
69131
69184
|
}
|
|
69132
69185
|
const persisted = this.sessionStore.load();
|
|
69133
|
-
|
|
69186
|
+
log30.info(`\uD83D\uDCC2 Loaded ${persisted.size} session(s) from persistence`);
|
|
69134
69187
|
const excludePostIdsByPlatform = new Map;
|
|
69135
69188
|
for (const session of persisted.values()) {
|
|
69136
69189
|
const platformId = session.platformId;
|
|
@@ -69150,10 +69203,10 @@ class SessionManager extends EventEmitter4 {
|
|
|
69150
69203
|
const excludePostIds = excludePostIdsByPlatform.get(platform.platformId);
|
|
69151
69204
|
platform.getBotUser().then((botUser) => {
|
|
69152
69205
|
cleanupOldStickyMessages(platform, botUser.id, true, excludePostIds).catch((err) => {
|
|
69153
|
-
|
|
69206
|
+
log30.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
|
|
69154
69207
|
});
|
|
69155
69208
|
}).catch((err) => {
|
|
69156
|
-
|
|
69209
|
+
log30.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
|
|
69157
69210
|
});
|
|
69158
69211
|
}
|
|
69159
69212
|
if (persisted.size > 0) {
|
|
@@ -69167,10 +69220,10 @@ class SessionManager extends EventEmitter4 {
|
|
|
69167
69220
|
}
|
|
69168
69221
|
}
|
|
69169
69222
|
if (pausedToSkip.length > 0) {
|
|
69170
|
-
|
|
69223
|
+
log30.info(`⏸️ ${pausedToSkip.length} session(s) remain paused (waiting for user message)`);
|
|
69171
69224
|
}
|
|
69172
69225
|
if (activeToResume.length > 0) {
|
|
69173
|
-
|
|
69226
|
+
log30.info(`\uD83D\uDD04 Attempting to resume ${activeToResume.length} active session(s)...`);
|
|
69174
69227
|
for (const state of activeToResume) {
|
|
69175
69228
|
await resumeSession(state, this.getContext());
|
|
69176
69229
|
}
|
|
@@ -69595,7 +69648,7 @@ Mention me to start a session in this worktree.`, threadId);
|
|
|
69595
69648
|
const message = messageBuilder(formatter);
|
|
69596
69649
|
await post(session, "info", message);
|
|
69597
69650
|
} catch (err) {
|
|
69598
|
-
|
|
69651
|
+
log30.warn(`Failed to broadcast to session ${session.threadId}: ${err}`);
|
|
69599
69652
|
}
|
|
69600
69653
|
}
|
|
69601
69654
|
}
|
|
@@ -69614,7 +69667,7 @@ Mention me to start a session in this worktree.`, threadId);
|
|
|
69614
69667
|
session.messageManager?.setPendingUpdatePrompt({ postId: post2.id });
|
|
69615
69668
|
this.registerPost(post2.id, session.threadId);
|
|
69616
69669
|
} catch (err) {
|
|
69617
|
-
|
|
69670
|
+
log30.warn(`Failed to post ask message to ${threadId}: ${err}`);
|
|
69618
69671
|
}
|
|
69619
69672
|
}
|
|
69620
69673
|
}
|
|
@@ -77210,29 +77263,29 @@ function SessionLog({ logs, maxLines = 20 }) {
|
|
|
77210
77263
|
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
77211
77264
|
flexDirection: "column",
|
|
77212
77265
|
flexShrink: 0,
|
|
77213
|
-
children: displayLogs.map((
|
|
77266
|
+
children: displayLogs.map((log31) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
77214
77267
|
flexShrink: 0,
|
|
77215
77268
|
children: [
|
|
77216
77269
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
77217
|
-
color: getColorForLevel(
|
|
77270
|
+
color: getColorForLevel(log31.level),
|
|
77218
77271
|
dimColor: true,
|
|
77219
77272
|
wrap: "truncate",
|
|
77220
77273
|
children: [
|
|
77221
77274
|
"[",
|
|
77222
|
-
padComponent(
|
|
77275
|
+
padComponent(log31.component),
|
|
77223
77276
|
"]"
|
|
77224
77277
|
]
|
|
77225
77278
|
}, undefined, true, undefined, this),
|
|
77226
77279
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
77227
|
-
color: getColorForLevel(
|
|
77280
|
+
color: getColorForLevel(log31.level),
|
|
77228
77281
|
wrap: "truncate",
|
|
77229
77282
|
children: [
|
|
77230
77283
|
" ",
|
|
77231
|
-
|
|
77284
|
+
log31.message
|
|
77232
77285
|
]
|
|
77233
77286
|
}, undefined, true, undefined, this)
|
|
77234
77287
|
]
|
|
77235
|
-
},
|
|
77288
|
+
}, log31.id, true, undefined, this))
|
|
77236
77289
|
}, undefined, false, undefined, this);
|
|
77237
77290
|
}
|
|
77238
77291
|
// src/ui/components/Footer.tsx
|
|
@@ -77756,7 +77809,7 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
|
|
|
77756
77809
|
const scrollRef = import_react59.default.useRef(null);
|
|
77757
77810
|
const { stdout } = use_stdout_default();
|
|
77758
77811
|
const isDebug = process.env.DEBUG === "1";
|
|
77759
|
-
const displayLogs = logs.filter((
|
|
77812
|
+
const displayLogs = logs.filter((log31) => isDebug || log31.level !== "debug");
|
|
77760
77813
|
const visibleLogs = displayLogs.slice(-Math.max(maxLines * 3, 100));
|
|
77761
77814
|
import_react59.default.useEffect(() => {
|
|
77762
77815
|
const handleResize = () => scrollRef.current?.remeasure();
|
|
@@ -77796,25 +77849,25 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
|
|
|
77796
77849
|
overflow: "hidden",
|
|
77797
77850
|
children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(ScrollView, {
|
|
77798
77851
|
ref: scrollRef,
|
|
77799
|
-
children: visibleLogs.map((
|
|
77852
|
+
children: visibleLogs.map((log31) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
77800
77853
|
children: [
|
|
77801
77854
|
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
77802
77855
|
dimColor: true,
|
|
77803
77856
|
children: [
|
|
77804
77857
|
"[",
|
|
77805
|
-
padComponent2(
|
|
77858
|
+
padComponent2(log31.component),
|
|
77806
77859
|
"]"
|
|
77807
77860
|
]
|
|
77808
77861
|
}, undefined, true, undefined, this),
|
|
77809
77862
|
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
77810
|
-
color: getLevelColor(
|
|
77863
|
+
color: getLevelColor(log31.level),
|
|
77811
77864
|
children: [
|
|
77812
77865
|
" ",
|
|
77813
|
-
|
|
77866
|
+
log31.message
|
|
77814
77867
|
]
|
|
77815
77868
|
}, undefined, true, undefined, this)
|
|
77816
77869
|
]
|
|
77817
|
-
},
|
|
77870
|
+
}, log31.id, true, undefined, this))
|
|
77818
77871
|
}, undefined, false, undefined, this)
|
|
77819
77872
|
}, undefined, false, undefined, this);
|
|
77820
77873
|
}
|
|
@@ -78331,10 +78384,10 @@ function useAppState(initialConfig) {
|
|
|
78331
78384
|
});
|
|
78332
78385
|
}, []);
|
|
78333
78386
|
const getLogsForSession = import_react60.useCallback((sessionId) => {
|
|
78334
|
-
return state.logs.filter((
|
|
78387
|
+
return state.logs.filter((log31) => log31.sessionId === sessionId);
|
|
78335
78388
|
}, [state.logs]);
|
|
78336
78389
|
const getGlobalLogs = import_react60.useCallback(() => {
|
|
78337
|
-
return state.logs.filter((
|
|
78390
|
+
return state.logs.filter((log31) => !log31.sessionId);
|
|
78338
78391
|
}, [state.logs]);
|
|
78339
78392
|
const togglePlatformEnabled = import_react60.useCallback((platformId) => {
|
|
78340
78393
|
let newEnabled = false;
|
|
@@ -79341,7 +79394,7 @@ import { EventEmitter as EventEmitter9 } from "events";
|
|
|
79341
79394
|
// src/auto-update/checker.ts
|
|
79342
79395
|
init_logger();
|
|
79343
79396
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
79344
|
-
var
|
|
79397
|
+
var log31 = createLogger("checker");
|
|
79345
79398
|
var PACKAGE_NAME = "claude-threads";
|
|
79346
79399
|
function compareVersions(a, b) {
|
|
79347
79400
|
const partsA = a.replace(/^v/, "").split(".").map(Number);
|
|
@@ -79364,13 +79417,13 @@ async function fetchLatestVersion() {
|
|
|
79364
79417
|
}
|
|
79365
79418
|
});
|
|
79366
79419
|
if (!response.ok) {
|
|
79367
|
-
|
|
79420
|
+
log31.warn(`Failed to fetch latest version: HTTP ${response.status}`);
|
|
79368
79421
|
return null;
|
|
79369
79422
|
}
|
|
79370
79423
|
const data = await response.json();
|
|
79371
79424
|
return data.version ?? null;
|
|
79372
79425
|
} catch (err) {
|
|
79373
|
-
|
|
79426
|
+
log31.warn(`Failed to fetch latest version: ${err}`);
|
|
79374
79427
|
return null;
|
|
79375
79428
|
}
|
|
79376
79429
|
}
|
|
@@ -79387,38 +79440,38 @@ class UpdateChecker extends EventEmitter7 {
|
|
|
79387
79440
|
}
|
|
79388
79441
|
start() {
|
|
79389
79442
|
if (!this.config.enabled) {
|
|
79390
|
-
|
|
79443
|
+
log31.debug("Auto-update disabled, not starting checker");
|
|
79391
79444
|
return;
|
|
79392
79445
|
}
|
|
79393
79446
|
setTimeout(() => {
|
|
79394
79447
|
this.check().catch((err) => {
|
|
79395
|
-
|
|
79448
|
+
log31.warn(`Initial update check failed: ${err}`);
|
|
79396
79449
|
});
|
|
79397
79450
|
}, 5000);
|
|
79398
79451
|
const intervalMs = this.config.checkIntervalMinutes * 60 * 1000;
|
|
79399
79452
|
this.checkInterval = setInterval(() => {
|
|
79400
79453
|
this.check().catch((err) => {
|
|
79401
|
-
|
|
79454
|
+
log31.warn(`Periodic update check failed: ${err}`);
|
|
79402
79455
|
});
|
|
79403
79456
|
}, intervalMs);
|
|
79404
|
-
|
|
79457
|
+
log31.info(`\uD83D\uDD04 Update checker started (every ${this.config.checkIntervalMinutes} minutes)`);
|
|
79405
79458
|
}
|
|
79406
79459
|
stop() {
|
|
79407
79460
|
if (this.checkInterval) {
|
|
79408
79461
|
clearInterval(this.checkInterval);
|
|
79409
79462
|
this.checkInterval = null;
|
|
79410
79463
|
}
|
|
79411
|
-
|
|
79464
|
+
log31.debug("Update checker stopped");
|
|
79412
79465
|
}
|
|
79413
79466
|
async check() {
|
|
79414
79467
|
if (this.isChecking) {
|
|
79415
|
-
|
|
79468
|
+
log31.debug("Check already in progress, skipping");
|
|
79416
79469
|
return this.lastUpdateInfo;
|
|
79417
79470
|
}
|
|
79418
79471
|
this.isChecking = true;
|
|
79419
79472
|
this.emit("check:start");
|
|
79420
79473
|
try {
|
|
79421
|
-
|
|
79474
|
+
log31.debug("Checking for updates...");
|
|
79422
79475
|
const latestVersion2 = await fetchLatestVersion();
|
|
79423
79476
|
if (!latestVersion2) {
|
|
79424
79477
|
this.emit("check:complete", false);
|
|
@@ -79435,18 +79488,18 @@ class UpdateChecker extends EventEmitter7 {
|
|
|
79435
79488
|
detectedAt: new Date
|
|
79436
79489
|
};
|
|
79437
79490
|
if (!this.lastUpdateInfo || this.lastUpdateInfo.latestVersion !== latestVersion2) {
|
|
79438
|
-
|
|
79491
|
+
log31.info(`\uD83C\uDD95 Update available: v${currentVersion} → v${latestVersion2}`);
|
|
79439
79492
|
this.lastUpdateInfo = updateInfo;
|
|
79440
79493
|
this.emit("update", updateInfo);
|
|
79441
79494
|
}
|
|
79442
79495
|
this.emit("check:complete", true);
|
|
79443
79496
|
return updateInfo;
|
|
79444
79497
|
}
|
|
79445
|
-
|
|
79498
|
+
log31.debug(`Up to date (v${currentVersion})`);
|
|
79446
79499
|
this.emit("check:complete", false);
|
|
79447
79500
|
return null;
|
|
79448
79501
|
} catch (err) {
|
|
79449
|
-
|
|
79502
|
+
log31.warn(`Update check failed: ${err}`);
|
|
79450
79503
|
this.emit("check:error", err);
|
|
79451
79504
|
return null;
|
|
79452
79505
|
} finally {
|
|
@@ -79517,7 +79570,7 @@ function isInScheduledWindow(window2) {
|
|
|
79517
79570
|
}
|
|
79518
79571
|
|
|
79519
79572
|
// src/auto-update/scheduler.ts
|
|
79520
|
-
var
|
|
79573
|
+
var log32 = createLogger("scheduler");
|
|
79521
79574
|
|
|
79522
79575
|
class UpdateScheduler extends EventEmitter8 {
|
|
79523
79576
|
config;
|
|
@@ -79541,7 +79594,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79541
79594
|
scheduleUpdate(updateInfo) {
|
|
79542
79595
|
this.pendingUpdate = updateInfo;
|
|
79543
79596
|
if (this.config.autoRestartMode === "immediate") {
|
|
79544
|
-
|
|
79597
|
+
log32.info("Immediate mode: triggering update now");
|
|
79545
79598
|
this.emit("ready", updateInfo);
|
|
79546
79599
|
return;
|
|
79547
79600
|
}
|
|
@@ -79554,19 +79607,19 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79554
79607
|
this.scheduledRestartAt = null;
|
|
79555
79608
|
this.askApprovals.clear();
|
|
79556
79609
|
this.askStartTime = null;
|
|
79557
|
-
|
|
79610
|
+
log32.debug("Update schedule cancelled");
|
|
79558
79611
|
}
|
|
79559
79612
|
deferUpdate(minutes) {
|
|
79560
79613
|
const deferUntil = new Date(Date.now() + minutes * 60 * 1000);
|
|
79561
79614
|
this.scheduledRestartAt = null;
|
|
79562
79615
|
this.idleStartTime = null;
|
|
79563
79616
|
this.emit("deferred", deferUntil);
|
|
79564
|
-
|
|
79617
|
+
log32.info(`Update deferred until ${deferUntil.toLocaleTimeString()}`);
|
|
79565
79618
|
return deferUntil;
|
|
79566
79619
|
}
|
|
79567
79620
|
recordAskResponse(threadId, approved) {
|
|
79568
79621
|
this.askApprovals.set(threadId, approved);
|
|
79569
|
-
|
|
79622
|
+
log32.debug(`Thread ${threadId.substring(0, 8)} ${approved ? "approved" : "denied"} update`);
|
|
79570
79623
|
this.checkAskCondition();
|
|
79571
79624
|
}
|
|
79572
79625
|
getScheduledRestartAt() {
|
|
@@ -79587,7 +79640,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79587
79640
|
return;
|
|
79588
79641
|
this.checkCondition();
|
|
79589
79642
|
this.checkTimer = setInterval(() => this.checkCondition(), 1e4);
|
|
79590
|
-
|
|
79643
|
+
log32.debug(`Started checking for ${this.config.autoRestartMode} condition`);
|
|
79591
79644
|
}
|
|
79592
79645
|
stopChecking() {
|
|
79593
79646
|
if (this.checkTimer) {
|
|
@@ -79618,17 +79671,17 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79618
79671
|
if (activity.activeSessionCount === 0) {
|
|
79619
79672
|
if (!this.idleStartTime) {
|
|
79620
79673
|
this.idleStartTime = new Date;
|
|
79621
|
-
|
|
79674
|
+
log32.debug("No active sessions, starting idle timer");
|
|
79622
79675
|
}
|
|
79623
79676
|
const idleMs = Date.now() - this.idleStartTime.getTime();
|
|
79624
79677
|
const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
79625
79678
|
if (idleMs >= requiredMs) {
|
|
79626
|
-
|
|
79679
|
+
log32.info(`Idle for ${this.config.idleTimeoutMinutes} minutes, triggering update`);
|
|
79627
79680
|
this.triggerCountdown();
|
|
79628
79681
|
}
|
|
79629
79682
|
} else {
|
|
79630
79683
|
if (this.idleStartTime) {
|
|
79631
|
-
|
|
79684
|
+
log32.debug("Sessions became active, resetting idle timer");
|
|
79632
79685
|
this.idleStartTime = null;
|
|
79633
79686
|
}
|
|
79634
79687
|
}
|
|
@@ -79639,7 +79692,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79639
79692
|
const quietMs = Date.now() - activity.lastActivityAt.getTime();
|
|
79640
79693
|
const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
|
|
79641
79694
|
if (quietMs >= requiredMs && !activity.anySessionBusy) {
|
|
79642
|
-
|
|
79695
|
+
log32.info(`Sessions quiet for ${this.config.quietTimeoutMinutes} minutes, triggering update`);
|
|
79643
79696
|
this.triggerCountdown();
|
|
79644
79697
|
}
|
|
79645
79698
|
} else if (activity.activeSessionCount === 0) {
|
|
@@ -79649,7 +79702,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79649
79702
|
const idleMs = Date.now() - this.idleStartTime.getTime();
|
|
79650
79703
|
const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
|
|
79651
79704
|
if (idleMs >= requiredMs) {
|
|
79652
|
-
|
|
79705
|
+
log32.info("No sessions and quiet timeout reached, triggering update");
|
|
79653
79706
|
this.triggerCountdown();
|
|
79654
79707
|
}
|
|
79655
79708
|
}
|
|
@@ -79660,13 +79713,13 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79660
79713
|
}
|
|
79661
79714
|
const activity = this.getSessionActivity();
|
|
79662
79715
|
if (activity.activeSessionCount === 0) {
|
|
79663
|
-
|
|
79716
|
+
log32.info("Within scheduled window and no active sessions, triggering update");
|
|
79664
79717
|
this.triggerCountdown();
|
|
79665
79718
|
} else if (activity.lastActivityAt) {
|
|
79666
79719
|
const quietMs = Date.now() - activity.lastActivityAt.getTime();
|
|
79667
79720
|
const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
79668
79721
|
if (quietMs >= requiredMs && !activity.anySessionBusy) {
|
|
79669
|
-
|
|
79722
|
+
log32.info("Within scheduled window and sessions quiet, triggering update");
|
|
79670
79723
|
this.triggerCountdown();
|
|
79671
79724
|
}
|
|
79672
79725
|
}
|
|
@@ -79674,14 +79727,14 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79674
79727
|
checkAskCondition() {
|
|
79675
79728
|
const threadIds = this.getActiveThreadIds();
|
|
79676
79729
|
if (threadIds.length === 0) {
|
|
79677
|
-
|
|
79730
|
+
log32.info("No active threads, proceeding with update");
|
|
79678
79731
|
this.triggerCountdown();
|
|
79679
79732
|
return;
|
|
79680
79733
|
}
|
|
79681
79734
|
if (!this.askStartTime && this.pendingUpdate) {
|
|
79682
79735
|
this.askStartTime = new Date;
|
|
79683
79736
|
this.postAskMessage(threadIds, this.pendingUpdate.latestVersion).catch((err) => {
|
|
79684
|
-
|
|
79737
|
+
log32.warn(`Failed to post ask message: ${err}`);
|
|
79685
79738
|
});
|
|
79686
79739
|
return;
|
|
79687
79740
|
}
|
|
@@ -79694,12 +79747,12 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79694
79747
|
denials++;
|
|
79695
79748
|
}
|
|
79696
79749
|
if (approvals > threadIds.length / 2) {
|
|
79697
|
-
|
|
79750
|
+
log32.info(`Majority approved (${approvals}/${threadIds.length}), triggering update`);
|
|
79698
79751
|
this.triggerCountdown();
|
|
79699
79752
|
return;
|
|
79700
79753
|
}
|
|
79701
79754
|
if (denials > threadIds.length / 2) {
|
|
79702
|
-
|
|
79755
|
+
log32.info(`Majority denied (${denials}/${threadIds.length}), deferring update`);
|
|
79703
79756
|
this.deferUpdate(60);
|
|
79704
79757
|
return;
|
|
79705
79758
|
}
|
|
@@ -79707,7 +79760,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79707
79760
|
const elapsedMs = Date.now() - this.askStartTime.getTime();
|
|
79708
79761
|
const timeoutMs = this.config.askTimeoutMinutes * 60 * 1000;
|
|
79709
79762
|
if (elapsedMs >= timeoutMs) {
|
|
79710
|
-
|
|
79763
|
+
log32.info(`Ask timeout reached (${this.config.askTimeoutMinutes} min), triggering update`);
|
|
79711
79764
|
this.triggerCountdown();
|
|
79712
79765
|
}
|
|
79713
79766
|
}
|
|
@@ -79727,7 +79780,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79727
79780
|
this.emit("ready", this.pendingUpdate);
|
|
79728
79781
|
}
|
|
79729
79782
|
}, 1000);
|
|
79730
|
-
|
|
79783
|
+
log32.info("Update countdown started (60 seconds)");
|
|
79731
79784
|
}
|
|
79732
79785
|
stopCountdown() {
|
|
79733
79786
|
if (this.countdownTimer) {
|
|
@@ -79743,24 +79796,24 @@ import { spawn as spawn4, spawnSync } from "child_process";
|
|
|
79743
79796
|
import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
79744
79797
|
import { dirname as dirname8, resolve as resolve6 } from "path";
|
|
79745
79798
|
import { homedir as homedir5 } from "os";
|
|
79746
|
-
var
|
|
79799
|
+
var log33 = createLogger("installer");
|
|
79747
79800
|
function detectPackageManager() {
|
|
79748
79801
|
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
79749
79802
|
const originalInstaller = detectOriginalInstaller();
|
|
79750
79803
|
if (originalInstaller) {
|
|
79751
|
-
|
|
79804
|
+
log33.debug(`Detected original installer: ${originalInstaller}`);
|
|
79752
79805
|
if (originalInstaller === "bun") {
|
|
79753
79806
|
const bunCheck2 = spawnSync("bun", ["--version"], { stdio: "ignore" });
|
|
79754
79807
|
if (bunCheck2.status === 0) {
|
|
79755
79808
|
return { cmd: "bun", isBun: true };
|
|
79756
79809
|
}
|
|
79757
|
-
|
|
79810
|
+
log33.warn("Originally installed with bun, but bun not found. Falling back to npm.");
|
|
79758
79811
|
} else {
|
|
79759
79812
|
const npmCheck2 = spawnSync(npmCmd, ["--version"], { stdio: "ignore" });
|
|
79760
79813
|
if (npmCheck2.status === 0) {
|
|
79761
79814
|
return { cmd: npmCmd, isBun: false };
|
|
79762
79815
|
}
|
|
79763
|
-
|
|
79816
|
+
log33.warn("Originally installed with npm, but npm not found. Falling back to bun.");
|
|
79764
79817
|
}
|
|
79765
79818
|
}
|
|
79766
79819
|
const bunCheck = spawnSync("bun", ["--version"], { stdio: "ignore" });
|
|
@@ -79811,7 +79864,7 @@ function loadUpdateState() {
|
|
|
79811
79864
|
return JSON.parse(content);
|
|
79812
79865
|
}
|
|
79813
79866
|
} catch (err) {
|
|
79814
|
-
|
|
79867
|
+
log33.warn(`Failed to load update state: ${err}`);
|
|
79815
79868
|
}
|
|
79816
79869
|
return {};
|
|
79817
79870
|
}
|
|
@@ -79822,9 +79875,9 @@ function saveUpdateState(state) {
|
|
|
79822
79875
|
mkdirSync4(dir, { recursive: true });
|
|
79823
79876
|
}
|
|
79824
79877
|
writeFileSync6(STATE_PATH, JSON.stringify(state, null, 2), "utf-8");
|
|
79825
|
-
|
|
79878
|
+
log33.debug("Update state saved");
|
|
79826
79879
|
} catch (err) {
|
|
79827
|
-
|
|
79880
|
+
log33.warn(`Failed to save update state: ${err}`);
|
|
79828
79881
|
}
|
|
79829
79882
|
}
|
|
79830
79883
|
function clearUpdateState() {
|
|
@@ -79833,7 +79886,7 @@ function clearUpdateState() {
|
|
|
79833
79886
|
writeFileSync6(STATE_PATH, "{}", "utf-8");
|
|
79834
79887
|
}
|
|
79835
79888
|
} catch (err) {
|
|
79836
|
-
|
|
79889
|
+
log33.warn(`Failed to clear update state: ${err}`);
|
|
79837
79890
|
}
|
|
79838
79891
|
}
|
|
79839
79892
|
function checkJustUpdated() {
|
|
@@ -79865,11 +79918,11 @@ function clearRuntimeSettings() {
|
|
|
79865
79918
|
}
|
|
79866
79919
|
}
|
|
79867
79920
|
async function installVersion(version) {
|
|
79868
|
-
|
|
79921
|
+
log33.info(`\uD83D\uDCE6 Installing ${PACKAGE_NAME2}@${version}...`);
|
|
79869
79922
|
const pm = detectPackageManager();
|
|
79870
79923
|
if (!pm) {
|
|
79871
79924
|
const error = "Neither bun nor npm found in PATH. Cannot install update.";
|
|
79872
|
-
|
|
79925
|
+
log33.error(`❌ ${error}`);
|
|
79873
79926
|
return { success: false, error };
|
|
79874
79927
|
}
|
|
79875
79928
|
saveUpdateState({
|
|
@@ -79881,7 +79934,7 @@ async function installVersion(version) {
|
|
|
79881
79934
|
return new Promise((resolve7) => {
|
|
79882
79935
|
const { cmd, isBun: isBun3 } = pm;
|
|
79883
79936
|
const args = ["install", "-g", `${PACKAGE_NAME2}@${version}`];
|
|
79884
|
-
|
|
79937
|
+
log33.debug(`Using ${isBun3 ? "bun" : "npm"} for installation`);
|
|
79885
79938
|
const child = spawn4(cmd, args, {
|
|
79886
79939
|
stdio: ["ignore", "pipe", "pipe"],
|
|
79887
79940
|
env: {
|
|
@@ -79899,7 +79952,7 @@ async function installVersion(version) {
|
|
|
79899
79952
|
});
|
|
79900
79953
|
child.on("close", (code) => {
|
|
79901
79954
|
if (code === 0) {
|
|
79902
|
-
|
|
79955
|
+
log33.info(`✅ Successfully installed ${PACKAGE_NAME2}@${version}`);
|
|
79903
79956
|
saveUpdateState({
|
|
79904
79957
|
previousVersion: VERSION,
|
|
79905
79958
|
targetVersion: version,
|
|
@@ -79909,20 +79962,20 @@ async function installVersion(version) {
|
|
|
79909
79962
|
resolve7({ success: true });
|
|
79910
79963
|
} else {
|
|
79911
79964
|
const errorMsg = stderr || stdout || `Exit code: ${code}`;
|
|
79912
|
-
|
|
79965
|
+
log33.error(`❌ Installation failed: ${errorMsg}`);
|
|
79913
79966
|
clearUpdateState();
|
|
79914
79967
|
resolve7({ success: false, error: errorMsg });
|
|
79915
79968
|
}
|
|
79916
79969
|
});
|
|
79917
79970
|
child.on("error", (err) => {
|
|
79918
|
-
|
|
79971
|
+
log33.error(`❌ Failed to spawn npm: ${err}`);
|
|
79919
79972
|
clearUpdateState();
|
|
79920
79973
|
resolve7({ success: false, error: err.message });
|
|
79921
79974
|
});
|
|
79922
79975
|
setTimeout(() => {
|
|
79923
79976
|
if (child.exitCode === null) {
|
|
79924
79977
|
child.kill();
|
|
79925
|
-
|
|
79978
|
+
log33.error("❌ Installation timed out");
|
|
79926
79979
|
clearUpdateState();
|
|
79927
79980
|
resolve7({ success: false, error: "Installation timed out" });
|
|
79928
79981
|
}
|
|
@@ -79964,7 +80017,7 @@ class UpdateInstaller {
|
|
|
79964
80017
|
}
|
|
79965
80018
|
|
|
79966
80019
|
// src/auto-update/manager.ts
|
|
79967
|
-
var
|
|
80020
|
+
var log34 = createLogger("updater");
|
|
79968
80021
|
|
|
79969
80022
|
class AutoUpdateManager extends EventEmitter9 {
|
|
79970
80023
|
config;
|
|
@@ -79987,23 +80040,23 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
79987
80040
|
}
|
|
79988
80041
|
start() {
|
|
79989
80042
|
if (!this.config.enabled) {
|
|
79990
|
-
|
|
80043
|
+
log34.info("Auto-update is disabled");
|
|
79991
80044
|
return;
|
|
79992
80045
|
}
|
|
79993
80046
|
const updateResult = this.installer.checkJustUpdated();
|
|
79994
80047
|
if (updateResult) {
|
|
79995
|
-
|
|
80048
|
+
log34.info(`\uD83C\uDF89 Updated from v${updateResult.previousVersion} to v${updateResult.currentVersion}`);
|
|
79996
80049
|
this.callbacks.broadcastUpdate((fmt) => `\uD83C\uDF89 ${fmt.formatBold("Bot updated")} from v${updateResult.previousVersion} to v${updateResult.currentVersion}`).catch((err) => {
|
|
79997
|
-
|
|
80050
|
+
log34.warn(`Failed to broadcast update notification: ${err}`);
|
|
79998
80051
|
});
|
|
79999
80052
|
}
|
|
80000
80053
|
this.checker.start();
|
|
80001
|
-
|
|
80054
|
+
log34.info(`\uD83D\uDD04 Auto-update manager started (mode: ${this.config.autoRestartMode})`);
|
|
80002
80055
|
}
|
|
80003
80056
|
stop() {
|
|
80004
80057
|
this.checker.stop();
|
|
80005
80058
|
this.scheduler.stop();
|
|
80006
|
-
|
|
80059
|
+
log34.debug("Auto-update manager stopped");
|
|
80007
80060
|
}
|
|
80008
80061
|
getState() {
|
|
80009
80062
|
return { ...this.state };
|
|
@@ -80017,10 +80070,10 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
80017
80070
|
async forceUpdate() {
|
|
80018
80071
|
const updateInfo = this.state.updateInfo || await this.checker.check();
|
|
80019
80072
|
if (!updateInfo) {
|
|
80020
|
-
|
|
80073
|
+
log34.info("No update available");
|
|
80021
80074
|
return;
|
|
80022
80075
|
}
|
|
80023
|
-
|
|
80076
|
+
log34.info("Forcing immediate update");
|
|
80024
80077
|
await this.performUpdate(updateInfo);
|
|
80025
80078
|
}
|
|
80026
80079
|
deferUpdate(minutes = 60) {
|
|
@@ -80075,7 +80128,7 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
80075
80128
|
await this.callbacks.broadcastUpdate((fmt) => `✅ ${fmt.formatBold("Update installed")} - restarting now. ${fmt.formatItalic("Sessions will resume automatically.")}`).catch(() => {});
|
|
80076
80129
|
await new Promise((resolve7) => setTimeout(resolve7, 1000));
|
|
80077
80130
|
await this.callbacks.prepareForRestart();
|
|
80078
|
-
|
|
80131
|
+
log34.info(`\uD83D\uDD04 Restarting for update to v${updateInfo.latestVersion}`);
|
|
80079
80132
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
80080
80133
|
process.stdout.write("\x1B[?25h");
|
|
80081
80134
|
process.exit(RESTART_EXIT_CODE);
|