claude-threads 1.9.2 → 1.9.3
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 +9 -0
- package/dist/index.js +479 -431
- package/dist/mcp/permission-server.js +74 -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()) {
|
|
@@ -61101,7 +61143,7 @@ function formatPullRequestLink(url, formatter) {
|
|
|
61101
61143
|
}
|
|
61102
61144
|
|
|
61103
61145
|
// src/operations/sticky-message/handler.ts
|
|
61104
|
-
var
|
|
61146
|
+
var log20 = createLogger("sticky");
|
|
61105
61147
|
var botStartedAt = new Date;
|
|
61106
61148
|
function getPendingPrompts(session) {
|
|
61107
61149
|
const prompts2 = [];
|
|
@@ -61176,21 +61218,21 @@ function initialize(store) {
|
|
|
61176
61218
|
stickyPostIds.set(platformId, postId);
|
|
61177
61219
|
}
|
|
61178
61220
|
if (persistedIds.size > 0) {
|
|
61179
|
-
|
|
61221
|
+
log20.info(`\uD83D\uDCCC Restored ${persistedIds.size} sticky post ID(s) from persistence`);
|
|
61180
61222
|
}
|
|
61181
61223
|
}
|
|
61182
61224
|
function setPlatformPaused(platformId, paused) {
|
|
61183
61225
|
if (paused) {
|
|
61184
61226
|
pausedPlatforms.set(platformId, true);
|
|
61185
|
-
|
|
61227
|
+
log20.debug(`Platform ${platformId} marked as paused`);
|
|
61186
61228
|
} else {
|
|
61187
61229
|
pausedPlatforms.delete(platformId);
|
|
61188
|
-
|
|
61230
|
+
log20.debug(`Platform ${platformId} marked as active`);
|
|
61189
61231
|
}
|
|
61190
61232
|
}
|
|
61191
61233
|
function setShuttingDown(shuttingDown) {
|
|
61192
61234
|
isShuttingDown = shuttingDown;
|
|
61193
|
-
|
|
61235
|
+
log20.debug(`Bot shutdown state: ${shuttingDown}`);
|
|
61194
61236
|
}
|
|
61195
61237
|
function getTaskContent(session) {
|
|
61196
61238
|
const taskState = session.messageManager?.getTaskListState();
|
|
@@ -61501,12 +61543,12 @@ async function validateLastMessageIds(platform, sessions) {
|
|
|
61501
61543
|
try {
|
|
61502
61544
|
const post2 = await platform.getPost(lastMessageId);
|
|
61503
61545
|
if (!post2) {
|
|
61504
|
-
|
|
61546
|
+
log20.debug(`lastMessageId ${lastMessageId.substring(0, 8)} for session ${session.sessionId} was deleted, clearing`);
|
|
61505
61547
|
session.lastMessageId = undefined;
|
|
61506
61548
|
session.lastMessageTs = undefined;
|
|
61507
61549
|
}
|
|
61508
61550
|
} catch (err) {
|
|
61509
|
-
|
|
61551
|
+
log20.debug(`Failed to validate lastMessageId for session ${session.sessionId}, clearing: ${err}`);
|
|
61510
61552
|
session.lastMessageId = undefined;
|
|
61511
61553
|
session.lastMessageTs = undefined;
|
|
61512
61554
|
}
|
|
@@ -61515,63 +61557,63 @@ async function validateLastMessageIds(platform, sessions) {
|
|
|
61515
61557
|
}
|
|
61516
61558
|
async function updateStickyMessageImpl(platform, sessions, config) {
|
|
61517
61559
|
const platformSessions = [...sessions.values()].filter((s) => s.platformId === platform.platformId);
|
|
61518
|
-
|
|
61560
|
+
log20.debug(`updateStickyMessage for ${platform.platformId}, ${platformSessions.length} sessions`);
|
|
61519
61561
|
for (const s of platformSessions) {
|
|
61520
|
-
|
|
61562
|
+
log20.debug(` - ${s.sessionId}: title="${s.sessionTitle}" firstPrompt="${s.firstPrompt?.substring(0, 30)}..."`);
|
|
61521
61563
|
}
|
|
61522
61564
|
await validateLastMessageIds(platform, platformSessions);
|
|
61523
61565
|
const formatter = platform.getFormatter();
|
|
61524
61566
|
const content = await buildStickyMessage(sessions, platform.platformId, config, formatter, (threadId) => platform.getThreadLink(threadId));
|
|
61525
61567
|
const existingPostId = stickyPostIds.get(platform.platformId);
|
|
61526
61568
|
const shouldBump = needsBump.get(platform.platformId) ?? false;
|
|
61527
|
-
|
|
61569
|
+
log20.debug(`existingPostId: ${existingPostId || "(none)"}, needsBump: ${shouldBump}`);
|
|
61528
61570
|
try {
|
|
61529
61571
|
if (existingPostId && !shouldBump) {
|
|
61530
|
-
|
|
61572
|
+
log20.debug(`Updating existing post in place...`);
|
|
61531
61573
|
try {
|
|
61532
61574
|
await platform.updatePost(existingPostId, content);
|
|
61533
61575
|
try {
|
|
61534
61576
|
await platform.pinPost(existingPostId);
|
|
61535
|
-
|
|
61577
|
+
log20.debug(`Re-pinned post`);
|
|
61536
61578
|
} catch (pinErr) {
|
|
61537
|
-
|
|
61579
|
+
log20.debug(`Re-pin failed (might already be pinned): ${pinErr}`);
|
|
61538
61580
|
}
|
|
61539
|
-
|
|
61581
|
+
log20.debug(`Updated successfully`);
|
|
61540
61582
|
return;
|
|
61541
61583
|
} catch (err) {
|
|
61542
|
-
|
|
61584
|
+
log20.debug(`Update failed, will create new: ${err}`);
|
|
61543
61585
|
}
|
|
61544
61586
|
}
|
|
61545
61587
|
needsBump.set(platform.platformId, false);
|
|
61546
61588
|
if (existingPostId) {
|
|
61547
|
-
|
|
61589
|
+
log20.debug(`Unpinning and deleting existing post ${existingPostId.substring(0, 8)}...`);
|
|
61548
61590
|
try {
|
|
61549
61591
|
await platform.unpinPost(existingPostId);
|
|
61550
|
-
|
|
61592
|
+
log20.debug(`Unpinned successfully`);
|
|
61551
61593
|
} catch (err) {
|
|
61552
|
-
|
|
61594
|
+
log20.debug(`Unpin failed (probably already unpinned): ${err}`);
|
|
61553
61595
|
}
|
|
61554
61596
|
try {
|
|
61555
61597
|
await platform.deletePost(existingPostId);
|
|
61556
|
-
|
|
61598
|
+
log20.debug(`Deleted successfully`);
|
|
61557
61599
|
} catch (err) {
|
|
61558
|
-
|
|
61600
|
+
log20.debug(`Delete failed (probably already deleted): ${err}`);
|
|
61559
61601
|
}
|
|
61560
61602
|
stickyPostIds.delete(platform.platformId);
|
|
61561
61603
|
}
|
|
61562
|
-
|
|
61604
|
+
log20.debug(`Creating new post...`);
|
|
61563
61605
|
const post2 = await platform.createPost(content);
|
|
61564
61606
|
stickyPostIds.set(platform.platformId, post2.id);
|
|
61565
61607
|
try {
|
|
61566
61608
|
await platform.pinPost(post2.id);
|
|
61567
|
-
|
|
61609
|
+
log20.debug(`Pinned post successfully`);
|
|
61568
61610
|
} catch (err) {
|
|
61569
|
-
|
|
61611
|
+
log20.debug(`Failed to pin post: ${err}`);
|
|
61570
61612
|
}
|
|
61571
61613
|
if (sessionStore) {
|
|
61572
61614
|
sessionStore.saveStickyPostId(platform.platformId, post2.id);
|
|
61573
61615
|
}
|
|
61574
|
-
|
|
61616
|
+
log20.info(`\uD83D\uDCCC Created sticky message for ${platform.platformId}: ${formatShortId(post2.id)}`);
|
|
61575
61617
|
const excludePostIds = new Set;
|
|
61576
61618
|
if (sessionStore) {
|
|
61577
61619
|
for (const session of sessionStore.load().values()) {
|
|
@@ -61587,10 +61629,10 @@ async function updateStickyMessageImpl(platform, sessions, config) {
|
|
|
61587
61629
|
}
|
|
61588
61630
|
const botUser = await platform.getBotUser();
|
|
61589
61631
|
cleanupOldStickyMessages(platform, botUser.id, false, excludePostIds).catch((err) => {
|
|
61590
|
-
|
|
61632
|
+
log20.debug(`Background cleanup failed: ${err}`);
|
|
61591
61633
|
});
|
|
61592
61634
|
} catch (err) {
|
|
61593
|
-
|
|
61635
|
+
log20.error(`Failed to update sticky message for ${platform.platformId}`, err instanceof Error ? err : undefined);
|
|
61594
61636
|
}
|
|
61595
61637
|
}
|
|
61596
61638
|
async function updateAllStickyMessages(platforms, sessions, config) {
|
|
@@ -61615,7 +61657,7 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
|
|
|
61615
61657
|
if (!forceRun) {
|
|
61616
61658
|
const lastRun = lastCleanupTime.get(platformId) || 0;
|
|
61617
61659
|
if (now - lastRun < CLEANUP_THROTTLE_MS) {
|
|
61618
|
-
|
|
61660
|
+
log20.debug(`Cleanup throttled for ${platformId} (last run ${Math.round((now - lastRun) / 1000)}s ago)`);
|
|
61619
61661
|
return;
|
|
61620
61662
|
}
|
|
61621
61663
|
}
|
|
@@ -61625,31 +61667,31 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
|
|
|
61625
61667
|
const pinnedPostIds = await platform.getPinnedPosts();
|
|
61626
61668
|
const recentPinnedIds = pinnedPostIds.filter((id) => id !== currentStickyId && !excludePostIds?.has(id) && isRecentPost(id));
|
|
61627
61669
|
if (recentPinnedIds.length === 0) {
|
|
61628
|
-
|
|
61670
|
+
log20.debug(`No recent pinned posts to check (${pinnedPostIds.length} total, current: ${currentStickyId?.substring(0, 8) || "(none)"})`);
|
|
61629
61671
|
return;
|
|
61630
61672
|
}
|
|
61631
|
-
|
|
61673
|
+
log20.debug(`Checking ${recentPinnedIds.length} recent pinned posts (of ${pinnedPostIds.length} total)`);
|
|
61632
61674
|
for (const postId of recentPinnedIds) {
|
|
61633
61675
|
try {
|
|
61634
61676
|
const post2 = await platform.getPost(postId);
|
|
61635
61677
|
if (!post2)
|
|
61636
61678
|
continue;
|
|
61637
61679
|
if (post2.userId === botUserId) {
|
|
61638
|
-
|
|
61680
|
+
log20.debug(`Cleaning up old sticky: ${postId.substring(0, 8)}...`);
|
|
61639
61681
|
try {
|
|
61640
61682
|
await platform.unpinPost(postId);
|
|
61641
61683
|
await platform.deletePost(postId);
|
|
61642
|
-
|
|
61684
|
+
log20.info(`\uD83E\uDDF9 Cleaned up old sticky message: ${postId.substring(0, 8)}...`);
|
|
61643
61685
|
} catch (err) {
|
|
61644
|
-
|
|
61686
|
+
log20.debug(`Failed to cleanup ${postId}: ${err}`);
|
|
61645
61687
|
}
|
|
61646
61688
|
}
|
|
61647
61689
|
} catch (err) {
|
|
61648
|
-
|
|
61690
|
+
log20.debug(`Could not check post ${postId}: ${err}`);
|
|
61649
61691
|
}
|
|
61650
61692
|
}
|
|
61651
61693
|
} catch (err) {
|
|
61652
|
-
|
|
61694
|
+
log20.error(`Failed to cleanup old sticky messages`, err instanceof Error ? err : undefined);
|
|
61653
61695
|
}
|
|
61654
61696
|
}
|
|
61655
61697
|
// src/operations/bug-report/handler.ts
|
|
@@ -65712,8 +65754,8 @@ function getUpdateInfo() {
|
|
|
65712
65754
|
init_emoji();
|
|
65713
65755
|
init_logger();
|
|
65714
65756
|
init_worktree();
|
|
65715
|
-
var
|
|
65716
|
-
var sessionLog2 = createSessionLog(
|
|
65757
|
+
var log21 = createLogger("commands");
|
|
65758
|
+
var sessionLog2 = createSessionLog(log21);
|
|
65717
65759
|
function sessionAccountOption(session, ctx) {
|
|
65718
65760
|
if (!session.claudeAccountId)
|
|
65719
65761
|
return;
|
|
@@ -66247,7 +66289,7 @@ init_logger();
|
|
|
66247
66289
|
import { exec as exec3 } from "child_process";
|
|
66248
66290
|
import { promisify as promisify3 } from "util";
|
|
66249
66291
|
var execAsync2 = promisify3(exec3);
|
|
66250
|
-
var
|
|
66292
|
+
var log22 = createLogger("branch");
|
|
66251
66293
|
var SUGGESTION_TIMEOUT3 = 15000;
|
|
66252
66294
|
var MAX_SUGGESTIONS = 3;
|
|
66253
66295
|
async function getCurrentBranch3(workingDir) {
|
|
@@ -66296,7 +66338,7 @@ function parseBranchSuggestions(response) {
|
|
|
66296
66338
|
return lines.slice(0, MAX_SUGGESTIONS);
|
|
66297
66339
|
}
|
|
66298
66340
|
async function suggestBranchNames(workingDir, userMessage) {
|
|
66299
|
-
|
|
66341
|
+
log22.debug(`Suggesting branch names for: "${userMessage.substring(0, 50)}..."`);
|
|
66300
66342
|
try {
|
|
66301
66343
|
const [currentBranch, recentCommits] = await Promise.all([
|
|
66302
66344
|
getCurrentBranch3(workingDir),
|
|
@@ -66310,14 +66352,14 @@ async function suggestBranchNames(workingDir, userMessage) {
|
|
|
66310
66352
|
workingDir
|
|
66311
66353
|
});
|
|
66312
66354
|
if (!result.success || !result.response) {
|
|
66313
|
-
|
|
66355
|
+
log22.debug(`Branch suggestion failed: ${result.error || "no response"}`);
|
|
66314
66356
|
return [];
|
|
66315
66357
|
}
|
|
66316
66358
|
const suggestions = parseBranchSuggestions(result.response);
|
|
66317
|
-
|
|
66359
|
+
log22.debug(`Got ${suggestions.length} branch suggestions: ${suggestions.join(", ")}`);
|
|
66318
66360
|
return suggestions;
|
|
66319
66361
|
} catch (err) {
|
|
66320
|
-
|
|
66362
|
+
log22.debug(`Branch suggestion error: ${err}`);
|
|
66321
66363
|
return [];
|
|
66322
66364
|
}
|
|
66323
66365
|
}
|
|
@@ -66326,8 +66368,8 @@ async function suggestBranchNames(workingDir, userMessage) {
|
|
|
66326
66368
|
init_worktree();
|
|
66327
66369
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
66328
66370
|
init_logger();
|
|
66329
|
-
var
|
|
66330
|
-
var sessionLog3 = createSessionLog(
|
|
66371
|
+
var log23 = createLogger("worktree");
|
|
66372
|
+
var sessionLog3 = createSessionLog(log23);
|
|
66331
66373
|
function parseWorktreeError(error) {
|
|
66332
66374
|
const message = error instanceof Error ? error.message : String(error);
|
|
66333
66375
|
const lowerMessage = message.toLowerCase();
|
|
@@ -66895,8 +66937,8 @@ async function cleanupWorktreeCommand(session, username, hasOtherSessionsUsingWo
|
|
|
66895
66937
|
}
|
|
66896
66938
|
// src/operations/events/handler.ts
|
|
66897
66939
|
init_logger();
|
|
66898
|
-
var
|
|
66899
|
-
var sessionLog4 = createSessionLog(
|
|
66940
|
+
var log24 = createLogger("events");
|
|
66941
|
+
var sessionLog4 = createSessionLog(log24);
|
|
66900
66942
|
function detectAndExecuteClaudeCommands(text, session, ctx) {
|
|
66901
66943
|
const parsed = parseClaudeCommand(text);
|
|
66902
66944
|
if (parsed && isClaudeAllowedCommand(parsed.command)) {
|
|
@@ -67144,8 +67186,8 @@ function createSessionContext(config, state, ops) {
|
|
|
67144
67186
|
// src/operations/context-prompt/handler.ts
|
|
67145
67187
|
init_emoji();
|
|
67146
67188
|
init_logger();
|
|
67147
|
-
var
|
|
67148
|
-
var sessionLog5 = createSessionLog(
|
|
67189
|
+
var log25 = createLogger("context");
|
|
67190
|
+
var sessionLog5 = createSessionLog(log25);
|
|
67149
67191
|
var CONTEXT_PROMPT_TIMEOUT_MS = 30000;
|
|
67150
67192
|
var CONTEXT_OPTIONS = [3, 5, 10];
|
|
67151
67193
|
var contextPromptTimeouts = new Map;
|
|
@@ -67395,8 +67437,8 @@ function formatRelativeTime(date) {
|
|
|
67395
67437
|
}
|
|
67396
67438
|
// src/session/lifecycle.ts
|
|
67397
67439
|
init_worktree();
|
|
67398
|
-
var
|
|
67399
|
-
var sessionLog6 = createSessionLog(
|
|
67440
|
+
var log26 = createLogger("lifecycle");
|
|
67441
|
+
var sessionLog6 = createSessionLog(log26);
|
|
67400
67442
|
function mutableSessions(ctx) {
|
|
67401
67443
|
return ctx.state.sessions;
|
|
67402
67444
|
}
|
|
@@ -67781,17 +67823,17 @@ async function startSession(options2, username, displayName, replyToPostId, plat
|
|
|
67781
67823
|
return;
|
|
67782
67824
|
}
|
|
67783
67825
|
workingDir = resolvedDir;
|
|
67784
|
-
|
|
67826
|
+
log26.info(`Starting session in directory: ${workingDir} (from !cd command)`);
|
|
67785
67827
|
}
|
|
67786
67828
|
if (initialOptions?.permissionMode) {
|
|
67787
67829
|
permissionMode = initialOptions.permissionMode;
|
|
67788
67830
|
forceInteractivePermissions = permissionMode === "default";
|
|
67789
67831
|
sessionPermissionModeOverride = permissionMode;
|
|
67790
|
-
|
|
67832
|
+
log26.info(`Starting session with permission mode "${permissionMode}" (from !permissions command)`);
|
|
67791
67833
|
} else if (initialOptions?.forceInteractivePermissions) {
|
|
67792
67834
|
forceInteractivePermissions = true;
|
|
67793
67835
|
permissionMode = "default";
|
|
67794
|
-
|
|
67836
|
+
log26.info(`Starting session with interactive permissions (from !permissions command)`);
|
|
67795
67837
|
}
|
|
67796
67838
|
const sessionContext = buildSessionContext(platform, workingDir);
|
|
67797
67839
|
const systemPrompt = `${sessionContext}
|
|
@@ -67800,7 +67842,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
67800
67842
|
const platformMcpConfig = platform.getMcpConfig();
|
|
67801
67843
|
const claudeAccount = ctx.ops.acquireClaudeAccount();
|
|
67802
67844
|
if (claudeAccount) {
|
|
67803
|
-
|
|
67845
|
+
log26.info(`Session ${sessionId.substring(0, 20)} reserved Claude account "${claudeAccount.id}"`);
|
|
67804
67846
|
}
|
|
67805
67847
|
const cliOptions = {
|
|
67806
67848
|
workingDir,
|
|
@@ -67905,28 +67947,28 @@ async function resumeSession(state, ctx) {
|
|
|
67905
67947
|
!state.claudeSessionId && "claudeSessionId",
|
|
67906
67948
|
!state.workingDir && "workingDir"
|
|
67907
67949
|
].filter(Boolean).join(", ");
|
|
67908
|
-
|
|
67950
|
+
log26.warn(`Skipping session with missing required fields: ${missing}`);
|
|
67909
67951
|
return;
|
|
67910
67952
|
}
|
|
67911
67953
|
const shortId = state.threadId.substring(0, 8);
|
|
67912
67954
|
const platforms = ctx.state.platforms;
|
|
67913
67955
|
const platform = platforms.get(state.platformId);
|
|
67914
67956
|
if (!platform) {
|
|
67915
|
-
|
|
67957
|
+
log26.warn(`Platform ${state.platformId} not registered, skipping resume for ${shortId}...`);
|
|
67916
67958
|
return;
|
|
67917
67959
|
}
|
|
67918
67960
|
const threadPost = await platform.getPost(state.threadId);
|
|
67919
67961
|
if (!threadPost) {
|
|
67920
|
-
|
|
67962
|
+
log26.warn(`Thread ${shortId}... deleted, skipping resume`);
|
|
67921
67963
|
ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
|
|
67922
67964
|
return;
|
|
67923
67965
|
}
|
|
67924
67966
|
if (ctx.state.sessions.size >= ctx.config.maxSessions) {
|
|
67925
|
-
|
|
67967
|
+
log26.warn(`Max sessions reached, skipping resume for ${shortId}...`);
|
|
67926
67968
|
return;
|
|
67927
67969
|
}
|
|
67928
67970
|
if (!existsSync11(state.workingDir)) {
|
|
67929
|
-
|
|
67971
|
+
log26.warn(`Working directory ${state.workingDir} no longer exists, skipping resume for ${shortId}...`);
|
|
67930
67972
|
ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
|
|
67931
67973
|
const resumeFormatter = platform.getFormatter();
|
|
67932
67974
|
const tempSession = {
|
|
@@ -67950,7 +67992,7 @@ Please start a new session.`), { action: "Post resume failure notification" });
|
|
|
67950
67992
|
${CHAT_PLATFORM_PROMPT}`;
|
|
67951
67993
|
const claudeAccount = ctx.ops.acquireClaudeAccount(state.claudeAccountId);
|
|
67952
67994
|
if (state.claudeAccountId && !claudeAccount) {
|
|
67953
|
-
|
|
67995
|
+
log26.warn(`Persisted session referenced Claude account "${state.claudeAccountId}" ` + `which is no longer configured — resuming under default env`);
|
|
67954
67996
|
}
|
|
67955
67997
|
const cliOptions = {
|
|
67956
67998
|
workingDir: state.workingDir,
|
|
@@ -68015,7 +68057,7 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
68015
68057
|
worktreePath: detected.worktreePath,
|
|
68016
68058
|
branch: detected.branch
|
|
68017
68059
|
};
|
|
68018
|
-
|
|
68060
|
+
log26.info(`Auto-detected worktree info for resumed session: branch=${detected.branch}`);
|
|
68019
68061
|
}
|
|
68020
68062
|
}
|
|
68021
68063
|
session.messageManager = createMessageManager(session, ctx);
|
|
@@ -68071,7 +68113,7 @@ ${sessionFormatter.formatItalic("Reconnected to Claude session. You can continue
|
|
|
68071
68113
|
await ctx.ops.updateStickyMessage();
|
|
68072
68114
|
ctx.ops.persistSession(session);
|
|
68073
68115
|
} catch (err) {
|
|
68074
|
-
|
|
68116
|
+
log26.error(`Failed to resume session ${shortId}`, err instanceof Error ? err : undefined);
|
|
68075
68117
|
ctx.ops.emitSessionRemove(sessionId);
|
|
68076
68118
|
mutableSessions(ctx).delete(sessionId);
|
|
68077
68119
|
ctx.state.sessionStore.remove(sessionId);
|
|
@@ -68111,18 +68153,18 @@ async function resumePausedSession(threadId, message, files, ctx) {
|
|
|
68111
68153
|
const persisted = ctx.state.sessionStore.load();
|
|
68112
68154
|
const state = findPersistedByThreadId(persisted, threadId);
|
|
68113
68155
|
if (!state) {
|
|
68114
|
-
|
|
68156
|
+
log26.debug(`No persisted session found for ${threadId.substring(0, 8)}...`);
|
|
68115
68157
|
return;
|
|
68116
68158
|
}
|
|
68117
68159
|
const shortId = threadId.substring(0, 8);
|
|
68118
|
-
|
|
68160
|
+
log26.info(`\uD83D\uDD04 Resuming paused session ${shortId}... for new message`);
|
|
68119
68161
|
await resumeSession(state, ctx);
|
|
68120
68162
|
const session = ctx.ops.findSessionByThreadId(threadId);
|
|
68121
68163
|
if (session && session.claude.isRunning() && session.messageManager) {
|
|
68122
68164
|
session.messageCount++;
|
|
68123
68165
|
await session.messageManager.handleUserMessage(message, files, state.startedBy);
|
|
68124
68166
|
} else {
|
|
68125
|
-
|
|
68167
|
+
log26.warn(`Failed to resume session ${shortId}..., could not send message`);
|
|
68126
68168
|
}
|
|
68127
68169
|
}
|
|
68128
68170
|
async function handleExit(sessionId, code, ctx) {
|
|
@@ -68130,7 +68172,7 @@ async function handleExit(sessionId, code, ctx) {
|
|
|
68130
68172
|
const shortId = sessionId.substring(0, 8);
|
|
68131
68173
|
sessionLog6(session).debug(`handleExit called code=${code} isShuttingDown=${ctx.state.isShuttingDown}`);
|
|
68132
68174
|
if (!session) {
|
|
68133
|
-
|
|
68175
|
+
log26.debug(`Session ${shortId}... not found (already cleaned up)`);
|
|
68134
68176
|
return;
|
|
68135
68177
|
}
|
|
68136
68178
|
if (isSessionRestarting(session)) {
|
|
@@ -68323,7 +68365,7 @@ async function cleanupIdleSessions(timeoutMs, warningMs, ctx) {
|
|
|
68323
68365
|
}
|
|
68324
68366
|
|
|
68325
68367
|
// src/operations/monitor/handler.ts
|
|
68326
|
-
var
|
|
68368
|
+
var log27 = createLogger("monitor");
|
|
68327
68369
|
var DEFAULT_INTERVAL_MS = 60 * 1000;
|
|
68328
68370
|
|
|
68329
68371
|
class SessionMonitor {
|
|
@@ -68345,14 +68387,14 @@ class SessionMonitor {
|
|
|
68345
68387
|
}
|
|
68346
68388
|
start() {
|
|
68347
68389
|
if (this.isRunning) {
|
|
68348
|
-
|
|
68390
|
+
log27.debug("Session monitor already running");
|
|
68349
68391
|
return;
|
|
68350
68392
|
}
|
|
68351
68393
|
this.isRunning = true;
|
|
68352
|
-
|
|
68394
|
+
log27.debug(`Session monitor started (interval: ${this.intervalMs / 1000}s)`);
|
|
68353
68395
|
this.timer = setInterval(() => {
|
|
68354
68396
|
this.runCheck().catch((err) => {
|
|
68355
|
-
|
|
68397
|
+
log27.error(`Error during session monitoring: ${err}`);
|
|
68356
68398
|
});
|
|
68357
68399
|
}, this.intervalMs);
|
|
68358
68400
|
}
|
|
@@ -68362,7 +68404,7 @@ class SessionMonitor {
|
|
|
68362
68404
|
this.timer = null;
|
|
68363
68405
|
}
|
|
68364
68406
|
this.isRunning = false;
|
|
68365
|
-
|
|
68407
|
+
log27.debug("Session monitor stopped");
|
|
68366
68408
|
}
|
|
68367
68409
|
async runCheck() {
|
|
68368
68410
|
await cleanupIdleSessions(this.sessionTimeoutMs, this.sessionWarningMs, this.getContext());
|
|
@@ -68374,8 +68416,8 @@ class SessionMonitor {
|
|
|
68374
68416
|
// src/operations/plugin/handler.ts
|
|
68375
68417
|
init_spawn();
|
|
68376
68418
|
init_logger();
|
|
68377
|
-
var
|
|
68378
|
-
var sessionLog7 = createSessionLog(
|
|
68419
|
+
var log28 = createLogger("plugin");
|
|
68420
|
+
var sessionLog7 = createSessionLog(log28);
|
|
68379
68421
|
async function runPluginCommand(args, cwd, timeout2 = 60000) {
|
|
68380
68422
|
return new Promise((resolve6) => {
|
|
68381
68423
|
const claudePath = process.env.CLAUDE_PATH || "claude";
|
|
@@ -68396,7 +68438,7 @@ async function runPluginCommand(args, cwd, timeout2 = 60000) {
|
|
|
68396
68438
|
});
|
|
68397
68439
|
proc.on("error", (err) => {
|
|
68398
68440
|
resolve6({ stdout, stderr, exitCode: 1 });
|
|
68399
|
-
|
|
68441
|
+
log28.error(`Plugin command error: ${err.message}`);
|
|
68400
68442
|
});
|
|
68401
68443
|
});
|
|
68402
68444
|
}
|
|
@@ -68595,9 +68637,105 @@ class SessionRegistry {
|
|
|
68595
68637
|
}
|
|
68596
68638
|
}
|
|
68597
68639
|
|
|
68640
|
+
// src/session/reaction-router.ts
|
|
68641
|
+
init_emoji();
|
|
68642
|
+
init_logger();
|
|
68643
|
+
var log29 = createLogger("manager");
|
|
68644
|
+
async function handleReaction(deps, platformId, postId, emojiName, username, action) {
|
|
68645
|
+
const normalizedEmoji = normalizeEmojiName(emojiName);
|
|
68646
|
+
if (action === "added" && isResumeEmoji(normalizedEmoji)) {
|
|
68647
|
+
const resumed = await tryResumeFromReaction(deps, platformId, postId, username);
|
|
68648
|
+
if (resumed)
|
|
68649
|
+
return;
|
|
68650
|
+
}
|
|
68651
|
+
const session = deps.registry.findByPost(postId);
|
|
68652
|
+
if (!session)
|
|
68653
|
+
return;
|
|
68654
|
+
if (session.platformId !== platformId)
|
|
68655
|
+
return;
|
|
68656
|
+
if (!session.sessionAllowedUsers.has(username) && !session.platform.isUserAllowed(username)) {
|
|
68657
|
+
log29.info(`\uD83D\uDEAB rejected reaction from unauthorized user`, {
|
|
68658
|
+
event: "reaction.rejected",
|
|
68659
|
+
platformId,
|
|
68660
|
+
sessionId: session.sessionId,
|
|
68661
|
+
postId,
|
|
68662
|
+
emoji: normalizedEmoji,
|
|
68663
|
+
action,
|
|
68664
|
+
user: username
|
|
68665
|
+
});
|
|
68666
|
+
return;
|
|
68667
|
+
}
|
|
68668
|
+
await dispatch(deps, session, postId, normalizedEmoji, username, action);
|
|
68669
|
+
}
|
|
68670
|
+
async function tryResumeFromReaction(deps, platformId, postId, username) {
|
|
68671
|
+
const persistedSession = deps.sessionStore.findByPostId(platformId, postId);
|
|
68672
|
+
if (!persistedSession)
|
|
68673
|
+
return false;
|
|
68674
|
+
const sessionId = `${platformId}:${persistedSession.threadId}`;
|
|
68675
|
+
if (deps.registry.hasById(sessionId))
|
|
68676
|
+
return false;
|
|
68677
|
+
const allowedUsers = new Set(persistedSession.sessionAllowedUsers);
|
|
68678
|
+
const platform = deps.platforms.get(platformId);
|
|
68679
|
+
if (!allowedUsers.has(username) && !platform?.isUserAllowed(username)) {
|
|
68680
|
+
if (platform) {
|
|
68681
|
+
await platform.createPost(`⚠️ @${username} is not authorized to resume this session`, persistedSession.threadId);
|
|
68682
|
+
}
|
|
68683
|
+
return false;
|
|
68684
|
+
}
|
|
68685
|
+
if (deps.registry.size >= deps.limits.maxSessions) {
|
|
68686
|
+
if (platform) {
|
|
68687
|
+
const fmt = platform.getFormatter();
|
|
68688
|
+
await platform.createPost(`⚠️ ${fmt.formatBold("Too busy")} - ${deps.registry.size} sessions active. Please try again later.`, persistedSession.threadId);
|
|
68689
|
+
}
|
|
68690
|
+
return false;
|
|
68691
|
+
}
|
|
68692
|
+
const shortId = persistedSession.threadId.substring(0, 8);
|
|
68693
|
+
log29.info(`\uD83D\uDD04 Resuming session ${shortId}... via emoji reaction by @${username}`);
|
|
68694
|
+
await resumeSession(persistedSession, deps.getContext());
|
|
68695
|
+
return true;
|
|
68696
|
+
}
|
|
68697
|
+
async function dispatch(deps, session, postId, emojiName, username, action) {
|
|
68698
|
+
if (action === "added") {
|
|
68699
|
+
if (session.sessionStartPostId === postId) {
|
|
68700
|
+
if (isCancelEmoji(emojiName)) {
|
|
68701
|
+
await cancelSession(session, username, deps.getContext());
|
|
68702
|
+
return;
|
|
68703
|
+
}
|
|
68704
|
+
if (isEscapeEmoji(emojiName)) {
|
|
68705
|
+
await interruptSession(session, username);
|
|
68706
|
+
return;
|
|
68707
|
+
}
|
|
68708
|
+
}
|
|
68709
|
+
if (session.worktreePromptPostId === postId && emojiName === "x") {
|
|
68710
|
+
await handleWorktreeSkip(session, username, (s) => deps.persistSession(s), (s, q) => offerContextPrompt(s, q, undefined, deps.getContextPromptHandler()));
|
|
68711
|
+
return;
|
|
68712
|
+
}
|
|
68713
|
+
if (session.pendingWorktreeSuggestions?.postId === postId) {
|
|
68714
|
+
const emojiIndex = getNumberEmojiIndex(emojiName);
|
|
68715
|
+
if (emojiIndex >= 0) {
|
|
68716
|
+
const handled = await handleBranchSuggestionReaction(session, postId, emojiIndex, username, (tid, branch, user) => deps.createAndSwitchToWorktree(tid, branch, user));
|
|
68717
|
+
if (handled)
|
|
68718
|
+
return;
|
|
68719
|
+
}
|
|
68720
|
+
}
|
|
68721
|
+
if (session.lastError?.postId === postId && isBugReportEmoji(emojiName)) {
|
|
68722
|
+
if (session.startedBy === username || session.platform.isUserAllowed(username) || session.sessionAllowedUsers.has(username)) {
|
|
68723
|
+
log29.info(`\uD83D\uDC1B @${username} triggered bug report from error reaction`);
|
|
68724
|
+
await reportBug(session, undefined, username, deps.getContext(), session.lastError);
|
|
68725
|
+
return;
|
|
68726
|
+
}
|
|
68727
|
+
}
|
|
68728
|
+
}
|
|
68729
|
+
if (session.messageManager) {
|
|
68730
|
+
const handled = await session.messageManager.handleReaction(postId, emojiName, username, action);
|
|
68731
|
+
if (handled)
|
|
68732
|
+
return;
|
|
68733
|
+
}
|
|
68734
|
+
}
|
|
68735
|
+
|
|
68598
68736
|
// src/session/manager.ts
|
|
68599
68737
|
init_logger();
|
|
68600
|
-
var
|
|
68738
|
+
var log30 = createLogger("manager");
|
|
68601
68739
|
|
|
68602
68740
|
class SessionManager extends EventEmitter4 {
|
|
68603
68741
|
platforms = new Map;
|
|
@@ -68666,7 +68804,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
68666
68804
|
markNeedsBump(platformId);
|
|
68667
68805
|
this.updateStickyMessage();
|
|
68668
68806
|
});
|
|
68669
|
-
|
|
68807
|
+
log30.info(`\uD83D\uDCE1 Platform "${platformId}" registered`);
|
|
68670
68808
|
}
|
|
68671
68809
|
removePlatform(platformId) {
|
|
68672
68810
|
this.platforms.delete(platformId);
|
|
@@ -68682,7 +68820,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
68682
68820
|
if (users) {
|
|
68683
68821
|
users.add(sessionId);
|
|
68684
68822
|
}
|
|
68685
|
-
|
|
68823
|
+
log30.debug(`Registered session ${sessionId.substring(0, 20)} as worktree user for ${worktreePath}`);
|
|
68686
68824
|
}
|
|
68687
68825
|
unregisterWorktreeUser(worktreePath, sessionId) {
|
|
68688
68826
|
const users = this.worktreeUsers.get(worktreePath);
|
|
@@ -68796,95 +68934,19 @@ class SessionManager extends EventEmitter4 {
|
|
|
68796
68934
|
}
|
|
68797
68935
|
async handleMessage(_platformId, _post, _user) {}
|
|
68798
68936
|
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;
|
|
68937
|
+
await handleReaction(this.getReactionRouterDeps(), platformId, postId, emojiName, username, action);
|
|
68850
68938
|
}
|
|
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
|
-
}
|
|
68939
|
+
getReactionRouterDeps() {
|
|
68940
|
+
return {
|
|
68941
|
+
registry: this.registry,
|
|
68942
|
+
sessionStore: this.sessionStore,
|
|
68943
|
+
platforms: this.platforms,
|
|
68944
|
+
limits: this.limits,
|
|
68945
|
+
getContext: () => this.getContext(),
|
|
68946
|
+
getContextPromptHandler: () => this.getContextPromptHandler(),
|
|
68947
|
+
persistSession: (s) => this.persistSession(s),
|
|
68948
|
+
createAndSwitchToWorktree: (tid, branch, user) => this.createAndSwitchToWorktree(tid, branch, user)
|
|
68949
|
+
};
|
|
68888
68950
|
}
|
|
68889
68951
|
getContextPromptHandler() {
|
|
68890
68952
|
return {
|
|
@@ -68943,28 +69005,14 @@ class SessionManager extends EventEmitter4 {
|
|
|
68943
69005
|
this.stopTyping(session);
|
|
68944
69006
|
}
|
|
68945
69007
|
persistSession(session) {
|
|
68946
|
-
const useSerializeV2 = process.env.CLAUDE_THREADS_SERIALIZE_V2 !== "0";
|
|
68947
69008
|
let taskListSnapshot;
|
|
68948
69009
|
let contextPromptSnapshot;
|
|
68949
|
-
if (
|
|
69010
|
+
if (session.messageManager) {
|
|
68950
69011
|
const serialized = session.messageManager.serialize();
|
|
68951
69012
|
taskListSnapshot = serialized.taskList;
|
|
68952
69013
|
if (serialized.contextPrompt) {
|
|
68953
69014
|
contextPromptSnapshot = serialized.contextPrompt;
|
|
68954
69015
|
}
|
|
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
69016
|
}
|
|
68969
69017
|
const state = {
|
|
68970
69018
|
platformId: session.platformId,
|
|
@@ -69058,11 +69106,11 @@ class SessionManager extends EventEmitter4 {
|
|
|
69058
69106
|
}
|
|
69059
69107
|
}
|
|
69060
69108
|
if (sessionsToKill.length === 0) {
|
|
69061
|
-
|
|
69109
|
+
log30.info(`No active sessions to pause for platform ${platformId}`);
|
|
69062
69110
|
await this.updateStickyMessage();
|
|
69063
69111
|
return;
|
|
69064
69112
|
}
|
|
69065
|
-
|
|
69113
|
+
log30.info(`⏸️ Pausing ${sessionsToKill.length} session(s) for platform ${platformId}`);
|
|
69066
69114
|
for (const session of sessionsToKill) {
|
|
69067
69115
|
try {
|
|
69068
69116
|
const fmt = session.platform.getFormatter();
|
|
@@ -69078,9 +69126,9 @@ class SessionManager extends EventEmitter4 {
|
|
|
69078
69126
|
session.claude.kill();
|
|
69079
69127
|
this.registry.unregister(session.sessionId);
|
|
69080
69128
|
this.emitSessionRemove(session.sessionId);
|
|
69081
|
-
|
|
69129
|
+
log30.info(`⏸️ Paused session ${session.threadId.substring(0, 8)}`);
|
|
69082
69130
|
} catch (err) {
|
|
69083
|
-
|
|
69131
|
+
log30.warn(`Failed to pause session ${session.threadId}: ${err}`);
|
|
69084
69132
|
}
|
|
69085
69133
|
}
|
|
69086
69134
|
for (const session of sessionsToKill) {
|
|
@@ -69101,17 +69149,17 @@ class SessionManager extends EventEmitter4 {
|
|
|
69101
69149
|
sessionsToResume.push(state);
|
|
69102
69150
|
}
|
|
69103
69151
|
if (sessionsToResume.length === 0) {
|
|
69104
|
-
|
|
69152
|
+
log30.info(`No paused sessions to resume for platform ${platformId}`);
|
|
69105
69153
|
await this.updateStickyMessage();
|
|
69106
69154
|
return;
|
|
69107
69155
|
}
|
|
69108
|
-
|
|
69156
|
+
log30.info(`▶️ Resuming ${sessionsToResume.length} paused session(s) for platform ${platformId}`);
|
|
69109
69157
|
for (const state of sessionsToResume) {
|
|
69110
69158
|
try {
|
|
69111
69159
|
await resumeSession(state, this.getContext());
|
|
69112
|
-
|
|
69160
|
+
log30.info(`▶️ Resumed session ${state.threadId.substring(0, 8)}`);
|
|
69113
69161
|
} catch (err) {
|
|
69114
|
-
|
|
69162
|
+
log30.warn(`Failed to resume session ${state.threadId}: ${err}`);
|
|
69115
69163
|
}
|
|
69116
69164
|
}
|
|
69117
69165
|
await this.updateStickyMessage();
|
|
@@ -69123,14 +69171,14 @@ class SessionManager extends EventEmitter4 {
|
|
|
69123
69171
|
const sessionTimeoutMs = this.limits.sessionTimeoutMinutes * 60 * 1000;
|
|
69124
69172
|
const staleIds = this.sessionStore.cleanStale(sessionTimeoutMs * 2);
|
|
69125
69173
|
if (staleIds.length > 0) {
|
|
69126
|
-
|
|
69174
|
+
log30.info(`\uD83E\uDDF9 Soft-deleted ${staleIds.length} stale session(s) (kept for history)`);
|
|
69127
69175
|
}
|
|
69128
69176
|
const removedCount = this.sessionStore.cleanHistory();
|
|
69129
69177
|
if (removedCount > 0) {
|
|
69130
|
-
|
|
69178
|
+
log30.info(`\uD83D\uDDD1️ Permanently removed ${removedCount} old session(s) from history`);
|
|
69131
69179
|
}
|
|
69132
69180
|
const persisted = this.sessionStore.load();
|
|
69133
|
-
|
|
69181
|
+
log30.info(`\uD83D\uDCC2 Loaded ${persisted.size} session(s) from persistence`);
|
|
69134
69182
|
const excludePostIdsByPlatform = new Map;
|
|
69135
69183
|
for (const session of persisted.values()) {
|
|
69136
69184
|
const platformId = session.platformId;
|
|
@@ -69150,10 +69198,10 @@ class SessionManager extends EventEmitter4 {
|
|
|
69150
69198
|
const excludePostIds = excludePostIdsByPlatform.get(platform.platformId);
|
|
69151
69199
|
platform.getBotUser().then((botUser) => {
|
|
69152
69200
|
cleanupOldStickyMessages(platform, botUser.id, true, excludePostIds).catch((err) => {
|
|
69153
|
-
|
|
69201
|
+
log30.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
|
|
69154
69202
|
});
|
|
69155
69203
|
}).catch((err) => {
|
|
69156
|
-
|
|
69204
|
+
log30.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
|
|
69157
69205
|
});
|
|
69158
69206
|
}
|
|
69159
69207
|
if (persisted.size > 0) {
|
|
@@ -69167,10 +69215,10 @@ class SessionManager extends EventEmitter4 {
|
|
|
69167
69215
|
}
|
|
69168
69216
|
}
|
|
69169
69217
|
if (pausedToSkip.length > 0) {
|
|
69170
|
-
|
|
69218
|
+
log30.info(`⏸️ ${pausedToSkip.length} session(s) remain paused (waiting for user message)`);
|
|
69171
69219
|
}
|
|
69172
69220
|
if (activeToResume.length > 0) {
|
|
69173
|
-
|
|
69221
|
+
log30.info(`\uD83D\uDD04 Attempting to resume ${activeToResume.length} active session(s)...`);
|
|
69174
69222
|
for (const state of activeToResume) {
|
|
69175
69223
|
await resumeSession(state, this.getContext());
|
|
69176
69224
|
}
|
|
@@ -69595,7 +69643,7 @@ Mention me to start a session in this worktree.`, threadId);
|
|
|
69595
69643
|
const message = messageBuilder(formatter);
|
|
69596
69644
|
await post(session, "info", message);
|
|
69597
69645
|
} catch (err) {
|
|
69598
|
-
|
|
69646
|
+
log30.warn(`Failed to broadcast to session ${session.threadId}: ${err}`);
|
|
69599
69647
|
}
|
|
69600
69648
|
}
|
|
69601
69649
|
}
|
|
@@ -69614,7 +69662,7 @@ Mention me to start a session in this worktree.`, threadId);
|
|
|
69614
69662
|
session.messageManager?.setPendingUpdatePrompt({ postId: post2.id });
|
|
69615
69663
|
this.registerPost(post2.id, session.threadId);
|
|
69616
69664
|
} catch (err) {
|
|
69617
|
-
|
|
69665
|
+
log30.warn(`Failed to post ask message to ${threadId}: ${err}`);
|
|
69618
69666
|
}
|
|
69619
69667
|
}
|
|
69620
69668
|
}
|
|
@@ -77210,29 +77258,29 @@ function SessionLog({ logs, maxLines = 20 }) {
|
|
|
77210
77258
|
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
77211
77259
|
flexDirection: "column",
|
|
77212
77260
|
flexShrink: 0,
|
|
77213
|
-
children: displayLogs.map((
|
|
77261
|
+
children: displayLogs.map((log31) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
77214
77262
|
flexShrink: 0,
|
|
77215
77263
|
children: [
|
|
77216
77264
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
77217
|
-
color: getColorForLevel(
|
|
77265
|
+
color: getColorForLevel(log31.level),
|
|
77218
77266
|
dimColor: true,
|
|
77219
77267
|
wrap: "truncate",
|
|
77220
77268
|
children: [
|
|
77221
77269
|
"[",
|
|
77222
|
-
padComponent(
|
|
77270
|
+
padComponent(log31.component),
|
|
77223
77271
|
"]"
|
|
77224
77272
|
]
|
|
77225
77273
|
}, undefined, true, undefined, this),
|
|
77226
77274
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
77227
|
-
color: getColorForLevel(
|
|
77275
|
+
color: getColorForLevel(log31.level),
|
|
77228
77276
|
wrap: "truncate",
|
|
77229
77277
|
children: [
|
|
77230
77278
|
" ",
|
|
77231
|
-
|
|
77279
|
+
log31.message
|
|
77232
77280
|
]
|
|
77233
77281
|
}, undefined, true, undefined, this)
|
|
77234
77282
|
]
|
|
77235
|
-
},
|
|
77283
|
+
}, log31.id, true, undefined, this))
|
|
77236
77284
|
}, undefined, false, undefined, this);
|
|
77237
77285
|
}
|
|
77238
77286
|
// src/ui/components/Footer.tsx
|
|
@@ -77756,7 +77804,7 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
|
|
|
77756
77804
|
const scrollRef = import_react59.default.useRef(null);
|
|
77757
77805
|
const { stdout } = use_stdout_default();
|
|
77758
77806
|
const isDebug = process.env.DEBUG === "1";
|
|
77759
|
-
const displayLogs = logs.filter((
|
|
77807
|
+
const displayLogs = logs.filter((log31) => isDebug || log31.level !== "debug");
|
|
77760
77808
|
const visibleLogs = displayLogs.slice(-Math.max(maxLines * 3, 100));
|
|
77761
77809
|
import_react59.default.useEffect(() => {
|
|
77762
77810
|
const handleResize = () => scrollRef.current?.remeasure();
|
|
@@ -77796,25 +77844,25 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
|
|
|
77796
77844
|
overflow: "hidden",
|
|
77797
77845
|
children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(ScrollView, {
|
|
77798
77846
|
ref: scrollRef,
|
|
77799
|
-
children: visibleLogs.map((
|
|
77847
|
+
children: visibleLogs.map((log31) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
77800
77848
|
children: [
|
|
77801
77849
|
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
77802
77850
|
dimColor: true,
|
|
77803
77851
|
children: [
|
|
77804
77852
|
"[",
|
|
77805
|
-
padComponent2(
|
|
77853
|
+
padComponent2(log31.component),
|
|
77806
77854
|
"]"
|
|
77807
77855
|
]
|
|
77808
77856
|
}, undefined, true, undefined, this),
|
|
77809
77857
|
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
77810
|
-
color: getLevelColor(
|
|
77858
|
+
color: getLevelColor(log31.level),
|
|
77811
77859
|
children: [
|
|
77812
77860
|
" ",
|
|
77813
|
-
|
|
77861
|
+
log31.message
|
|
77814
77862
|
]
|
|
77815
77863
|
}, undefined, true, undefined, this)
|
|
77816
77864
|
]
|
|
77817
|
-
},
|
|
77865
|
+
}, log31.id, true, undefined, this))
|
|
77818
77866
|
}, undefined, false, undefined, this)
|
|
77819
77867
|
}, undefined, false, undefined, this);
|
|
77820
77868
|
}
|
|
@@ -78331,10 +78379,10 @@ function useAppState(initialConfig) {
|
|
|
78331
78379
|
});
|
|
78332
78380
|
}, []);
|
|
78333
78381
|
const getLogsForSession = import_react60.useCallback((sessionId) => {
|
|
78334
|
-
return state.logs.filter((
|
|
78382
|
+
return state.logs.filter((log31) => log31.sessionId === sessionId);
|
|
78335
78383
|
}, [state.logs]);
|
|
78336
78384
|
const getGlobalLogs = import_react60.useCallback(() => {
|
|
78337
|
-
return state.logs.filter((
|
|
78385
|
+
return state.logs.filter((log31) => !log31.sessionId);
|
|
78338
78386
|
}, [state.logs]);
|
|
78339
78387
|
const togglePlatformEnabled = import_react60.useCallback((platformId) => {
|
|
78340
78388
|
let newEnabled = false;
|
|
@@ -79341,7 +79389,7 @@ import { EventEmitter as EventEmitter9 } from "events";
|
|
|
79341
79389
|
// src/auto-update/checker.ts
|
|
79342
79390
|
init_logger();
|
|
79343
79391
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
79344
|
-
var
|
|
79392
|
+
var log31 = createLogger("checker");
|
|
79345
79393
|
var PACKAGE_NAME = "claude-threads";
|
|
79346
79394
|
function compareVersions(a, b) {
|
|
79347
79395
|
const partsA = a.replace(/^v/, "").split(".").map(Number);
|
|
@@ -79364,13 +79412,13 @@ async function fetchLatestVersion() {
|
|
|
79364
79412
|
}
|
|
79365
79413
|
});
|
|
79366
79414
|
if (!response.ok) {
|
|
79367
|
-
|
|
79415
|
+
log31.warn(`Failed to fetch latest version: HTTP ${response.status}`);
|
|
79368
79416
|
return null;
|
|
79369
79417
|
}
|
|
79370
79418
|
const data = await response.json();
|
|
79371
79419
|
return data.version ?? null;
|
|
79372
79420
|
} catch (err) {
|
|
79373
|
-
|
|
79421
|
+
log31.warn(`Failed to fetch latest version: ${err}`);
|
|
79374
79422
|
return null;
|
|
79375
79423
|
}
|
|
79376
79424
|
}
|
|
@@ -79387,38 +79435,38 @@ class UpdateChecker extends EventEmitter7 {
|
|
|
79387
79435
|
}
|
|
79388
79436
|
start() {
|
|
79389
79437
|
if (!this.config.enabled) {
|
|
79390
|
-
|
|
79438
|
+
log31.debug("Auto-update disabled, not starting checker");
|
|
79391
79439
|
return;
|
|
79392
79440
|
}
|
|
79393
79441
|
setTimeout(() => {
|
|
79394
79442
|
this.check().catch((err) => {
|
|
79395
|
-
|
|
79443
|
+
log31.warn(`Initial update check failed: ${err}`);
|
|
79396
79444
|
});
|
|
79397
79445
|
}, 5000);
|
|
79398
79446
|
const intervalMs = this.config.checkIntervalMinutes * 60 * 1000;
|
|
79399
79447
|
this.checkInterval = setInterval(() => {
|
|
79400
79448
|
this.check().catch((err) => {
|
|
79401
|
-
|
|
79449
|
+
log31.warn(`Periodic update check failed: ${err}`);
|
|
79402
79450
|
});
|
|
79403
79451
|
}, intervalMs);
|
|
79404
|
-
|
|
79452
|
+
log31.info(`\uD83D\uDD04 Update checker started (every ${this.config.checkIntervalMinutes} minutes)`);
|
|
79405
79453
|
}
|
|
79406
79454
|
stop() {
|
|
79407
79455
|
if (this.checkInterval) {
|
|
79408
79456
|
clearInterval(this.checkInterval);
|
|
79409
79457
|
this.checkInterval = null;
|
|
79410
79458
|
}
|
|
79411
|
-
|
|
79459
|
+
log31.debug("Update checker stopped");
|
|
79412
79460
|
}
|
|
79413
79461
|
async check() {
|
|
79414
79462
|
if (this.isChecking) {
|
|
79415
|
-
|
|
79463
|
+
log31.debug("Check already in progress, skipping");
|
|
79416
79464
|
return this.lastUpdateInfo;
|
|
79417
79465
|
}
|
|
79418
79466
|
this.isChecking = true;
|
|
79419
79467
|
this.emit("check:start");
|
|
79420
79468
|
try {
|
|
79421
|
-
|
|
79469
|
+
log31.debug("Checking for updates...");
|
|
79422
79470
|
const latestVersion2 = await fetchLatestVersion();
|
|
79423
79471
|
if (!latestVersion2) {
|
|
79424
79472
|
this.emit("check:complete", false);
|
|
@@ -79435,18 +79483,18 @@ class UpdateChecker extends EventEmitter7 {
|
|
|
79435
79483
|
detectedAt: new Date
|
|
79436
79484
|
};
|
|
79437
79485
|
if (!this.lastUpdateInfo || this.lastUpdateInfo.latestVersion !== latestVersion2) {
|
|
79438
|
-
|
|
79486
|
+
log31.info(`\uD83C\uDD95 Update available: v${currentVersion} → v${latestVersion2}`);
|
|
79439
79487
|
this.lastUpdateInfo = updateInfo;
|
|
79440
79488
|
this.emit("update", updateInfo);
|
|
79441
79489
|
}
|
|
79442
79490
|
this.emit("check:complete", true);
|
|
79443
79491
|
return updateInfo;
|
|
79444
79492
|
}
|
|
79445
|
-
|
|
79493
|
+
log31.debug(`Up to date (v${currentVersion})`);
|
|
79446
79494
|
this.emit("check:complete", false);
|
|
79447
79495
|
return null;
|
|
79448
79496
|
} catch (err) {
|
|
79449
|
-
|
|
79497
|
+
log31.warn(`Update check failed: ${err}`);
|
|
79450
79498
|
this.emit("check:error", err);
|
|
79451
79499
|
return null;
|
|
79452
79500
|
} finally {
|
|
@@ -79517,7 +79565,7 @@ function isInScheduledWindow(window2) {
|
|
|
79517
79565
|
}
|
|
79518
79566
|
|
|
79519
79567
|
// src/auto-update/scheduler.ts
|
|
79520
|
-
var
|
|
79568
|
+
var log32 = createLogger("scheduler");
|
|
79521
79569
|
|
|
79522
79570
|
class UpdateScheduler extends EventEmitter8 {
|
|
79523
79571
|
config;
|
|
@@ -79541,7 +79589,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79541
79589
|
scheduleUpdate(updateInfo) {
|
|
79542
79590
|
this.pendingUpdate = updateInfo;
|
|
79543
79591
|
if (this.config.autoRestartMode === "immediate") {
|
|
79544
|
-
|
|
79592
|
+
log32.info("Immediate mode: triggering update now");
|
|
79545
79593
|
this.emit("ready", updateInfo);
|
|
79546
79594
|
return;
|
|
79547
79595
|
}
|
|
@@ -79554,19 +79602,19 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79554
79602
|
this.scheduledRestartAt = null;
|
|
79555
79603
|
this.askApprovals.clear();
|
|
79556
79604
|
this.askStartTime = null;
|
|
79557
|
-
|
|
79605
|
+
log32.debug("Update schedule cancelled");
|
|
79558
79606
|
}
|
|
79559
79607
|
deferUpdate(minutes) {
|
|
79560
79608
|
const deferUntil = new Date(Date.now() + minutes * 60 * 1000);
|
|
79561
79609
|
this.scheduledRestartAt = null;
|
|
79562
79610
|
this.idleStartTime = null;
|
|
79563
79611
|
this.emit("deferred", deferUntil);
|
|
79564
|
-
|
|
79612
|
+
log32.info(`Update deferred until ${deferUntil.toLocaleTimeString()}`);
|
|
79565
79613
|
return deferUntil;
|
|
79566
79614
|
}
|
|
79567
79615
|
recordAskResponse(threadId, approved) {
|
|
79568
79616
|
this.askApprovals.set(threadId, approved);
|
|
79569
|
-
|
|
79617
|
+
log32.debug(`Thread ${threadId.substring(0, 8)} ${approved ? "approved" : "denied"} update`);
|
|
79570
79618
|
this.checkAskCondition();
|
|
79571
79619
|
}
|
|
79572
79620
|
getScheduledRestartAt() {
|
|
@@ -79587,7 +79635,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79587
79635
|
return;
|
|
79588
79636
|
this.checkCondition();
|
|
79589
79637
|
this.checkTimer = setInterval(() => this.checkCondition(), 1e4);
|
|
79590
|
-
|
|
79638
|
+
log32.debug(`Started checking for ${this.config.autoRestartMode} condition`);
|
|
79591
79639
|
}
|
|
79592
79640
|
stopChecking() {
|
|
79593
79641
|
if (this.checkTimer) {
|
|
@@ -79618,17 +79666,17 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79618
79666
|
if (activity.activeSessionCount === 0) {
|
|
79619
79667
|
if (!this.idleStartTime) {
|
|
79620
79668
|
this.idleStartTime = new Date;
|
|
79621
|
-
|
|
79669
|
+
log32.debug("No active sessions, starting idle timer");
|
|
79622
79670
|
}
|
|
79623
79671
|
const idleMs = Date.now() - this.idleStartTime.getTime();
|
|
79624
79672
|
const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
79625
79673
|
if (idleMs >= requiredMs) {
|
|
79626
|
-
|
|
79674
|
+
log32.info(`Idle for ${this.config.idleTimeoutMinutes} minutes, triggering update`);
|
|
79627
79675
|
this.triggerCountdown();
|
|
79628
79676
|
}
|
|
79629
79677
|
} else {
|
|
79630
79678
|
if (this.idleStartTime) {
|
|
79631
|
-
|
|
79679
|
+
log32.debug("Sessions became active, resetting idle timer");
|
|
79632
79680
|
this.idleStartTime = null;
|
|
79633
79681
|
}
|
|
79634
79682
|
}
|
|
@@ -79639,7 +79687,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79639
79687
|
const quietMs = Date.now() - activity.lastActivityAt.getTime();
|
|
79640
79688
|
const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
|
|
79641
79689
|
if (quietMs >= requiredMs && !activity.anySessionBusy) {
|
|
79642
|
-
|
|
79690
|
+
log32.info(`Sessions quiet for ${this.config.quietTimeoutMinutes} minutes, triggering update`);
|
|
79643
79691
|
this.triggerCountdown();
|
|
79644
79692
|
}
|
|
79645
79693
|
} else if (activity.activeSessionCount === 0) {
|
|
@@ -79649,7 +79697,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79649
79697
|
const idleMs = Date.now() - this.idleStartTime.getTime();
|
|
79650
79698
|
const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
|
|
79651
79699
|
if (idleMs >= requiredMs) {
|
|
79652
|
-
|
|
79700
|
+
log32.info("No sessions and quiet timeout reached, triggering update");
|
|
79653
79701
|
this.triggerCountdown();
|
|
79654
79702
|
}
|
|
79655
79703
|
}
|
|
@@ -79660,13 +79708,13 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79660
79708
|
}
|
|
79661
79709
|
const activity = this.getSessionActivity();
|
|
79662
79710
|
if (activity.activeSessionCount === 0) {
|
|
79663
|
-
|
|
79711
|
+
log32.info("Within scheduled window and no active sessions, triggering update");
|
|
79664
79712
|
this.triggerCountdown();
|
|
79665
79713
|
} else if (activity.lastActivityAt) {
|
|
79666
79714
|
const quietMs = Date.now() - activity.lastActivityAt.getTime();
|
|
79667
79715
|
const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
79668
79716
|
if (quietMs >= requiredMs && !activity.anySessionBusy) {
|
|
79669
|
-
|
|
79717
|
+
log32.info("Within scheduled window and sessions quiet, triggering update");
|
|
79670
79718
|
this.triggerCountdown();
|
|
79671
79719
|
}
|
|
79672
79720
|
}
|
|
@@ -79674,14 +79722,14 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79674
79722
|
checkAskCondition() {
|
|
79675
79723
|
const threadIds = this.getActiveThreadIds();
|
|
79676
79724
|
if (threadIds.length === 0) {
|
|
79677
|
-
|
|
79725
|
+
log32.info("No active threads, proceeding with update");
|
|
79678
79726
|
this.triggerCountdown();
|
|
79679
79727
|
return;
|
|
79680
79728
|
}
|
|
79681
79729
|
if (!this.askStartTime && this.pendingUpdate) {
|
|
79682
79730
|
this.askStartTime = new Date;
|
|
79683
79731
|
this.postAskMessage(threadIds, this.pendingUpdate.latestVersion).catch((err) => {
|
|
79684
|
-
|
|
79732
|
+
log32.warn(`Failed to post ask message: ${err}`);
|
|
79685
79733
|
});
|
|
79686
79734
|
return;
|
|
79687
79735
|
}
|
|
@@ -79694,12 +79742,12 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79694
79742
|
denials++;
|
|
79695
79743
|
}
|
|
79696
79744
|
if (approvals > threadIds.length / 2) {
|
|
79697
|
-
|
|
79745
|
+
log32.info(`Majority approved (${approvals}/${threadIds.length}), triggering update`);
|
|
79698
79746
|
this.triggerCountdown();
|
|
79699
79747
|
return;
|
|
79700
79748
|
}
|
|
79701
79749
|
if (denials > threadIds.length / 2) {
|
|
79702
|
-
|
|
79750
|
+
log32.info(`Majority denied (${denials}/${threadIds.length}), deferring update`);
|
|
79703
79751
|
this.deferUpdate(60);
|
|
79704
79752
|
return;
|
|
79705
79753
|
}
|
|
@@ -79707,7 +79755,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79707
79755
|
const elapsedMs = Date.now() - this.askStartTime.getTime();
|
|
79708
79756
|
const timeoutMs = this.config.askTimeoutMinutes * 60 * 1000;
|
|
79709
79757
|
if (elapsedMs >= timeoutMs) {
|
|
79710
|
-
|
|
79758
|
+
log32.info(`Ask timeout reached (${this.config.askTimeoutMinutes} min), triggering update`);
|
|
79711
79759
|
this.triggerCountdown();
|
|
79712
79760
|
}
|
|
79713
79761
|
}
|
|
@@ -79727,7 +79775,7 @@ class UpdateScheduler extends EventEmitter8 {
|
|
|
79727
79775
|
this.emit("ready", this.pendingUpdate);
|
|
79728
79776
|
}
|
|
79729
79777
|
}, 1000);
|
|
79730
|
-
|
|
79778
|
+
log32.info("Update countdown started (60 seconds)");
|
|
79731
79779
|
}
|
|
79732
79780
|
stopCountdown() {
|
|
79733
79781
|
if (this.countdownTimer) {
|
|
@@ -79743,24 +79791,24 @@ import { spawn as spawn4, spawnSync } from "child_process";
|
|
|
79743
79791
|
import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
79744
79792
|
import { dirname as dirname8, resolve as resolve6 } from "path";
|
|
79745
79793
|
import { homedir as homedir5 } from "os";
|
|
79746
|
-
var
|
|
79794
|
+
var log33 = createLogger("installer");
|
|
79747
79795
|
function detectPackageManager() {
|
|
79748
79796
|
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
79749
79797
|
const originalInstaller = detectOriginalInstaller();
|
|
79750
79798
|
if (originalInstaller) {
|
|
79751
|
-
|
|
79799
|
+
log33.debug(`Detected original installer: ${originalInstaller}`);
|
|
79752
79800
|
if (originalInstaller === "bun") {
|
|
79753
79801
|
const bunCheck2 = spawnSync("bun", ["--version"], { stdio: "ignore" });
|
|
79754
79802
|
if (bunCheck2.status === 0) {
|
|
79755
79803
|
return { cmd: "bun", isBun: true };
|
|
79756
79804
|
}
|
|
79757
|
-
|
|
79805
|
+
log33.warn("Originally installed with bun, but bun not found. Falling back to npm.");
|
|
79758
79806
|
} else {
|
|
79759
79807
|
const npmCheck2 = spawnSync(npmCmd, ["--version"], { stdio: "ignore" });
|
|
79760
79808
|
if (npmCheck2.status === 0) {
|
|
79761
79809
|
return { cmd: npmCmd, isBun: false };
|
|
79762
79810
|
}
|
|
79763
|
-
|
|
79811
|
+
log33.warn("Originally installed with npm, but npm not found. Falling back to bun.");
|
|
79764
79812
|
}
|
|
79765
79813
|
}
|
|
79766
79814
|
const bunCheck = spawnSync("bun", ["--version"], { stdio: "ignore" });
|
|
@@ -79811,7 +79859,7 @@ function loadUpdateState() {
|
|
|
79811
79859
|
return JSON.parse(content);
|
|
79812
79860
|
}
|
|
79813
79861
|
} catch (err) {
|
|
79814
|
-
|
|
79862
|
+
log33.warn(`Failed to load update state: ${err}`);
|
|
79815
79863
|
}
|
|
79816
79864
|
return {};
|
|
79817
79865
|
}
|
|
@@ -79822,9 +79870,9 @@ function saveUpdateState(state) {
|
|
|
79822
79870
|
mkdirSync4(dir, { recursive: true });
|
|
79823
79871
|
}
|
|
79824
79872
|
writeFileSync6(STATE_PATH, JSON.stringify(state, null, 2), "utf-8");
|
|
79825
|
-
|
|
79873
|
+
log33.debug("Update state saved");
|
|
79826
79874
|
} catch (err) {
|
|
79827
|
-
|
|
79875
|
+
log33.warn(`Failed to save update state: ${err}`);
|
|
79828
79876
|
}
|
|
79829
79877
|
}
|
|
79830
79878
|
function clearUpdateState() {
|
|
@@ -79833,7 +79881,7 @@ function clearUpdateState() {
|
|
|
79833
79881
|
writeFileSync6(STATE_PATH, "{}", "utf-8");
|
|
79834
79882
|
}
|
|
79835
79883
|
} catch (err) {
|
|
79836
|
-
|
|
79884
|
+
log33.warn(`Failed to clear update state: ${err}`);
|
|
79837
79885
|
}
|
|
79838
79886
|
}
|
|
79839
79887
|
function checkJustUpdated() {
|
|
@@ -79865,11 +79913,11 @@ function clearRuntimeSettings() {
|
|
|
79865
79913
|
}
|
|
79866
79914
|
}
|
|
79867
79915
|
async function installVersion(version) {
|
|
79868
|
-
|
|
79916
|
+
log33.info(`\uD83D\uDCE6 Installing ${PACKAGE_NAME2}@${version}...`);
|
|
79869
79917
|
const pm = detectPackageManager();
|
|
79870
79918
|
if (!pm) {
|
|
79871
79919
|
const error = "Neither bun nor npm found in PATH. Cannot install update.";
|
|
79872
|
-
|
|
79920
|
+
log33.error(`❌ ${error}`);
|
|
79873
79921
|
return { success: false, error };
|
|
79874
79922
|
}
|
|
79875
79923
|
saveUpdateState({
|
|
@@ -79881,7 +79929,7 @@ async function installVersion(version) {
|
|
|
79881
79929
|
return new Promise((resolve7) => {
|
|
79882
79930
|
const { cmd, isBun: isBun3 } = pm;
|
|
79883
79931
|
const args = ["install", "-g", `${PACKAGE_NAME2}@${version}`];
|
|
79884
|
-
|
|
79932
|
+
log33.debug(`Using ${isBun3 ? "bun" : "npm"} for installation`);
|
|
79885
79933
|
const child = spawn4(cmd, args, {
|
|
79886
79934
|
stdio: ["ignore", "pipe", "pipe"],
|
|
79887
79935
|
env: {
|
|
@@ -79899,7 +79947,7 @@ async function installVersion(version) {
|
|
|
79899
79947
|
});
|
|
79900
79948
|
child.on("close", (code) => {
|
|
79901
79949
|
if (code === 0) {
|
|
79902
|
-
|
|
79950
|
+
log33.info(`✅ Successfully installed ${PACKAGE_NAME2}@${version}`);
|
|
79903
79951
|
saveUpdateState({
|
|
79904
79952
|
previousVersion: VERSION,
|
|
79905
79953
|
targetVersion: version,
|
|
@@ -79909,20 +79957,20 @@ async function installVersion(version) {
|
|
|
79909
79957
|
resolve7({ success: true });
|
|
79910
79958
|
} else {
|
|
79911
79959
|
const errorMsg = stderr || stdout || `Exit code: ${code}`;
|
|
79912
|
-
|
|
79960
|
+
log33.error(`❌ Installation failed: ${errorMsg}`);
|
|
79913
79961
|
clearUpdateState();
|
|
79914
79962
|
resolve7({ success: false, error: errorMsg });
|
|
79915
79963
|
}
|
|
79916
79964
|
});
|
|
79917
79965
|
child.on("error", (err) => {
|
|
79918
|
-
|
|
79966
|
+
log33.error(`❌ Failed to spawn npm: ${err}`);
|
|
79919
79967
|
clearUpdateState();
|
|
79920
79968
|
resolve7({ success: false, error: err.message });
|
|
79921
79969
|
});
|
|
79922
79970
|
setTimeout(() => {
|
|
79923
79971
|
if (child.exitCode === null) {
|
|
79924
79972
|
child.kill();
|
|
79925
|
-
|
|
79973
|
+
log33.error("❌ Installation timed out");
|
|
79926
79974
|
clearUpdateState();
|
|
79927
79975
|
resolve7({ success: false, error: "Installation timed out" });
|
|
79928
79976
|
}
|
|
@@ -79964,7 +80012,7 @@ class UpdateInstaller {
|
|
|
79964
80012
|
}
|
|
79965
80013
|
|
|
79966
80014
|
// src/auto-update/manager.ts
|
|
79967
|
-
var
|
|
80015
|
+
var log34 = createLogger("updater");
|
|
79968
80016
|
|
|
79969
80017
|
class AutoUpdateManager extends EventEmitter9 {
|
|
79970
80018
|
config;
|
|
@@ -79987,23 +80035,23 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
79987
80035
|
}
|
|
79988
80036
|
start() {
|
|
79989
80037
|
if (!this.config.enabled) {
|
|
79990
|
-
|
|
80038
|
+
log34.info("Auto-update is disabled");
|
|
79991
80039
|
return;
|
|
79992
80040
|
}
|
|
79993
80041
|
const updateResult = this.installer.checkJustUpdated();
|
|
79994
80042
|
if (updateResult) {
|
|
79995
|
-
|
|
80043
|
+
log34.info(`\uD83C\uDF89 Updated from v${updateResult.previousVersion} to v${updateResult.currentVersion}`);
|
|
79996
80044
|
this.callbacks.broadcastUpdate((fmt) => `\uD83C\uDF89 ${fmt.formatBold("Bot updated")} from v${updateResult.previousVersion} to v${updateResult.currentVersion}`).catch((err) => {
|
|
79997
|
-
|
|
80045
|
+
log34.warn(`Failed to broadcast update notification: ${err}`);
|
|
79998
80046
|
});
|
|
79999
80047
|
}
|
|
80000
80048
|
this.checker.start();
|
|
80001
|
-
|
|
80049
|
+
log34.info(`\uD83D\uDD04 Auto-update manager started (mode: ${this.config.autoRestartMode})`);
|
|
80002
80050
|
}
|
|
80003
80051
|
stop() {
|
|
80004
80052
|
this.checker.stop();
|
|
80005
80053
|
this.scheduler.stop();
|
|
80006
|
-
|
|
80054
|
+
log34.debug("Auto-update manager stopped");
|
|
80007
80055
|
}
|
|
80008
80056
|
getState() {
|
|
80009
80057
|
return { ...this.state };
|
|
@@ -80017,10 +80065,10 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
80017
80065
|
async forceUpdate() {
|
|
80018
80066
|
const updateInfo = this.state.updateInfo || await this.checker.check();
|
|
80019
80067
|
if (!updateInfo) {
|
|
80020
|
-
|
|
80068
|
+
log34.info("No update available");
|
|
80021
80069
|
return;
|
|
80022
80070
|
}
|
|
80023
|
-
|
|
80071
|
+
log34.info("Forcing immediate update");
|
|
80024
80072
|
await this.performUpdate(updateInfo);
|
|
80025
80073
|
}
|
|
80026
80074
|
deferUpdate(minutes = 60) {
|
|
@@ -80075,7 +80123,7 @@ class AutoUpdateManager extends EventEmitter9 {
|
|
|
80075
80123
|
await this.callbacks.broadcastUpdate((fmt) => `✅ ${fmt.formatBold("Update installed")} - restarting now. ${fmt.formatItalic("Sessions will resume automatically.")}`).catch(() => {});
|
|
80076
80124
|
await new Promise((resolve7) => setTimeout(resolve7, 1000));
|
|
80077
80125
|
await this.callbacks.prepareForRestart();
|
|
80078
|
-
|
|
80126
|
+
log34.info(`\uD83D\uDD04 Restarting for update to v${updateInfo.latestVersion}`);
|
|
80079
80127
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
80080
80128
|
process.stdout.write("\x1B[?25h");
|
|
80081
80129
|
process.exit(RESTART_EXIT_CODE);
|