happy-imou-cloud 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseReasoningProcessor-01KqA3Kz.cjs → BaseReasoningProcessor-B6tJ_eL5.cjs} +2 -2
- package/dist/{BaseReasoningProcessor-DQE2l7Xu.mjs → BaseReasoningProcessor-D8VhEbs2.mjs} +2 -2
- package/dist/{api-B8v4tczT.cjs → api-D2Njw9Im.cjs} +56 -3
- package/dist/{api-B5Ui8Fw0.mjs → api-MYhAGPLn.mjs} +56 -3
- package/dist/{command-D8yNlaDo.cjs → command-CVldr51S.cjs} +3 -3
- package/dist/{command-BfIuJmeo.mjs → command-nmK6O-ab.mjs} +3 -3
- package/dist/{index-BByhFIIq.mjs → index-B97L7qLD.mjs} +15 -17
- package/dist/{index-BOqJ9hwi.cjs → index-Bg-YziG2.cjs} +17 -19
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +6 -0
- package/dist/lib.d.mts +6 -0
- package/dist/lib.mjs +1 -1
- package/dist/{persistence-C33AMdtv.cjs → persistence-D_2GkJAO.cjs} +28 -6
- package/dist/{persistence-CzpZpiL3.mjs → persistence-Dkm7rm8k.mjs} +29 -7
- package/dist/{registerKillSessionHandler-BtSK7IOa.mjs → registerKillSessionHandler-5GbrO0FM.mjs} +2 -2
- package/dist/{registerKillSessionHandler-BkzQulD9.cjs → registerKillSessionHandler-BAXmJQRt.cjs} +2 -2
- package/dist/{runClaude-CNVufgZb.cjs → runClaude-B-GNEkKg.cjs} +228 -44
- package/dist/{runClaude-C_WLfM6c.mjs → runClaude-Cii3R2Fv.mjs} +229 -45
- package/dist/{runCodex-8eWjTPJr.mjs → runCodex-C--ZwAhl.mjs} +5 -5
- package/dist/{runCodex-Dzy8anlX.cjs → runCodex-CPHyGwj9.cjs} +5 -5
- package/dist/{runGemini-nbr0mm-S.mjs → runGemini-CQp7Nuzn.mjs} +5 -5
- package/dist/{runGemini-CgsVKP7m.cjs → runGemini-DaDz1bzQ.cjs} +5 -5
- package/package.json +1 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { readFile, unlink, open, stat,
|
|
1
|
+
import { readFile, unlink, mkdir, open, stat, writeFile, rename } from 'node:fs/promises';
|
|
2
2
|
import { existsSync, unlinkSync, writeFileSync, readdirSync, readFileSync, constants } from 'node:fs';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
|
-
import { c as configuration, l as logger, e as encodeBase64 } from './api-
|
|
4
|
+
import { c as configuration, l as logger, e as encodeBase64 } from './api-MYhAGPLn.mjs';
|
|
5
5
|
import * as z from 'zod';
|
|
6
6
|
import 'axios';
|
|
7
7
|
import 'chalk';
|
|
@@ -185,16 +185,37 @@ async function updateSettings(updater) {
|
|
|
185
185
|
const LOCK_RETRY_INTERVAL_MS = 100;
|
|
186
186
|
const MAX_LOCK_ATTEMPTS = 50;
|
|
187
187
|
const STALE_LOCK_TIMEOUT_MS = 1e4;
|
|
188
|
+
const LOCK_CONTENTION_CODES = /* @__PURE__ */ new Set(["EEXIST", "EPERM", "EACCES", "EBUSY"]);
|
|
189
|
+
const LOCK_RELEASE_RETRYABLE_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
188
190
|
const lockFile = configuration.settingsFile + ".lock";
|
|
189
|
-
const tmpFile = `${configuration.settingsFile}.${process.pid}.${Date.now()}.tmp`;
|
|
191
|
+
const tmpFile = `${configuration.settingsFile}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
190
192
|
let fileHandle;
|
|
191
193
|
let attempts = 0;
|
|
194
|
+
if (!existsSync(configuration.happyCloudHomeDir)) {
|
|
195
|
+
await mkdir(configuration.happyCloudHomeDir, { recursive: true });
|
|
196
|
+
}
|
|
197
|
+
async function removeFileWithRetry(path) {
|
|
198
|
+
for (let attempt = 1; attempt <= 20; attempt++) {
|
|
199
|
+
try {
|
|
200
|
+
await unlink(path);
|
|
201
|
+
return;
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (err?.code === "ENOENT") {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (!LOCK_RELEASE_RETRYABLE_CODES.has(err?.code) || attempt === 20) {
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
192
213
|
while (attempts < MAX_LOCK_ATTEMPTS) {
|
|
193
214
|
try {
|
|
194
215
|
fileHandle = await open(lockFile, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);
|
|
195
216
|
break;
|
|
196
217
|
} catch (err) {
|
|
197
|
-
if (err
|
|
218
|
+
if (LOCK_CONTENTION_CODES.has(err?.code)) {
|
|
198
219
|
attempts++;
|
|
199
220
|
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
|
|
200
221
|
try {
|
|
@@ -224,11 +245,12 @@ async function updateSettings(updater) {
|
|
|
224
245
|
return updated;
|
|
225
246
|
} finally {
|
|
226
247
|
if (existsSync(tmpFile)) {
|
|
227
|
-
await
|
|
248
|
+
await removeFileWithRetry(tmpFile).catch(() => {
|
|
228
249
|
});
|
|
229
250
|
}
|
|
230
|
-
await fileHandle.close()
|
|
231
|
-
|
|
251
|
+
await fileHandle.close().catch(() => {
|
|
252
|
+
});
|
|
253
|
+
await removeFileWithRetry(lockFile).catch(() => {
|
|
232
254
|
});
|
|
233
255
|
}
|
|
234
256
|
}
|
package/dist/{registerKillSessionHandler-BtSK7IOa.mjs → registerKillSessionHandler-5GbrO0FM.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as formatDisplayMessage } from './index-
|
|
2
|
-
import { l as logger } from './api-
|
|
1
|
+
import { f as formatDisplayMessage } from './index-B97L7qLD.mjs';
|
|
2
|
+
import { l as logger } from './api-MYhAGPLn.mjs';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
import 'axios';
|
|
5
5
|
import 'node:events';
|
package/dist/{registerKillSessionHandler-BkzQulD9.cjs → registerKillSessionHandler-BAXmJQRt.cjs}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
4
|
-
var api = require('./api-
|
|
3
|
+
var index = require('./index-Bg-YziG2.cjs');
|
|
4
|
+
var api = require('./api-D2Njw9Im.cjs');
|
|
5
5
|
var crypto = require('crypto');
|
|
6
6
|
require('axios');
|
|
7
7
|
require('node:events');
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
var os = require('node:os');
|
|
4
4
|
var node_crypto = require('node:crypto');
|
|
5
|
-
var api = require('./api-
|
|
6
|
-
var index = require('./index-
|
|
5
|
+
var api = require('./api-D2Njw9Im.cjs');
|
|
6
|
+
var index = require('./index-Bg-YziG2.cjs');
|
|
7
7
|
var future = require('./future-Dq4Ha1Dn.cjs');
|
|
8
8
|
var types = require('./types-DVk3crez.cjs');
|
|
9
9
|
var path = require('node:path');
|
|
10
10
|
var promises = require('node:fs/promises');
|
|
11
11
|
var fs = require('fs/promises');
|
|
12
12
|
var ink = require('ink');
|
|
13
|
-
var registerKillSessionHandler = require('./registerKillSessionHandler-
|
|
13
|
+
var registerKillSessionHandler = require('./registerKillSessionHandler-BAXmJQRt.cjs');
|
|
14
14
|
var React = require('react');
|
|
15
15
|
var node_child_process = require('node:child_process');
|
|
16
16
|
var node_readline = require('node:readline');
|
|
@@ -23,7 +23,7 @@ require('tweetnacl');
|
|
|
23
23
|
require('expo-server-sdk');
|
|
24
24
|
require('chalk');
|
|
25
25
|
var node_util = require('node:util');
|
|
26
|
-
var persistence = require('./persistence-
|
|
26
|
+
var persistence = require('./persistence-D_2GkJAO.cjs');
|
|
27
27
|
var node_http = require('node:http');
|
|
28
28
|
require('fs');
|
|
29
29
|
require('zod');
|
|
@@ -62,6 +62,7 @@ class Session {
|
|
|
62
62
|
/** JavaScript runtime to use for spawning Claude Code (default: 'node') */
|
|
63
63
|
jsRuntime;
|
|
64
64
|
sessionId;
|
|
65
|
+
transcriptPath = null;
|
|
65
66
|
mode = "local";
|
|
66
67
|
thinking = false;
|
|
67
68
|
/** Callbacks to be notified when session ID is found/changed */
|
|
@@ -115,15 +116,33 @@ class Session {
|
|
|
115
116
|
* Updates internal state, syncs to API metadata, and notifies
|
|
116
117
|
* all registered callbacks (e.g., SessionScanner) about the change.
|
|
117
118
|
*/
|
|
118
|
-
onSessionFound = (sessionId) => {
|
|
119
|
+
onSessionFound = (sessionId, hookData) => {
|
|
120
|
+
const nextTranscriptPathRaw = hookData?.transcript_path ?? hookData?.transcriptPath;
|
|
121
|
+
const nextTranscriptPath = typeof nextTranscriptPathRaw === "string" ? nextTranscriptPathRaw : null;
|
|
122
|
+
const previousSessionId = this.sessionId;
|
|
123
|
+
const previousTranscriptPath = this.transcriptPath;
|
|
119
124
|
this.sessionId = sessionId;
|
|
125
|
+
if (previousSessionId !== sessionId) {
|
|
126
|
+
this.transcriptPath = nextTranscriptPath;
|
|
127
|
+
} else if (nextTranscriptPath) {
|
|
128
|
+
this.transcriptPath = nextTranscriptPath;
|
|
129
|
+
}
|
|
120
130
|
this.client.updateMetadata((metadata) => ({
|
|
121
131
|
...metadata,
|
|
122
|
-
claudeSessionId: sessionId
|
|
132
|
+
claudeSessionId: sessionId,
|
|
133
|
+
claudeTranscriptPath: this.transcriptPath || void 0
|
|
123
134
|
}));
|
|
124
|
-
api.logger.debug(`[Session] Claude
|
|
135
|
+
api.logger.debug(`[Session] Claude session info updated: sessionId=${sessionId}, transcriptPath=${this.transcriptPath ?? "none"}`);
|
|
136
|
+
const didTranscriptPathChange = nextTranscriptPath !== null && nextTranscriptPath !== previousTranscriptPath;
|
|
137
|
+
if (previousSessionId === sessionId && !didTranscriptPathChange) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const info = {
|
|
141
|
+
sessionId,
|
|
142
|
+
transcriptPath: this.transcriptPath
|
|
143
|
+
};
|
|
125
144
|
for (const callback of this.sessionFoundCallbacks) {
|
|
126
|
-
callback(
|
|
145
|
+
callback(info);
|
|
127
146
|
}
|
|
128
147
|
};
|
|
129
148
|
/**
|
|
@@ -146,6 +165,7 @@ class Session {
|
|
|
146
165
|
*/
|
|
147
166
|
clearSessionId = () => {
|
|
148
167
|
this.sessionId = null;
|
|
168
|
+
this.transcriptPath = null;
|
|
149
169
|
api.logger.debug("[Session] Session ID cleared");
|
|
150
170
|
};
|
|
151
171
|
/**
|
|
@@ -250,9 +270,51 @@ class InvalidateSync {
|
|
|
250
270
|
|
|
251
271
|
function startFileWatcher(file, onFileChange) {
|
|
252
272
|
const abortController = new AbortController();
|
|
273
|
+
const parentDir = path.dirname(file);
|
|
274
|
+
const targetName = path.basename(file);
|
|
253
275
|
void (async () => {
|
|
254
276
|
while (true) {
|
|
255
277
|
try {
|
|
278
|
+
try {
|
|
279
|
+
await fs.stat(file);
|
|
280
|
+
} catch (e) {
|
|
281
|
+
if (abortController.signal.aborted) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (e?.code === "ENOENT") {
|
|
285
|
+
api.logger.debug(`[FILE_WATCHER] Waiting for file to exist: ${file}`);
|
|
286
|
+
const dirWatcher = fs.watch(parentDir, { persistent: true, signal: abortController.signal });
|
|
287
|
+
try {
|
|
288
|
+
await fs.stat(file);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
if (err?.code !== "ENOENT") {
|
|
291
|
+
throw err;
|
|
292
|
+
}
|
|
293
|
+
for await (const event of dirWatcher) {
|
|
294
|
+
if (abortController.signal.aborted) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const name = typeof event?.filename === "string" ? String(event.filename) : null;
|
|
298
|
+
if (name && name !== targetName) {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
await fs.stat(file);
|
|
303
|
+
api.logger.debug(`[FILE_WATCHER] File appeared: ${file}`);
|
|
304
|
+
break;
|
|
305
|
+
} catch (nextErr) {
|
|
306
|
+
if (nextErr?.code === "ENOENT") {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
throw nextErr;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
throw e;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
onFileChange(file);
|
|
256
318
|
api.logger.debug(`[FILE_WATCHER] Starting watcher for ${file}`);
|
|
257
319
|
const watcher = fs.watch(file, { persistent: true, signal: abortController.signal });
|
|
258
320
|
for await (const event of watcher) {
|
|
@@ -282,19 +344,67 @@ const INTERNAL_CLAUDE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
282
344
|
"queue-operation"
|
|
283
345
|
]);
|
|
284
346
|
async function createSessionScanner(opts) {
|
|
285
|
-
const
|
|
347
|
+
const initialProjectDir = index.getProjectPath(opts.workingDirectory);
|
|
348
|
+
let projectDirOverride = null;
|
|
349
|
+
const sessionFileOverrides = /* @__PURE__ */ new Map();
|
|
350
|
+
const transcriptMissingWarningMs = opts.transcriptMissingWarningMs ?? 5e3;
|
|
351
|
+
const warnedMissingTranscripts = /* @__PURE__ */ new Set();
|
|
352
|
+
const missingTranscriptTimers = /* @__PURE__ */ new Map();
|
|
353
|
+
function effectiveProjectDir() {
|
|
354
|
+
return projectDirOverride ?? initialProjectDir;
|
|
355
|
+
}
|
|
356
|
+
function getSessionFilePath(sessionId) {
|
|
357
|
+
const override = sessionFileOverrides.get(sessionId);
|
|
358
|
+
return override ?? path.join(effectiveProjectDir(), `${sessionId}.jsonl`);
|
|
359
|
+
}
|
|
360
|
+
function scheduleTranscriptMissingWarning(sessionId) {
|
|
361
|
+
if (!opts.onTranscriptMissing) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (!Number.isFinite(transcriptMissingWarningMs) || transcriptMissingWarningMs <= 0) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (warnedMissingTranscripts.has(sessionId) || missingTranscriptTimers.has(sessionId)) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const timeoutId = setTimeout(async () => {
|
|
371
|
+
missingTranscriptTimers.delete(sessionId);
|
|
372
|
+
if (warnedMissingTranscripts.has(sessionId)) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const filePath = getSessionFilePath(sessionId);
|
|
376
|
+
try {
|
|
377
|
+
await promises.readFile(filePath, "utf-8");
|
|
378
|
+
return;
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
warnedMissingTranscripts.add(sessionId);
|
|
382
|
+
try {
|
|
383
|
+
opts.onTranscriptMissing?.({ sessionId, filePath });
|
|
384
|
+
} catch (err) {
|
|
385
|
+
api.logger.debug("[SESSION_SCANNER] onTranscriptMissing callback threw:", err);
|
|
386
|
+
}
|
|
387
|
+
}, transcriptMissingWarningMs);
|
|
388
|
+
missingTranscriptTimers.set(sessionId, timeoutId);
|
|
389
|
+
}
|
|
286
390
|
let finishedSessions = /* @__PURE__ */ new Set();
|
|
287
391
|
let pendingSessions = /* @__PURE__ */ new Set();
|
|
288
392
|
let currentSessionId = null;
|
|
289
393
|
let watchers = /* @__PURE__ */ new Map();
|
|
290
394
|
let processedMessageKeys = /* @__PURE__ */ new Set();
|
|
395
|
+
if (opts.sessionId && typeof opts.transcriptPath === "string" && opts.transcriptPath.trim()) {
|
|
396
|
+
const transcriptPath = opts.transcriptPath.trim();
|
|
397
|
+
sessionFileOverrides.set(opts.sessionId, transcriptPath);
|
|
398
|
+
projectDirOverride = path.dirname(transcriptPath);
|
|
399
|
+
}
|
|
291
400
|
if (opts.sessionId) {
|
|
292
|
-
let messages = await readSessionLog(
|
|
401
|
+
let messages = await readSessionLog(getSessionFilePath(opts.sessionId));
|
|
293
402
|
api.logger.debug(`[SESSION_SCANNER] Marking ${messages.length} existing messages as processed from session ${opts.sessionId}`);
|
|
294
403
|
for (let m of messages) {
|
|
295
404
|
processedMessageKeys.add(messageKey(m));
|
|
296
405
|
}
|
|
297
406
|
currentSessionId = opts.sessionId;
|
|
407
|
+
scheduleTranscriptMissingWarning(opts.sessionId);
|
|
298
408
|
}
|
|
299
409
|
const sync = new InvalidateSync(async () => {
|
|
300
410
|
let sessions = [];
|
|
@@ -310,7 +420,7 @@ async function createSessionScanner(opts) {
|
|
|
310
420
|
}
|
|
311
421
|
}
|
|
312
422
|
for (let session of sessions) {
|
|
313
|
-
const sessionMessages = await readSessionLog(
|
|
423
|
+
const sessionMessages = await readSessionLog(getSessionFilePath(session));
|
|
314
424
|
let skipped = 0;
|
|
315
425
|
let sent = 0;
|
|
316
426
|
for (let file of sessionMessages) {
|
|
@@ -335,11 +445,27 @@ async function createSessionScanner(opts) {
|
|
|
335
445
|
}
|
|
336
446
|
}
|
|
337
447
|
for (let p of sessions) {
|
|
338
|
-
|
|
448
|
+
const desiredPath = getSessionFilePath(p);
|
|
449
|
+
const existing = watchers.get(p);
|
|
450
|
+
if (!existing) {
|
|
339
451
|
api.logger.debug(`[SESSION_SCANNER] Starting watcher for session: ${p}`);
|
|
340
|
-
watchers.set(p,
|
|
341
|
-
|
|
342
|
-
|
|
452
|
+
watchers.set(p, {
|
|
453
|
+
filePath: desiredPath,
|
|
454
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
455
|
+
sync.invalidate();
|
|
456
|
+
})
|
|
457
|
+
});
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
if (existing.filePath !== desiredPath) {
|
|
461
|
+
api.logger.debug(`[SESSION_SCANNER] Restarting watcher for session: ${p} (${existing.filePath} -> ${desiredPath})`);
|
|
462
|
+
existing.stop();
|
|
463
|
+
watchers.set(p, {
|
|
464
|
+
filePath: desiredPath,
|
|
465
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
466
|
+
sync.invalidate();
|
|
467
|
+
})
|
|
468
|
+
});
|
|
343
469
|
}
|
|
344
470
|
}
|
|
345
471
|
});
|
|
@@ -351,23 +477,55 @@ async function createSessionScanner(opts) {
|
|
|
351
477
|
cleanup: async () => {
|
|
352
478
|
clearInterval(intervalId);
|
|
353
479
|
for (let w of watchers.values()) {
|
|
354
|
-
w();
|
|
480
|
+
w.stop();
|
|
355
481
|
}
|
|
356
482
|
watchers.clear();
|
|
483
|
+
for (const timeoutId of missingTranscriptTimers.values()) {
|
|
484
|
+
clearTimeout(timeoutId);
|
|
485
|
+
}
|
|
486
|
+
missingTranscriptTimers.clear();
|
|
357
487
|
await sync.invalidateAndAwait();
|
|
358
488
|
sync.stop();
|
|
359
489
|
},
|
|
360
|
-
onNewSession: (
|
|
490
|
+
onNewSession: (arg) => {
|
|
491
|
+
const sessionId = typeof arg === "string" ? arg : arg.sessionId;
|
|
492
|
+
const transcriptPathRaw = typeof arg === "string" ? null : arg.transcriptPath;
|
|
493
|
+
const transcriptPath = typeof transcriptPathRaw === "string" && transcriptPathRaw.trim() ? transcriptPathRaw.trim() : null;
|
|
494
|
+
let didUpdatePaths = false;
|
|
495
|
+
if (transcriptPath) {
|
|
496
|
+
const previousOverride = sessionFileOverrides.get(sessionId);
|
|
497
|
+
if (previousOverride !== transcriptPath) {
|
|
498
|
+
sessionFileOverrides.set(sessionId, transcriptPath);
|
|
499
|
+
didUpdatePaths = true;
|
|
500
|
+
}
|
|
501
|
+
const nextProjectDir = path.dirname(transcriptPath);
|
|
502
|
+
if (projectDirOverride !== nextProjectDir) {
|
|
503
|
+
projectDirOverride = nextProjectDir;
|
|
504
|
+
didUpdatePaths = true;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
361
507
|
if (currentSessionId === sessionId) {
|
|
362
|
-
|
|
508
|
+
if (didUpdatePaths) {
|
|
509
|
+
sync.invalidate();
|
|
510
|
+
} else {
|
|
511
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
|
|
512
|
+
}
|
|
363
513
|
return;
|
|
364
514
|
}
|
|
365
515
|
if (finishedSessions.has(sessionId)) {
|
|
366
|
-
|
|
516
|
+
if (didUpdatePaths) {
|
|
517
|
+
sync.invalidate();
|
|
518
|
+
} else {
|
|
519
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already finished, skipping`);
|
|
520
|
+
}
|
|
367
521
|
return;
|
|
368
522
|
}
|
|
369
523
|
if (pendingSessions.has(sessionId)) {
|
|
370
|
-
|
|
524
|
+
if (didUpdatePaths) {
|
|
525
|
+
sync.invalidate();
|
|
526
|
+
} else {
|
|
527
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already pending, skipping`);
|
|
528
|
+
}
|
|
371
529
|
return;
|
|
372
530
|
}
|
|
373
531
|
if (currentSessionId) {
|
|
@@ -375,6 +533,7 @@ async function createSessionScanner(opts) {
|
|
|
375
533
|
}
|
|
376
534
|
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId}`);
|
|
377
535
|
currentSessionId = sessionId;
|
|
536
|
+
scheduleTranscriptMissingWarning(sessionId);
|
|
378
537
|
sync.invalidate();
|
|
379
538
|
}
|
|
380
539
|
};
|
|
@@ -392,14 +551,13 @@ function messageKey(message) {
|
|
|
392
551
|
throw Error();
|
|
393
552
|
}
|
|
394
553
|
}
|
|
395
|
-
async function readSessionLog(
|
|
396
|
-
|
|
397
|
-
api.logger.debug(`[SESSION_SCANNER] Reading session file: ${expectedSessionFile}`);
|
|
554
|
+
async function readSessionLog(sessionFilePath) {
|
|
555
|
+
api.logger.debug(`[SESSION_SCANNER] Reading session file: ${sessionFilePath}`);
|
|
398
556
|
let file;
|
|
399
557
|
try {
|
|
400
|
-
file = await promises.readFile(
|
|
558
|
+
file = await promises.readFile(sessionFilePath, "utf-8");
|
|
401
559
|
} catch (error) {
|
|
402
|
-
api.logger.debug(`[SESSION_SCANNER] Session file not found: ${
|
|
560
|
+
api.logger.debug(`[SESSION_SCANNER] Session file not found: ${sessionFilePath}`);
|
|
403
561
|
return [];
|
|
404
562
|
}
|
|
405
563
|
let lines = file.split("\n");
|
|
@@ -429,15 +587,25 @@ async function readSessionLog(projectDir, sessionId) {
|
|
|
429
587
|
async function claudeLocalLauncher(session) {
|
|
430
588
|
const scanner = await createSessionScanner({
|
|
431
589
|
sessionId: session.sessionId,
|
|
590
|
+
transcriptPath: session.transcriptPath,
|
|
432
591
|
workingDirectory: session.path,
|
|
433
592
|
onMessage: (message) => {
|
|
434
593
|
if (message.type !== "summary") {
|
|
435
594
|
session.client.sendClaudeSessionMessage(message);
|
|
436
595
|
}
|
|
596
|
+
},
|
|
597
|
+
onTranscriptMissing: () => {
|
|
598
|
+
session.client.sendSessionEvent({
|
|
599
|
+
type: "message",
|
|
600
|
+
message: "Claude transcript file not found yet, waiting for it to appear..."
|
|
601
|
+
});
|
|
437
602
|
}
|
|
438
603
|
});
|
|
439
|
-
const scannerSessionCallback = (
|
|
440
|
-
scanner.onNewSession(
|
|
604
|
+
const scannerSessionCallback = (info) => {
|
|
605
|
+
scanner.onNewSession({
|
|
606
|
+
sessionId: info.sessionId,
|
|
607
|
+
transcriptPath: info.transcriptPath
|
|
608
|
+
});
|
|
441
609
|
};
|
|
442
610
|
session.addSessionFoundCallback(scannerSessionCallback);
|
|
443
611
|
let exitReason = null;
|
|
@@ -475,7 +643,6 @@ async function claudeLocalLauncher(session) {
|
|
|
475
643
|
}
|
|
476
644
|
const handleSessionStart = (sessionId) => {
|
|
477
645
|
session.onSessionFound(sessionId);
|
|
478
|
-
scanner.onNewSession(sessionId);
|
|
479
646
|
};
|
|
480
647
|
while (true) {
|
|
481
648
|
if (exitReason) {
|
|
@@ -750,7 +917,7 @@ class AbortError extends Error {
|
|
|
750
917
|
}
|
|
751
918
|
}
|
|
752
919
|
|
|
753
|
-
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('runClaude-
|
|
920
|
+
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('runClaude-B-GNEkKg.cjs', document.baseURI).href)));
|
|
754
921
|
const __dirname$1 = path.join(__filename$1, "..");
|
|
755
922
|
function getGlobalClaudeVersion() {
|
|
756
923
|
try {
|
|
@@ -1424,7 +1591,7 @@ const systemPrompt = (() => {
|
|
|
1424
1591
|
|
|
1425
1592
|
async function claudeRemote(opts) {
|
|
1426
1593
|
let startFrom = opts.sessionId;
|
|
1427
|
-
if (opts.sessionId && !index.claudeCheckSession(opts.sessionId, opts.path)) {
|
|
1594
|
+
if (opts.sessionId && !index.claudeCheckSession(opts.sessionId, opts.path, opts.transcriptPath)) {
|
|
1428
1595
|
startFrom = null;
|
|
1429
1596
|
}
|
|
1430
1597
|
if (!startFrom && opts.claudeArgs) {
|
|
@@ -1526,11 +1693,14 @@ async function claudeRemote(opts) {
|
|
|
1526
1693
|
updateThinking(true);
|
|
1527
1694
|
const systemInit = message;
|
|
1528
1695
|
if (systemInit.session_id) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
const found = await awaitFileExist(
|
|
1696
|
+
const transcriptPath = opts.transcriptPath && opts.sessionId === systemInit.session_id ? opts.transcriptPath : path.join(index.getProjectPath(opts.path), `${systemInit.session_id}.jsonl`);
|
|
1697
|
+
api.logger.debug(`[claudeRemote] Waiting for session file to be written to disk: ${transcriptPath}`);
|
|
1698
|
+
const found = await awaitFileExist(transcriptPath);
|
|
1532
1699
|
api.logger.debug(`[claudeRemote] Session file found: ${systemInit.session_id} ${found}`);
|
|
1533
|
-
opts.onSessionFound(systemInit.session_id
|
|
1700
|
+
opts.onSessionFound(systemInit.session_id, {
|
|
1701
|
+
transcript_path: transcriptPath,
|
|
1702
|
+
transcriptPath
|
|
1703
|
+
});
|
|
1534
1704
|
}
|
|
1535
1705
|
}
|
|
1536
1706
|
if (message.type === "result") {
|
|
@@ -1983,11 +2153,21 @@ function formatClaudeMessageForInk(message, messageBuffer, onAssistantResult) {
|
|
|
1983
2153
|
case "assistant": {
|
|
1984
2154
|
const assistantMsg = message;
|
|
1985
2155
|
if (assistantMsg.message && assistantMsg.message.content) {
|
|
1986
|
-
|
|
2156
|
+
let assistantHeaderShown = false;
|
|
1987
2157
|
for (const block of assistantMsg.message.content) {
|
|
1988
|
-
if (block.type === "
|
|
2158
|
+
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim()) {
|
|
2159
|
+
messageBuffer.addMessage(`[Thinking] ${block.thinking}`, "status");
|
|
2160
|
+
} else if (block.type === "text") {
|
|
2161
|
+
if (!assistantHeaderShown) {
|
|
2162
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2163
|
+
assistantHeaderShown = true;
|
|
2164
|
+
}
|
|
1989
2165
|
messageBuffer.addMessage(block.text || "", "assistant");
|
|
1990
2166
|
} else if (block.type === "tool_use") {
|
|
2167
|
+
if (!assistantHeaderShown) {
|
|
2168
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2169
|
+
assistantHeaderShown = true;
|
|
2170
|
+
}
|
|
1991
2171
|
messageBuffer.addMessage(`\u{1F527} Tool: ${block.name}`, "tool");
|
|
1992
2172
|
if (block.input) {
|
|
1993
2173
|
const inputStr = JSON.stringify(block.input, null, 2);
|
|
@@ -2633,6 +2813,7 @@ async function claudeRemoteLauncher(session) {
|
|
|
2633
2813
|
try {
|
|
2634
2814
|
const remoteResult = await claudeRemote({
|
|
2635
2815
|
sessionId: session.sessionId,
|
|
2816
|
+
transcriptPath: session.transcriptPath,
|
|
2636
2817
|
path: session.path,
|
|
2637
2818
|
allowedTools: session.allowedTools ?? [],
|
|
2638
2819
|
mcpServers: session.mcpServers,
|
|
@@ -2666,9 +2847,9 @@ async function claudeRemoteLauncher(session) {
|
|
|
2666
2847
|
}
|
|
2667
2848
|
return null;
|
|
2668
2849
|
},
|
|
2669
|
-
onSessionFound: (sessionId) => {
|
|
2850
|
+
onSessionFound: (sessionId, data) => {
|
|
2670
2851
|
sdkToLogConverter.updateSessionId(sessionId);
|
|
2671
|
-
session.onSessionFound(sessionId);
|
|
2852
|
+
session.onSessionFound(sessionId, data);
|
|
2672
2853
|
},
|
|
2673
2854
|
onThinkingChange: session.onThinkingChange,
|
|
2674
2855
|
claudeEnvVars: session.claudeEnvVars,
|
|
@@ -2857,13 +3038,20 @@ async function startHookServer(options) {
|
|
|
2857
3038
|
}
|
|
2858
3039
|
clearTimeout(timeout);
|
|
2859
3040
|
const body = Buffer.concat(chunks).toString("utf-8");
|
|
2860
|
-
api.logger.debug("[hookServer] Received session hook:", body);
|
|
2861
3041
|
let data = {};
|
|
2862
3042
|
try {
|
|
2863
3043
|
data = JSON.parse(body);
|
|
2864
3044
|
} catch (parseError) {
|
|
2865
3045
|
api.logger.debug("[hookServer] Failed to parse hook data as JSON:", parseError);
|
|
2866
3046
|
}
|
|
3047
|
+
api.logger.debug("[hookServer] Received session hook", {
|
|
3048
|
+
sessionId: data.session_id || data.sessionId || null,
|
|
3049
|
+
transcriptPath: data.transcript_path || data.transcriptPath || null,
|
|
3050
|
+
cwd: data.cwd,
|
|
3051
|
+
hookEventName: data.hook_event_name,
|
|
3052
|
+
source: data.source,
|
|
3053
|
+
bodyLength: body.length
|
|
3054
|
+
});
|
|
2867
3055
|
const sessionId = data.session_id || data.sessionId;
|
|
2868
3056
|
if (sessionId) {
|
|
2869
3057
|
api.logger.debug(`[hookServer] Session hook received session ID: ${sessionId}`);
|
|
@@ -3065,11 +3253,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
3065
3253
|
onSessionHook: (sessionId, data) => {
|
|
3066
3254
|
api.logger.debug(`[START] Session hook received: ${sessionId}`, data);
|
|
3067
3255
|
if (currentSession) {
|
|
3068
|
-
|
|
3069
|
-
if (previousSessionId !== sessionId) {
|
|
3070
|
-
api.logger.debug(`[START] Claude session ID changed: ${previousSessionId} -> ${sessionId}`);
|
|
3071
|
-
currentSession.onSessionFound(sessionId);
|
|
3072
|
-
}
|
|
3256
|
+
currentSession.onSessionFound(sessionId, data);
|
|
3073
3257
|
}
|
|
3074
3258
|
}
|
|
3075
3259
|
});
|