happy-imou-cloud 2.0.1 → 2.0.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/dist/{BaseReasoningProcessor-DQE2l7Xu.mjs → BaseReasoningProcessor-B37yOHxo.mjs} +2 -2
- package/dist/{BaseReasoningProcessor-01KqA3Kz.cjs → BaseReasoningProcessor-_wxlqKB8.cjs} +4 -4
- package/dist/{api-B8v4tczT.cjs → api-D9dIR956.cjs} +97 -44
- package/dist/{api-B5Ui8Fw0.mjs → api-DpQIC-DJ.mjs} +56 -3
- package/dist/{command-D8yNlaDo.cjs → command-CdXv1zNF.cjs} +3 -3
- package/dist/{command-BfIuJmeo.mjs → command-DRqrBuHM.mjs} +3 -3
- package/dist/{index-BByhFIIq.mjs → index-CriPm_z9.mjs} +15 -17
- package/dist/{index-BOqJ9hwi.cjs → index-LYPXVO_L.cjs} +98 -100
- 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-CzpZpiL3.mjs → persistence-CqgPgbzN.mjs} +29 -7
- package/dist/{persistence-C33AMdtv.cjs → persistence-PzKU0QCa.cjs} +54 -32
- package/dist/{registerKillSessionHandler-BkzQulD9.cjs → registerKillSessionHandler-BDBPoQSA.cjs} +2 -2
- package/dist/{registerKillSessionHandler-BtSK7IOa.mjs → registerKillSessionHandler-C3M_-4Zg.mjs} +2 -2
- package/dist/{runClaude-C_WLfM6c.mjs → runClaude-D6Pdkevn.mjs} +250 -46
- package/dist/{runClaude-CNVufgZb.cjs → runClaude-IeRSC5qX.cjs} +270 -66
- package/dist/{runCodex-8eWjTPJr.mjs → runCodex-CsfUU1Wb.mjs} +216 -401
- package/dist/{runCodex-Dzy8anlX.cjs → runCodex-WRmgSK6L.cjs} +216 -401
- package/dist/{runGemini-nbr0mm-S.mjs → runGemini-CrH3dQ0Y.mjs} +5 -5
- package/dist/{runGemini-CgsVKP7m.cjs → runGemini-qBh6zs5G.cjs} +5 -5
- package/package.json +1 -2
- package/dist/future-Dq4Ha1Dn.cjs +0 -24
- package/dist/future-xRdLl3vf.mjs +0 -22
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import os, { homedir } from 'node:os';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { l as logger, d as backoff, f as delay, g as AsyncLock, c as configuration, b as connectionState, A as ApiClient, p as packageJson, i as isAuthenticationRequiredError, s as startOfflineReconnection } from './api-
|
|
4
|
-
import { e as getProjectPath, h as claudeLocal, E as ExitCodeError, j as isBun, k as trimIdent, l as claudeCheckSession, p as projectPath, m as getEnvironmentInfo, i as initialMachineMetadata, b as stopCaffeinate, n as notifyDaemonSessionStarted, o as startCaffeinate } from './index-
|
|
5
|
-
import { F as Future } from './future-xRdLl3vf.mjs';
|
|
3
|
+
import { l as logger, d as backoff, f as delay, g as AsyncLock, c as configuration, b as connectionState, A as ApiClient, p as packageJson, i as isAuthenticationRequiredError, s as startOfflineReconnection } from './api-DpQIC-DJ.mjs';
|
|
4
|
+
import { e as getProjectPath, h as claudeLocal, E as ExitCodeError, j as isBun, k as trimIdent, l as claudeCheckSession, p as projectPath, m as getEnvironmentInfo, i as initialMachineMetadata, b as stopCaffeinate, n as notifyDaemonSessionStarted, o as startCaffeinate } from './index-CriPm_z9.mjs';
|
|
6
5
|
import { R as RawJSONLinesSchema } from './types-CiliQpqS.mjs';
|
|
7
|
-
import { join, resolve } from 'node:path';
|
|
6
|
+
import { dirname, basename, join, resolve } from 'node:path';
|
|
8
7
|
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import { watch, access } from 'fs/promises';
|
|
8
|
+
import { stat, watch, access } from 'fs/promises';
|
|
10
9
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
11
|
-
import { a as MessageBuffer, M as MessageQueue2, h as hashObject, r as registerKillSessionHandler } from './registerKillSessionHandler-
|
|
10
|
+
import { a as MessageBuffer, M as MessageQueue2, h as hashObject, r as registerKillSessionHandler } from './registerKillSessionHandler-C3M_-4Zg.mjs';
|
|
12
11
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
13
12
|
import { execSync, spawn } from 'node:child_process';
|
|
14
13
|
import { createInterface } from 'node:readline';
|
|
@@ -21,7 +20,7 @@ import 'tweetnacl';
|
|
|
21
20
|
import 'expo-server-sdk';
|
|
22
21
|
import 'chalk';
|
|
23
22
|
import { isDeepStrictEqual } from 'node:util';
|
|
24
|
-
import { readSettings } from './persistence-
|
|
23
|
+
import { readSettings } from './persistence-CqgPgbzN.mjs';
|
|
25
24
|
import { createServer } from 'node:http';
|
|
26
25
|
import 'fs';
|
|
27
26
|
import 'zod';
|
|
@@ -59,6 +58,7 @@ class Session {
|
|
|
59
58
|
/** JavaScript runtime to use for spawning Claude Code (default: 'node') */
|
|
60
59
|
jsRuntime;
|
|
61
60
|
sessionId;
|
|
61
|
+
transcriptPath = null;
|
|
62
62
|
mode = "local";
|
|
63
63
|
thinking = false;
|
|
64
64
|
/** Callbacks to be notified when session ID is found/changed */
|
|
@@ -112,15 +112,33 @@ class Session {
|
|
|
112
112
|
* Updates internal state, syncs to API metadata, and notifies
|
|
113
113
|
* all registered callbacks (e.g., SessionScanner) about the change.
|
|
114
114
|
*/
|
|
115
|
-
onSessionFound = (sessionId) => {
|
|
115
|
+
onSessionFound = (sessionId, hookData) => {
|
|
116
|
+
const nextTranscriptPathRaw = hookData?.transcript_path ?? hookData?.transcriptPath;
|
|
117
|
+
const nextTranscriptPath = typeof nextTranscriptPathRaw === "string" ? nextTranscriptPathRaw : null;
|
|
118
|
+
const previousSessionId = this.sessionId;
|
|
119
|
+
const previousTranscriptPath = this.transcriptPath;
|
|
116
120
|
this.sessionId = sessionId;
|
|
121
|
+
if (previousSessionId !== sessionId) {
|
|
122
|
+
this.transcriptPath = nextTranscriptPath;
|
|
123
|
+
} else if (nextTranscriptPath) {
|
|
124
|
+
this.transcriptPath = nextTranscriptPath;
|
|
125
|
+
}
|
|
117
126
|
this.client.updateMetadata((metadata) => ({
|
|
118
127
|
...metadata,
|
|
119
|
-
claudeSessionId: sessionId
|
|
128
|
+
claudeSessionId: sessionId,
|
|
129
|
+
claudeTranscriptPath: this.transcriptPath || void 0
|
|
120
130
|
}));
|
|
121
|
-
logger.debug(`[Session] Claude
|
|
131
|
+
logger.debug(`[Session] Claude session info updated: sessionId=${sessionId}, transcriptPath=${this.transcriptPath ?? "none"}`);
|
|
132
|
+
const didTranscriptPathChange = nextTranscriptPath !== null && nextTranscriptPath !== previousTranscriptPath;
|
|
133
|
+
if (previousSessionId === sessionId && !didTranscriptPathChange) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const info = {
|
|
137
|
+
sessionId,
|
|
138
|
+
transcriptPath: this.transcriptPath
|
|
139
|
+
};
|
|
122
140
|
for (const callback of this.sessionFoundCallbacks) {
|
|
123
|
-
callback(
|
|
141
|
+
callback(info);
|
|
124
142
|
}
|
|
125
143
|
};
|
|
126
144
|
/**
|
|
@@ -143,6 +161,7 @@ class Session {
|
|
|
143
161
|
*/
|
|
144
162
|
clearSessionId = () => {
|
|
145
163
|
this.sessionId = null;
|
|
164
|
+
this.transcriptPath = null;
|
|
146
165
|
logger.debug("[Session] Session ID cleared");
|
|
147
166
|
};
|
|
148
167
|
/**
|
|
@@ -179,6 +198,27 @@ class Session {
|
|
|
179
198
|
};
|
|
180
199
|
}
|
|
181
200
|
|
|
201
|
+
class Future {
|
|
202
|
+
_resolve;
|
|
203
|
+
_reject;
|
|
204
|
+
_promise;
|
|
205
|
+
constructor() {
|
|
206
|
+
this._promise = new Promise((resolve, reject) => {
|
|
207
|
+
this._resolve = resolve;
|
|
208
|
+
this._reject = reject;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
resolve(value) {
|
|
212
|
+
this._resolve(value);
|
|
213
|
+
}
|
|
214
|
+
reject(reason) {
|
|
215
|
+
this._reject(reason);
|
|
216
|
+
}
|
|
217
|
+
get promise() {
|
|
218
|
+
return this._promise;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
182
222
|
class InvalidateSync {
|
|
183
223
|
_invalidated = false;
|
|
184
224
|
_invalidatedDouble = false;
|
|
@@ -247,9 +287,51 @@ class InvalidateSync {
|
|
|
247
287
|
|
|
248
288
|
function startFileWatcher(file, onFileChange) {
|
|
249
289
|
const abortController = new AbortController();
|
|
290
|
+
const parentDir = dirname(file);
|
|
291
|
+
const targetName = basename(file);
|
|
250
292
|
void (async () => {
|
|
251
293
|
while (true) {
|
|
252
294
|
try {
|
|
295
|
+
try {
|
|
296
|
+
await stat(file);
|
|
297
|
+
} catch (e) {
|
|
298
|
+
if (abortController.signal.aborted) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (e?.code === "ENOENT") {
|
|
302
|
+
logger.debug(`[FILE_WATCHER] Waiting for file to exist: ${file}`);
|
|
303
|
+
const dirWatcher = watch(parentDir, { persistent: true, signal: abortController.signal });
|
|
304
|
+
try {
|
|
305
|
+
await stat(file);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
if (err?.code !== "ENOENT") {
|
|
308
|
+
throw err;
|
|
309
|
+
}
|
|
310
|
+
for await (const event of dirWatcher) {
|
|
311
|
+
if (abortController.signal.aborted) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const name = typeof event?.filename === "string" ? String(event.filename) : null;
|
|
315
|
+
if (name && name !== targetName) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
await stat(file);
|
|
320
|
+
logger.debug(`[FILE_WATCHER] File appeared: ${file}`);
|
|
321
|
+
break;
|
|
322
|
+
} catch (nextErr) {
|
|
323
|
+
if (nextErr?.code === "ENOENT") {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
throw nextErr;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
throw e;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
onFileChange(file);
|
|
253
335
|
logger.debug(`[FILE_WATCHER] Starting watcher for ${file}`);
|
|
254
336
|
const watcher = watch(file, { persistent: true, signal: abortController.signal });
|
|
255
337
|
for await (const event of watcher) {
|
|
@@ -279,19 +361,67 @@ const INTERNAL_CLAUDE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
279
361
|
"queue-operation"
|
|
280
362
|
]);
|
|
281
363
|
async function createSessionScanner(opts) {
|
|
282
|
-
const
|
|
364
|
+
const initialProjectDir = getProjectPath(opts.workingDirectory);
|
|
365
|
+
let projectDirOverride = null;
|
|
366
|
+
const sessionFileOverrides = /* @__PURE__ */ new Map();
|
|
367
|
+
const transcriptMissingWarningMs = opts.transcriptMissingWarningMs ?? 5e3;
|
|
368
|
+
const warnedMissingTranscripts = /* @__PURE__ */ new Set();
|
|
369
|
+
const missingTranscriptTimers = /* @__PURE__ */ new Map();
|
|
370
|
+
function effectiveProjectDir() {
|
|
371
|
+
return projectDirOverride ?? initialProjectDir;
|
|
372
|
+
}
|
|
373
|
+
function getSessionFilePath(sessionId) {
|
|
374
|
+
const override = sessionFileOverrides.get(sessionId);
|
|
375
|
+
return override ?? join(effectiveProjectDir(), `${sessionId}.jsonl`);
|
|
376
|
+
}
|
|
377
|
+
function scheduleTranscriptMissingWarning(sessionId) {
|
|
378
|
+
if (!opts.onTranscriptMissing) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (!Number.isFinite(transcriptMissingWarningMs) || transcriptMissingWarningMs <= 0) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (warnedMissingTranscripts.has(sessionId) || missingTranscriptTimers.has(sessionId)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const timeoutId = setTimeout(async () => {
|
|
388
|
+
missingTranscriptTimers.delete(sessionId);
|
|
389
|
+
if (warnedMissingTranscripts.has(sessionId)) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const filePath = getSessionFilePath(sessionId);
|
|
393
|
+
try {
|
|
394
|
+
await readFile(filePath, "utf-8");
|
|
395
|
+
return;
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
warnedMissingTranscripts.add(sessionId);
|
|
399
|
+
try {
|
|
400
|
+
opts.onTranscriptMissing?.({ sessionId, filePath });
|
|
401
|
+
} catch (err) {
|
|
402
|
+
logger.debug("[SESSION_SCANNER] onTranscriptMissing callback threw:", err);
|
|
403
|
+
}
|
|
404
|
+
}, transcriptMissingWarningMs);
|
|
405
|
+
missingTranscriptTimers.set(sessionId, timeoutId);
|
|
406
|
+
}
|
|
283
407
|
let finishedSessions = /* @__PURE__ */ new Set();
|
|
284
408
|
let pendingSessions = /* @__PURE__ */ new Set();
|
|
285
409
|
let currentSessionId = null;
|
|
286
410
|
let watchers = /* @__PURE__ */ new Map();
|
|
287
411
|
let processedMessageKeys = /* @__PURE__ */ new Set();
|
|
412
|
+
if (opts.sessionId && typeof opts.transcriptPath === "string" && opts.transcriptPath.trim()) {
|
|
413
|
+
const transcriptPath = opts.transcriptPath.trim();
|
|
414
|
+
sessionFileOverrides.set(opts.sessionId, transcriptPath);
|
|
415
|
+
projectDirOverride = dirname(transcriptPath);
|
|
416
|
+
}
|
|
288
417
|
if (opts.sessionId) {
|
|
289
|
-
let messages = await readSessionLog(
|
|
418
|
+
let messages = await readSessionLog(getSessionFilePath(opts.sessionId));
|
|
290
419
|
logger.debug(`[SESSION_SCANNER] Marking ${messages.length} existing messages as processed from session ${opts.sessionId}`);
|
|
291
420
|
for (let m of messages) {
|
|
292
421
|
processedMessageKeys.add(messageKey(m));
|
|
293
422
|
}
|
|
294
423
|
currentSessionId = opts.sessionId;
|
|
424
|
+
scheduleTranscriptMissingWarning(opts.sessionId);
|
|
295
425
|
}
|
|
296
426
|
const sync = new InvalidateSync(async () => {
|
|
297
427
|
let sessions = [];
|
|
@@ -307,7 +437,7 @@ async function createSessionScanner(opts) {
|
|
|
307
437
|
}
|
|
308
438
|
}
|
|
309
439
|
for (let session of sessions) {
|
|
310
|
-
const sessionMessages = await readSessionLog(
|
|
440
|
+
const sessionMessages = await readSessionLog(getSessionFilePath(session));
|
|
311
441
|
let skipped = 0;
|
|
312
442
|
let sent = 0;
|
|
313
443
|
for (let file of sessionMessages) {
|
|
@@ -332,11 +462,27 @@ async function createSessionScanner(opts) {
|
|
|
332
462
|
}
|
|
333
463
|
}
|
|
334
464
|
for (let p of sessions) {
|
|
335
|
-
|
|
465
|
+
const desiredPath = getSessionFilePath(p);
|
|
466
|
+
const existing = watchers.get(p);
|
|
467
|
+
if (!existing) {
|
|
336
468
|
logger.debug(`[SESSION_SCANNER] Starting watcher for session: ${p}`);
|
|
337
|
-
watchers.set(p,
|
|
338
|
-
|
|
339
|
-
|
|
469
|
+
watchers.set(p, {
|
|
470
|
+
filePath: desiredPath,
|
|
471
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
472
|
+
sync.invalidate();
|
|
473
|
+
})
|
|
474
|
+
});
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (existing.filePath !== desiredPath) {
|
|
478
|
+
logger.debug(`[SESSION_SCANNER] Restarting watcher for session: ${p} (${existing.filePath} -> ${desiredPath})`);
|
|
479
|
+
existing.stop();
|
|
480
|
+
watchers.set(p, {
|
|
481
|
+
filePath: desiredPath,
|
|
482
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
483
|
+
sync.invalidate();
|
|
484
|
+
})
|
|
485
|
+
});
|
|
340
486
|
}
|
|
341
487
|
}
|
|
342
488
|
});
|
|
@@ -348,23 +494,55 @@ async function createSessionScanner(opts) {
|
|
|
348
494
|
cleanup: async () => {
|
|
349
495
|
clearInterval(intervalId);
|
|
350
496
|
for (let w of watchers.values()) {
|
|
351
|
-
w();
|
|
497
|
+
w.stop();
|
|
352
498
|
}
|
|
353
499
|
watchers.clear();
|
|
500
|
+
for (const timeoutId of missingTranscriptTimers.values()) {
|
|
501
|
+
clearTimeout(timeoutId);
|
|
502
|
+
}
|
|
503
|
+
missingTranscriptTimers.clear();
|
|
354
504
|
await sync.invalidateAndAwait();
|
|
355
505
|
sync.stop();
|
|
356
506
|
},
|
|
357
|
-
onNewSession: (
|
|
507
|
+
onNewSession: (arg) => {
|
|
508
|
+
const sessionId = typeof arg === "string" ? arg : arg.sessionId;
|
|
509
|
+
const transcriptPathRaw = typeof arg === "string" ? null : arg.transcriptPath;
|
|
510
|
+
const transcriptPath = typeof transcriptPathRaw === "string" && transcriptPathRaw.trim() ? transcriptPathRaw.trim() : null;
|
|
511
|
+
let didUpdatePaths = false;
|
|
512
|
+
if (transcriptPath) {
|
|
513
|
+
const previousOverride = sessionFileOverrides.get(sessionId);
|
|
514
|
+
if (previousOverride !== transcriptPath) {
|
|
515
|
+
sessionFileOverrides.set(sessionId, transcriptPath);
|
|
516
|
+
didUpdatePaths = true;
|
|
517
|
+
}
|
|
518
|
+
const nextProjectDir = dirname(transcriptPath);
|
|
519
|
+
if (projectDirOverride !== nextProjectDir) {
|
|
520
|
+
projectDirOverride = nextProjectDir;
|
|
521
|
+
didUpdatePaths = true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
358
524
|
if (currentSessionId === sessionId) {
|
|
359
|
-
|
|
525
|
+
if (didUpdatePaths) {
|
|
526
|
+
sync.invalidate();
|
|
527
|
+
} else {
|
|
528
|
+
logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
|
|
529
|
+
}
|
|
360
530
|
return;
|
|
361
531
|
}
|
|
362
532
|
if (finishedSessions.has(sessionId)) {
|
|
363
|
-
|
|
533
|
+
if (didUpdatePaths) {
|
|
534
|
+
sync.invalidate();
|
|
535
|
+
} else {
|
|
536
|
+
logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already finished, skipping`);
|
|
537
|
+
}
|
|
364
538
|
return;
|
|
365
539
|
}
|
|
366
540
|
if (pendingSessions.has(sessionId)) {
|
|
367
|
-
|
|
541
|
+
if (didUpdatePaths) {
|
|
542
|
+
sync.invalidate();
|
|
543
|
+
} else {
|
|
544
|
+
logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already pending, skipping`);
|
|
545
|
+
}
|
|
368
546
|
return;
|
|
369
547
|
}
|
|
370
548
|
if (currentSessionId) {
|
|
@@ -372,6 +550,7 @@ async function createSessionScanner(opts) {
|
|
|
372
550
|
}
|
|
373
551
|
logger.debug(`[SESSION_SCANNER] New session: ${sessionId}`);
|
|
374
552
|
currentSessionId = sessionId;
|
|
553
|
+
scheduleTranscriptMissingWarning(sessionId);
|
|
375
554
|
sync.invalidate();
|
|
376
555
|
}
|
|
377
556
|
};
|
|
@@ -389,14 +568,13 @@ function messageKey(message) {
|
|
|
389
568
|
throw Error();
|
|
390
569
|
}
|
|
391
570
|
}
|
|
392
|
-
async function readSessionLog(
|
|
393
|
-
|
|
394
|
-
logger.debug(`[SESSION_SCANNER] Reading session file: ${expectedSessionFile}`);
|
|
571
|
+
async function readSessionLog(sessionFilePath) {
|
|
572
|
+
logger.debug(`[SESSION_SCANNER] Reading session file: ${sessionFilePath}`);
|
|
395
573
|
let file;
|
|
396
574
|
try {
|
|
397
|
-
file = await readFile(
|
|
575
|
+
file = await readFile(sessionFilePath, "utf-8");
|
|
398
576
|
} catch (error) {
|
|
399
|
-
logger.debug(`[SESSION_SCANNER] Session file not found: ${
|
|
577
|
+
logger.debug(`[SESSION_SCANNER] Session file not found: ${sessionFilePath}`);
|
|
400
578
|
return [];
|
|
401
579
|
}
|
|
402
580
|
let lines = file.split("\n");
|
|
@@ -426,15 +604,25 @@ async function readSessionLog(projectDir, sessionId) {
|
|
|
426
604
|
async function claudeLocalLauncher(session) {
|
|
427
605
|
const scanner = await createSessionScanner({
|
|
428
606
|
sessionId: session.sessionId,
|
|
607
|
+
transcriptPath: session.transcriptPath,
|
|
429
608
|
workingDirectory: session.path,
|
|
430
609
|
onMessage: (message) => {
|
|
431
610
|
if (message.type !== "summary") {
|
|
432
611
|
session.client.sendClaudeSessionMessage(message);
|
|
433
612
|
}
|
|
613
|
+
},
|
|
614
|
+
onTranscriptMissing: () => {
|
|
615
|
+
session.client.sendSessionEvent({
|
|
616
|
+
type: "message",
|
|
617
|
+
message: "Claude transcript file not found yet, waiting for it to appear..."
|
|
618
|
+
});
|
|
434
619
|
}
|
|
435
620
|
});
|
|
436
|
-
const scannerSessionCallback = (
|
|
437
|
-
scanner.onNewSession(
|
|
621
|
+
const scannerSessionCallback = (info) => {
|
|
622
|
+
scanner.onNewSession({
|
|
623
|
+
sessionId: info.sessionId,
|
|
624
|
+
transcriptPath: info.transcriptPath
|
|
625
|
+
});
|
|
438
626
|
};
|
|
439
627
|
session.addSessionFoundCallback(scannerSessionCallback);
|
|
440
628
|
let exitReason = null;
|
|
@@ -472,7 +660,6 @@ async function claudeLocalLauncher(session) {
|
|
|
472
660
|
}
|
|
473
661
|
const handleSessionStart = (sessionId) => {
|
|
474
662
|
session.onSessionFound(sessionId);
|
|
475
|
-
scanner.onNewSession(sessionId);
|
|
476
663
|
};
|
|
477
664
|
while (true) {
|
|
478
665
|
if (exitReason) {
|
|
@@ -1421,7 +1608,7 @@ const systemPrompt = (() => {
|
|
|
1421
1608
|
|
|
1422
1609
|
async function claudeRemote(opts) {
|
|
1423
1610
|
let startFrom = opts.sessionId;
|
|
1424
|
-
if (opts.sessionId && !claudeCheckSession(opts.sessionId, opts.path)) {
|
|
1611
|
+
if (opts.sessionId && !claudeCheckSession(opts.sessionId, opts.path, opts.transcriptPath)) {
|
|
1425
1612
|
startFrom = null;
|
|
1426
1613
|
}
|
|
1427
1614
|
if (!startFrom && opts.claudeArgs) {
|
|
@@ -1523,11 +1710,14 @@ async function claudeRemote(opts) {
|
|
|
1523
1710
|
updateThinking(true);
|
|
1524
1711
|
const systemInit = message;
|
|
1525
1712
|
if (systemInit.session_id) {
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
const found = await awaitFileExist(
|
|
1713
|
+
const transcriptPath = opts.transcriptPath && opts.sessionId === systemInit.session_id ? opts.transcriptPath : join(getProjectPath(opts.path), `${systemInit.session_id}.jsonl`);
|
|
1714
|
+
logger.debug(`[claudeRemote] Waiting for session file to be written to disk: ${transcriptPath}`);
|
|
1715
|
+
const found = await awaitFileExist(transcriptPath);
|
|
1529
1716
|
logger.debug(`[claudeRemote] Session file found: ${systemInit.session_id} ${found}`);
|
|
1530
|
-
opts.onSessionFound(systemInit.session_id
|
|
1717
|
+
opts.onSessionFound(systemInit.session_id, {
|
|
1718
|
+
transcript_path: transcriptPath,
|
|
1719
|
+
transcriptPath
|
|
1720
|
+
});
|
|
1531
1721
|
}
|
|
1532
1722
|
}
|
|
1533
1723
|
if (message.type === "result") {
|
|
@@ -1980,11 +2170,21 @@ function formatClaudeMessageForInk(message, messageBuffer, onAssistantResult) {
|
|
|
1980
2170
|
case "assistant": {
|
|
1981
2171
|
const assistantMsg = message;
|
|
1982
2172
|
if (assistantMsg.message && assistantMsg.message.content) {
|
|
1983
|
-
|
|
2173
|
+
let assistantHeaderShown = false;
|
|
1984
2174
|
for (const block of assistantMsg.message.content) {
|
|
1985
|
-
if (block.type === "
|
|
2175
|
+
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim()) {
|
|
2176
|
+
messageBuffer.addMessage(`[Thinking] ${block.thinking}`, "status");
|
|
2177
|
+
} else if (block.type === "text") {
|
|
2178
|
+
if (!assistantHeaderShown) {
|
|
2179
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2180
|
+
assistantHeaderShown = true;
|
|
2181
|
+
}
|
|
1986
2182
|
messageBuffer.addMessage(block.text || "", "assistant");
|
|
1987
2183
|
} else if (block.type === "tool_use") {
|
|
2184
|
+
if (!assistantHeaderShown) {
|
|
2185
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2186
|
+
assistantHeaderShown = true;
|
|
2187
|
+
}
|
|
1988
2188
|
messageBuffer.addMessage(`\u{1F527} Tool: ${block.name}`, "tool");
|
|
1989
2189
|
if (block.input) {
|
|
1990
2190
|
const inputStr = JSON.stringify(block.input, null, 2);
|
|
@@ -2630,6 +2830,7 @@ async function claudeRemoteLauncher(session) {
|
|
|
2630
2830
|
try {
|
|
2631
2831
|
const remoteResult = await claudeRemote({
|
|
2632
2832
|
sessionId: session.sessionId,
|
|
2833
|
+
transcriptPath: session.transcriptPath,
|
|
2633
2834
|
path: session.path,
|
|
2634
2835
|
allowedTools: session.allowedTools ?? [],
|
|
2635
2836
|
mcpServers: session.mcpServers,
|
|
@@ -2663,9 +2864,9 @@ async function claudeRemoteLauncher(session) {
|
|
|
2663
2864
|
}
|
|
2664
2865
|
return null;
|
|
2665
2866
|
},
|
|
2666
|
-
onSessionFound: (sessionId) => {
|
|
2867
|
+
onSessionFound: (sessionId, data) => {
|
|
2667
2868
|
sdkToLogConverter.updateSessionId(sessionId);
|
|
2668
|
-
session.onSessionFound(sessionId);
|
|
2869
|
+
session.onSessionFound(sessionId, data);
|
|
2669
2870
|
},
|
|
2670
2871
|
onThinkingChange: session.onThinkingChange,
|
|
2671
2872
|
claudeEnvVars: session.claudeEnvVars,
|
|
@@ -2854,13 +3055,20 @@ async function startHookServer(options) {
|
|
|
2854
3055
|
}
|
|
2855
3056
|
clearTimeout(timeout);
|
|
2856
3057
|
const body = Buffer.concat(chunks).toString("utf-8");
|
|
2857
|
-
logger.debug("[hookServer] Received session hook:", body);
|
|
2858
3058
|
let data = {};
|
|
2859
3059
|
try {
|
|
2860
3060
|
data = JSON.parse(body);
|
|
2861
3061
|
} catch (parseError) {
|
|
2862
3062
|
logger.debug("[hookServer] Failed to parse hook data as JSON:", parseError);
|
|
2863
3063
|
}
|
|
3064
|
+
logger.debug("[hookServer] Received session hook", {
|
|
3065
|
+
sessionId: data.session_id || data.sessionId || null,
|
|
3066
|
+
transcriptPath: data.transcript_path || data.transcriptPath || null,
|
|
3067
|
+
cwd: data.cwd,
|
|
3068
|
+
hookEventName: data.hook_event_name,
|
|
3069
|
+
source: data.source,
|
|
3070
|
+
bodyLength: body.length
|
|
3071
|
+
});
|
|
2864
3072
|
const sessionId = data.session_id || data.sessionId;
|
|
2865
3073
|
if (sessionId) {
|
|
2866
3074
|
logger.debug(`[hookServer] Session hook received session ID: ${sessionId}`);
|
|
@@ -3062,11 +3270,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
3062
3270
|
onSessionHook: (sessionId, data) => {
|
|
3063
3271
|
logger.debug(`[START] Session hook received: ${sessionId}`, data);
|
|
3064
3272
|
if (currentSession) {
|
|
3065
|
-
|
|
3066
|
-
if (previousSessionId !== sessionId) {
|
|
3067
|
-
logger.debug(`[START] Claude session ID changed: ${previousSessionId} -> ${sessionId}`);
|
|
3068
|
-
currentSession.onSessionFound(sessionId);
|
|
3069
|
-
}
|
|
3273
|
+
currentSession.onSessionFound(sessionId, data);
|
|
3070
3274
|
}
|
|
3071
3275
|
}
|
|
3072
3276
|
});
|