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
|
@@ -2,19 +2,18 @@
|
|
|
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-
|
|
7
|
-
var future = require('./future-Dq4Ha1Dn.cjs');
|
|
5
|
+
var api = require('./api-D9dIR956.cjs');
|
|
6
|
+
var index = require('./index-LYPXVO_L.cjs');
|
|
8
7
|
var types = require('./types-DVk3crez.cjs');
|
|
9
|
-
var
|
|
8
|
+
var node_path = require('node:path');
|
|
10
9
|
var promises = require('node:fs/promises');
|
|
11
10
|
var fs = require('fs/promises');
|
|
12
11
|
var ink = require('ink');
|
|
13
|
-
var registerKillSessionHandler = require('./registerKillSessionHandler-
|
|
12
|
+
var registerKillSessionHandler = require('./registerKillSessionHandler-BDBPoQSA.cjs');
|
|
14
13
|
var React = require('react');
|
|
15
14
|
var node_child_process = require('node:child_process');
|
|
16
15
|
var node_readline = require('node:readline');
|
|
17
|
-
var
|
|
16
|
+
var node_fs = require('node:fs');
|
|
18
17
|
var node_url = require('node:url');
|
|
19
18
|
require('axios');
|
|
20
19
|
require('node:events');
|
|
@@ -23,7 +22,7 @@ require('tweetnacl');
|
|
|
23
22
|
require('expo-server-sdk');
|
|
24
23
|
require('chalk');
|
|
25
24
|
var node_util = require('node:util');
|
|
26
|
-
var persistence = require('./persistence-
|
|
25
|
+
var persistence = require('./persistence-PzKU0QCa.cjs');
|
|
27
26
|
var node_http = require('node:http');
|
|
28
27
|
require('fs');
|
|
29
28
|
require('zod');
|
|
@@ -62,6 +61,7 @@ class Session {
|
|
|
62
61
|
/** JavaScript runtime to use for spawning Claude Code (default: 'node') */
|
|
63
62
|
jsRuntime;
|
|
64
63
|
sessionId;
|
|
64
|
+
transcriptPath = null;
|
|
65
65
|
mode = "local";
|
|
66
66
|
thinking = false;
|
|
67
67
|
/** Callbacks to be notified when session ID is found/changed */
|
|
@@ -115,15 +115,33 @@ class Session {
|
|
|
115
115
|
* Updates internal state, syncs to API metadata, and notifies
|
|
116
116
|
* all registered callbacks (e.g., SessionScanner) about the change.
|
|
117
117
|
*/
|
|
118
|
-
onSessionFound = (sessionId) => {
|
|
118
|
+
onSessionFound = (sessionId, hookData) => {
|
|
119
|
+
const nextTranscriptPathRaw = hookData?.transcript_path ?? hookData?.transcriptPath;
|
|
120
|
+
const nextTranscriptPath = typeof nextTranscriptPathRaw === "string" ? nextTranscriptPathRaw : null;
|
|
121
|
+
const previousSessionId = this.sessionId;
|
|
122
|
+
const previousTranscriptPath = this.transcriptPath;
|
|
119
123
|
this.sessionId = sessionId;
|
|
124
|
+
if (previousSessionId !== sessionId) {
|
|
125
|
+
this.transcriptPath = nextTranscriptPath;
|
|
126
|
+
} else if (nextTranscriptPath) {
|
|
127
|
+
this.transcriptPath = nextTranscriptPath;
|
|
128
|
+
}
|
|
120
129
|
this.client.updateMetadata((metadata) => ({
|
|
121
130
|
...metadata,
|
|
122
|
-
claudeSessionId: sessionId
|
|
131
|
+
claudeSessionId: sessionId,
|
|
132
|
+
claudeTranscriptPath: this.transcriptPath || void 0
|
|
123
133
|
}));
|
|
124
|
-
api.logger.debug(`[Session] Claude
|
|
134
|
+
api.logger.debug(`[Session] Claude session info updated: sessionId=${sessionId}, transcriptPath=${this.transcriptPath ?? "none"}`);
|
|
135
|
+
const didTranscriptPathChange = nextTranscriptPath !== null && nextTranscriptPath !== previousTranscriptPath;
|
|
136
|
+
if (previousSessionId === sessionId && !didTranscriptPathChange) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const info = {
|
|
140
|
+
sessionId,
|
|
141
|
+
transcriptPath: this.transcriptPath
|
|
142
|
+
};
|
|
125
143
|
for (const callback of this.sessionFoundCallbacks) {
|
|
126
|
-
callback(
|
|
144
|
+
callback(info);
|
|
127
145
|
}
|
|
128
146
|
};
|
|
129
147
|
/**
|
|
@@ -146,6 +164,7 @@ class Session {
|
|
|
146
164
|
*/
|
|
147
165
|
clearSessionId = () => {
|
|
148
166
|
this.sessionId = null;
|
|
167
|
+
this.transcriptPath = null;
|
|
149
168
|
api.logger.debug("[Session] Session ID cleared");
|
|
150
169
|
};
|
|
151
170
|
/**
|
|
@@ -182,6 +201,27 @@ class Session {
|
|
|
182
201
|
};
|
|
183
202
|
}
|
|
184
203
|
|
|
204
|
+
class Future {
|
|
205
|
+
_resolve;
|
|
206
|
+
_reject;
|
|
207
|
+
_promise;
|
|
208
|
+
constructor() {
|
|
209
|
+
this._promise = new Promise((resolve, reject) => {
|
|
210
|
+
this._resolve = resolve;
|
|
211
|
+
this._reject = reject;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
resolve(value) {
|
|
215
|
+
this._resolve(value);
|
|
216
|
+
}
|
|
217
|
+
reject(reason) {
|
|
218
|
+
this._reject(reason);
|
|
219
|
+
}
|
|
220
|
+
get promise() {
|
|
221
|
+
return this._promise;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
185
225
|
class InvalidateSync {
|
|
186
226
|
_invalidated = false;
|
|
187
227
|
_invalidatedDouble = false;
|
|
@@ -250,9 +290,51 @@ class InvalidateSync {
|
|
|
250
290
|
|
|
251
291
|
function startFileWatcher(file, onFileChange) {
|
|
252
292
|
const abortController = new AbortController();
|
|
293
|
+
const parentDir = node_path.dirname(file);
|
|
294
|
+
const targetName = node_path.basename(file);
|
|
253
295
|
void (async () => {
|
|
254
296
|
while (true) {
|
|
255
297
|
try {
|
|
298
|
+
try {
|
|
299
|
+
await fs.stat(file);
|
|
300
|
+
} catch (e) {
|
|
301
|
+
if (abortController.signal.aborted) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (e?.code === "ENOENT") {
|
|
305
|
+
api.logger.debug(`[FILE_WATCHER] Waiting for file to exist: ${file}`);
|
|
306
|
+
const dirWatcher = fs.watch(parentDir, { persistent: true, signal: abortController.signal });
|
|
307
|
+
try {
|
|
308
|
+
await fs.stat(file);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
if (err?.code !== "ENOENT") {
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
for await (const event of dirWatcher) {
|
|
314
|
+
if (abortController.signal.aborted) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const name = typeof event?.filename === "string" ? String(event.filename) : null;
|
|
318
|
+
if (name && name !== targetName) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
await fs.stat(file);
|
|
323
|
+
api.logger.debug(`[FILE_WATCHER] File appeared: ${file}`);
|
|
324
|
+
break;
|
|
325
|
+
} catch (nextErr) {
|
|
326
|
+
if (nextErr?.code === "ENOENT") {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
throw nextErr;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
throw e;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
onFileChange(file);
|
|
256
338
|
api.logger.debug(`[FILE_WATCHER] Starting watcher for ${file}`);
|
|
257
339
|
const watcher = fs.watch(file, { persistent: true, signal: abortController.signal });
|
|
258
340
|
for await (const event of watcher) {
|
|
@@ -282,19 +364,67 @@ const INTERNAL_CLAUDE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
282
364
|
"queue-operation"
|
|
283
365
|
]);
|
|
284
366
|
async function createSessionScanner(opts) {
|
|
285
|
-
const
|
|
367
|
+
const initialProjectDir = index.getProjectPath(opts.workingDirectory);
|
|
368
|
+
let projectDirOverride = null;
|
|
369
|
+
const sessionFileOverrides = /* @__PURE__ */ new Map();
|
|
370
|
+
const transcriptMissingWarningMs = opts.transcriptMissingWarningMs ?? 5e3;
|
|
371
|
+
const warnedMissingTranscripts = /* @__PURE__ */ new Set();
|
|
372
|
+
const missingTranscriptTimers = /* @__PURE__ */ new Map();
|
|
373
|
+
function effectiveProjectDir() {
|
|
374
|
+
return projectDirOverride ?? initialProjectDir;
|
|
375
|
+
}
|
|
376
|
+
function getSessionFilePath(sessionId) {
|
|
377
|
+
const override = sessionFileOverrides.get(sessionId);
|
|
378
|
+
return override ?? node_path.join(effectiveProjectDir(), `${sessionId}.jsonl`);
|
|
379
|
+
}
|
|
380
|
+
function scheduleTranscriptMissingWarning(sessionId) {
|
|
381
|
+
if (!opts.onTranscriptMissing) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (!Number.isFinite(transcriptMissingWarningMs) || transcriptMissingWarningMs <= 0) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (warnedMissingTranscripts.has(sessionId) || missingTranscriptTimers.has(sessionId)) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const timeoutId = setTimeout(async () => {
|
|
391
|
+
missingTranscriptTimers.delete(sessionId);
|
|
392
|
+
if (warnedMissingTranscripts.has(sessionId)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const filePath = getSessionFilePath(sessionId);
|
|
396
|
+
try {
|
|
397
|
+
await promises.readFile(filePath, "utf-8");
|
|
398
|
+
return;
|
|
399
|
+
} catch {
|
|
400
|
+
}
|
|
401
|
+
warnedMissingTranscripts.add(sessionId);
|
|
402
|
+
try {
|
|
403
|
+
opts.onTranscriptMissing?.({ sessionId, filePath });
|
|
404
|
+
} catch (err) {
|
|
405
|
+
api.logger.debug("[SESSION_SCANNER] onTranscriptMissing callback threw:", err);
|
|
406
|
+
}
|
|
407
|
+
}, transcriptMissingWarningMs);
|
|
408
|
+
missingTranscriptTimers.set(sessionId, timeoutId);
|
|
409
|
+
}
|
|
286
410
|
let finishedSessions = /* @__PURE__ */ new Set();
|
|
287
411
|
let pendingSessions = /* @__PURE__ */ new Set();
|
|
288
412
|
let currentSessionId = null;
|
|
289
413
|
let watchers = /* @__PURE__ */ new Map();
|
|
290
414
|
let processedMessageKeys = /* @__PURE__ */ new Set();
|
|
415
|
+
if (opts.sessionId && typeof opts.transcriptPath === "string" && opts.transcriptPath.trim()) {
|
|
416
|
+
const transcriptPath = opts.transcriptPath.trim();
|
|
417
|
+
sessionFileOverrides.set(opts.sessionId, transcriptPath);
|
|
418
|
+
projectDirOverride = node_path.dirname(transcriptPath);
|
|
419
|
+
}
|
|
291
420
|
if (opts.sessionId) {
|
|
292
|
-
let messages = await readSessionLog(
|
|
421
|
+
let messages = await readSessionLog(getSessionFilePath(opts.sessionId));
|
|
293
422
|
api.logger.debug(`[SESSION_SCANNER] Marking ${messages.length} existing messages as processed from session ${opts.sessionId}`);
|
|
294
423
|
for (let m of messages) {
|
|
295
424
|
processedMessageKeys.add(messageKey(m));
|
|
296
425
|
}
|
|
297
426
|
currentSessionId = opts.sessionId;
|
|
427
|
+
scheduleTranscriptMissingWarning(opts.sessionId);
|
|
298
428
|
}
|
|
299
429
|
const sync = new InvalidateSync(async () => {
|
|
300
430
|
let sessions = [];
|
|
@@ -310,7 +440,7 @@ async function createSessionScanner(opts) {
|
|
|
310
440
|
}
|
|
311
441
|
}
|
|
312
442
|
for (let session of sessions) {
|
|
313
|
-
const sessionMessages = await readSessionLog(
|
|
443
|
+
const sessionMessages = await readSessionLog(getSessionFilePath(session));
|
|
314
444
|
let skipped = 0;
|
|
315
445
|
let sent = 0;
|
|
316
446
|
for (let file of sessionMessages) {
|
|
@@ -335,11 +465,27 @@ async function createSessionScanner(opts) {
|
|
|
335
465
|
}
|
|
336
466
|
}
|
|
337
467
|
for (let p of sessions) {
|
|
338
|
-
|
|
468
|
+
const desiredPath = getSessionFilePath(p);
|
|
469
|
+
const existing = watchers.get(p);
|
|
470
|
+
if (!existing) {
|
|
339
471
|
api.logger.debug(`[SESSION_SCANNER] Starting watcher for session: ${p}`);
|
|
340
|
-
watchers.set(p,
|
|
341
|
-
|
|
342
|
-
|
|
472
|
+
watchers.set(p, {
|
|
473
|
+
filePath: desiredPath,
|
|
474
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
475
|
+
sync.invalidate();
|
|
476
|
+
})
|
|
477
|
+
});
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (existing.filePath !== desiredPath) {
|
|
481
|
+
api.logger.debug(`[SESSION_SCANNER] Restarting watcher for session: ${p} (${existing.filePath} -> ${desiredPath})`);
|
|
482
|
+
existing.stop();
|
|
483
|
+
watchers.set(p, {
|
|
484
|
+
filePath: desiredPath,
|
|
485
|
+
stop: startFileWatcher(desiredPath, () => {
|
|
486
|
+
sync.invalidate();
|
|
487
|
+
})
|
|
488
|
+
});
|
|
343
489
|
}
|
|
344
490
|
}
|
|
345
491
|
});
|
|
@@ -351,23 +497,55 @@ async function createSessionScanner(opts) {
|
|
|
351
497
|
cleanup: async () => {
|
|
352
498
|
clearInterval(intervalId);
|
|
353
499
|
for (let w of watchers.values()) {
|
|
354
|
-
w();
|
|
500
|
+
w.stop();
|
|
355
501
|
}
|
|
356
502
|
watchers.clear();
|
|
503
|
+
for (const timeoutId of missingTranscriptTimers.values()) {
|
|
504
|
+
clearTimeout(timeoutId);
|
|
505
|
+
}
|
|
506
|
+
missingTranscriptTimers.clear();
|
|
357
507
|
await sync.invalidateAndAwait();
|
|
358
508
|
sync.stop();
|
|
359
509
|
},
|
|
360
|
-
onNewSession: (
|
|
510
|
+
onNewSession: (arg) => {
|
|
511
|
+
const sessionId = typeof arg === "string" ? arg : arg.sessionId;
|
|
512
|
+
const transcriptPathRaw = typeof arg === "string" ? null : arg.transcriptPath;
|
|
513
|
+
const transcriptPath = typeof transcriptPathRaw === "string" && transcriptPathRaw.trim() ? transcriptPathRaw.trim() : null;
|
|
514
|
+
let didUpdatePaths = false;
|
|
515
|
+
if (transcriptPath) {
|
|
516
|
+
const previousOverride = sessionFileOverrides.get(sessionId);
|
|
517
|
+
if (previousOverride !== transcriptPath) {
|
|
518
|
+
sessionFileOverrides.set(sessionId, transcriptPath);
|
|
519
|
+
didUpdatePaths = true;
|
|
520
|
+
}
|
|
521
|
+
const nextProjectDir = node_path.dirname(transcriptPath);
|
|
522
|
+
if (projectDirOverride !== nextProjectDir) {
|
|
523
|
+
projectDirOverride = nextProjectDir;
|
|
524
|
+
didUpdatePaths = true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
361
527
|
if (currentSessionId === sessionId) {
|
|
362
|
-
|
|
528
|
+
if (didUpdatePaths) {
|
|
529
|
+
sync.invalidate();
|
|
530
|
+
} else {
|
|
531
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
|
|
532
|
+
}
|
|
363
533
|
return;
|
|
364
534
|
}
|
|
365
535
|
if (finishedSessions.has(sessionId)) {
|
|
366
|
-
|
|
536
|
+
if (didUpdatePaths) {
|
|
537
|
+
sync.invalidate();
|
|
538
|
+
} else {
|
|
539
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already finished, skipping`);
|
|
540
|
+
}
|
|
367
541
|
return;
|
|
368
542
|
}
|
|
369
543
|
if (pendingSessions.has(sessionId)) {
|
|
370
|
-
|
|
544
|
+
if (didUpdatePaths) {
|
|
545
|
+
sync.invalidate();
|
|
546
|
+
} else {
|
|
547
|
+
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is already pending, skipping`);
|
|
548
|
+
}
|
|
371
549
|
return;
|
|
372
550
|
}
|
|
373
551
|
if (currentSessionId) {
|
|
@@ -375,6 +553,7 @@ async function createSessionScanner(opts) {
|
|
|
375
553
|
}
|
|
376
554
|
api.logger.debug(`[SESSION_SCANNER] New session: ${sessionId}`);
|
|
377
555
|
currentSessionId = sessionId;
|
|
556
|
+
scheduleTranscriptMissingWarning(sessionId);
|
|
378
557
|
sync.invalidate();
|
|
379
558
|
}
|
|
380
559
|
};
|
|
@@ -392,14 +571,13 @@ function messageKey(message) {
|
|
|
392
571
|
throw Error();
|
|
393
572
|
}
|
|
394
573
|
}
|
|
395
|
-
async function readSessionLog(
|
|
396
|
-
|
|
397
|
-
api.logger.debug(`[SESSION_SCANNER] Reading session file: ${expectedSessionFile}`);
|
|
574
|
+
async function readSessionLog(sessionFilePath) {
|
|
575
|
+
api.logger.debug(`[SESSION_SCANNER] Reading session file: ${sessionFilePath}`);
|
|
398
576
|
let file;
|
|
399
577
|
try {
|
|
400
|
-
file = await promises.readFile(
|
|
578
|
+
file = await promises.readFile(sessionFilePath, "utf-8");
|
|
401
579
|
} catch (error) {
|
|
402
|
-
api.logger.debug(`[SESSION_SCANNER] Session file not found: ${
|
|
580
|
+
api.logger.debug(`[SESSION_SCANNER] Session file not found: ${sessionFilePath}`);
|
|
403
581
|
return [];
|
|
404
582
|
}
|
|
405
583
|
let lines = file.split("\n");
|
|
@@ -429,20 +607,30 @@ async function readSessionLog(projectDir, sessionId) {
|
|
|
429
607
|
async function claudeLocalLauncher(session) {
|
|
430
608
|
const scanner = await createSessionScanner({
|
|
431
609
|
sessionId: session.sessionId,
|
|
610
|
+
transcriptPath: session.transcriptPath,
|
|
432
611
|
workingDirectory: session.path,
|
|
433
612
|
onMessage: (message) => {
|
|
434
613
|
if (message.type !== "summary") {
|
|
435
614
|
session.client.sendClaudeSessionMessage(message);
|
|
436
615
|
}
|
|
616
|
+
},
|
|
617
|
+
onTranscriptMissing: () => {
|
|
618
|
+
session.client.sendSessionEvent({
|
|
619
|
+
type: "message",
|
|
620
|
+
message: "Claude transcript file not found yet, waiting for it to appear..."
|
|
621
|
+
});
|
|
437
622
|
}
|
|
438
623
|
});
|
|
439
|
-
const scannerSessionCallback = (
|
|
440
|
-
scanner.onNewSession(
|
|
624
|
+
const scannerSessionCallback = (info) => {
|
|
625
|
+
scanner.onNewSession({
|
|
626
|
+
sessionId: info.sessionId,
|
|
627
|
+
transcriptPath: info.transcriptPath
|
|
628
|
+
});
|
|
441
629
|
};
|
|
442
630
|
session.addSessionFoundCallback(scannerSessionCallback);
|
|
443
631
|
let exitReason = null;
|
|
444
632
|
const processAbortController = new AbortController();
|
|
445
|
-
let exutFuture = new
|
|
633
|
+
let exutFuture = new Future();
|
|
446
634
|
try {
|
|
447
635
|
async function abort() {
|
|
448
636
|
if (!processAbortController.signal.aborted) {
|
|
@@ -475,7 +663,6 @@ async function claudeLocalLauncher(session) {
|
|
|
475
663
|
}
|
|
476
664
|
const handleSessionStart = (sessionId) => {
|
|
477
665
|
session.onSessionFound(sessionId);
|
|
478
|
-
scanner.onNewSession(sessionId);
|
|
479
666
|
};
|
|
480
667
|
while (true) {
|
|
481
668
|
if (exitReason) {
|
|
@@ -750,8 +937,8 @@ class AbortError extends Error {
|
|
|
750
937
|
}
|
|
751
938
|
}
|
|
752
939
|
|
|
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-
|
|
754
|
-
const __dirname$1 =
|
|
940
|
+
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-IeRSC5qX.cjs', document.baseURI).href)));
|
|
941
|
+
const __dirname$1 = node_path.join(__filename$1, "..");
|
|
755
942
|
function getGlobalClaudeVersion() {
|
|
756
943
|
try {
|
|
757
944
|
const cleanEnv = getCleanEnv();
|
|
@@ -815,7 +1002,7 @@ function findGlobalClaudePath() {
|
|
|
815
1002
|
cwd: homeDir,
|
|
816
1003
|
env: cleanEnv
|
|
817
1004
|
}).trim();
|
|
818
|
-
if (result &&
|
|
1005
|
+
if (result && node_fs.existsSync(result)) {
|
|
819
1006
|
api.logger.debug(`[Claude SDK] Found global claude path via which: ${result}`);
|
|
820
1007
|
return result;
|
|
821
1008
|
}
|
|
@@ -825,7 +1012,7 @@ function findGlobalClaudePath() {
|
|
|
825
1012
|
return null;
|
|
826
1013
|
}
|
|
827
1014
|
function getDefaultClaudeCodePath() {
|
|
828
|
-
const nodeModulesPath =
|
|
1015
|
+
const nodeModulesPath = node_path.join(__dirname$1, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
829
1016
|
if (process.env.HAPPY_CLAUDE_PATH) {
|
|
830
1017
|
api.logger.debug(`[Claude SDK] Using HAPPY_CLAUDE_PATH: ${process.env.HAPPY_CLAUDE_PATH}`);
|
|
831
1018
|
return process.env.HAPPY_CLAUDE_PATH;
|
|
@@ -1114,7 +1301,7 @@ function query(config) {
|
|
|
1114
1301
|
}
|
|
1115
1302
|
const isJsFile = pathToClaudeCodeExecutable.endsWith(".js") || pathToClaudeCodeExecutable.endsWith(".cjs");
|
|
1116
1303
|
const isCommandOnly = pathToClaudeCodeExecutable === "claude";
|
|
1117
|
-
if (!isCommandOnly && !
|
|
1304
|
+
if (!isCommandOnly && !node_fs.existsSync(pathToClaudeCodeExecutable)) {
|
|
1118
1305
|
throw new ReferenceError(`Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`);
|
|
1119
1306
|
}
|
|
1120
1307
|
const spawnCommand = isJsFile ? executable : pathToClaudeCodeExecutable;
|
|
@@ -1371,17 +1558,17 @@ async function awaitFileExist(file, timeout = 1e4) {
|
|
|
1371
1558
|
}
|
|
1372
1559
|
|
|
1373
1560
|
function getClaudeSettingsPath() {
|
|
1374
|
-
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR ||
|
|
1375
|
-
return
|
|
1561
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || node_path.join(os.homedir(), ".claude");
|
|
1562
|
+
return node_path.join(claudeConfigDir, "settings.json");
|
|
1376
1563
|
}
|
|
1377
1564
|
function readClaudeSettings() {
|
|
1378
1565
|
try {
|
|
1379
1566
|
const settingsPath = getClaudeSettingsPath();
|
|
1380
|
-
if (!
|
|
1567
|
+
if (!node_fs.existsSync(settingsPath)) {
|
|
1381
1568
|
api.logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
|
|
1382
1569
|
return null;
|
|
1383
1570
|
}
|
|
1384
|
-
const settingsContent =
|
|
1571
|
+
const settingsContent = node_fs.readFileSync(settingsPath, "utf-8");
|
|
1385
1572
|
const settings = JSON.parse(settingsContent);
|
|
1386
1573
|
api.logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
|
|
1387
1574
|
api.logger.debug(`[ClaudeSettings] includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
|
|
@@ -1424,7 +1611,7 @@ const systemPrompt = (() => {
|
|
|
1424
1611
|
|
|
1425
1612
|
async function claudeRemote(opts) {
|
|
1426
1613
|
let startFrom = opts.sessionId;
|
|
1427
|
-
if (opts.sessionId && !index.claudeCheckSession(opts.sessionId, opts.path)) {
|
|
1614
|
+
if (opts.sessionId && !index.claudeCheckSession(opts.sessionId, opts.path, opts.transcriptPath)) {
|
|
1428
1615
|
startFrom = null;
|
|
1429
1616
|
}
|
|
1430
1617
|
if (!startFrom && opts.claudeArgs) {
|
|
@@ -1490,7 +1677,7 @@ async function claudeRemote(opts) {
|
|
|
1490
1677
|
executable: opts.jsRuntime ?? "node",
|
|
1491
1678
|
abort: opts.signal,
|
|
1492
1679
|
pathToClaudeCodeExecutable: (() => {
|
|
1493
|
-
return
|
|
1680
|
+
return node_path.resolve(node_path.join(index.projectPath(), "scripts", "claude_remote_launcher.cjs"));
|
|
1494
1681
|
})(),
|
|
1495
1682
|
settingsPath: opts.hookSettingsPath
|
|
1496
1683
|
};
|
|
@@ -1526,11 +1713,14 @@ async function claudeRemote(opts) {
|
|
|
1526
1713
|
updateThinking(true);
|
|
1527
1714
|
const systemInit = message;
|
|
1528
1715
|
if (systemInit.session_id) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
const found = await awaitFileExist(
|
|
1716
|
+
const transcriptPath = opts.transcriptPath && opts.sessionId === systemInit.session_id ? opts.transcriptPath : node_path.join(index.getProjectPath(opts.path), `${systemInit.session_id}.jsonl`);
|
|
1717
|
+
api.logger.debug(`[claudeRemote] Waiting for session file to be written to disk: ${transcriptPath}`);
|
|
1718
|
+
const found = await awaitFileExist(transcriptPath);
|
|
1532
1719
|
api.logger.debug(`[claudeRemote] Session file found: ${systemInit.session_id} ${found}`);
|
|
1533
|
-
opts.onSessionFound(systemInit.session_id
|
|
1720
|
+
opts.onSessionFound(systemInit.session_id, {
|
|
1721
|
+
transcript_path: transcriptPath,
|
|
1722
|
+
transcriptPath
|
|
1723
|
+
});
|
|
1534
1724
|
}
|
|
1535
1725
|
}
|
|
1536
1726
|
if (message.type === "result") {
|
|
@@ -1983,11 +2173,21 @@ function formatClaudeMessageForInk(message, messageBuffer, onAssistantResult) {
|
|
|
1983
2173
|
case "assistant": {
|
|
1984
2174
|
const assistantMsg = message;
|
|
1985
2175
|
if (assistantMsg.message && assistantMsg.message.content) {
|
|
1986
|
-
|
|
2176
|
+
let assistantHeaderShown = false;
|
|
1987
2177
|
for (const block of assistantMsg.message.content) {
|
|
1988
|
-
if (block.type === "
|
|
2178
|
+
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim()) {
|
|
2179
|
+
messageBuffer.addMessage(`[Thinking] ${block.thinking}`, "status");
|
|
2180
|
+
} else if (block.type === "text") {
|
|
2181
|
+
if (!assistantHeaderShown) {
|
|
2182
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2183
|
+
assistantHeaderShown = true;
|
|
2184
|
+
}
|
|
1989
2185
|
messageBuffer.addMessage(block.text || "", "assistant");
|
|
1990
2186
|
} else if (block.type === "tool_use") {
|
|
2187
|
+
if (!assistantHeaderShown) {
|
|
2188
|
+
messageBuffer.addMessage("\u{1F916} Assistant:", "assistant");
|
|
2189
|
+
assistantHeaderShown = true;
|
|
2190
|
+
}
|
|
1991
2191
|
messageBuffer.addMessage(`\u{1F527} Tool: ${block.name}`, "tool");
|
|
1992
2192
|
if (block.input) {
|
|
1993
2193
|
const inputStr = JSON.stringify(block.input, null, 2);
|
|
@@ -2627,12 +2827,13 @@ async function claudeRemoteLauncher(session) {
|
|
|
2627
2827
|
previousSessionId = session.sessionId;
|
|
2628
2828
|
const controller = new AbortController();
|
|
2629
2829
|
abortController = controller;
|
|
2630
|
-
abortFuture = new
|
|
2830
|
+
abortFuture = new Future();
|
|
2631
2831
|
let modeHash = null;
|
|
2632
2832
|
let mode = null;
|
|
2633
2833
|
try {
|
|
2634
2834
|
const remoteResult = await claudeRemote({
|
|
2635
2835
|
sessionId: session.sessionId,
|
|
2836
|
+
transcriptPath: session.transcriptPath,
|
|
2636
2837
|
path: session.path,
|
|
2637
2838
|
allowedTools: session.allowedTools ?? [],
|
|
2638
2839
|
mcpServers: session.mcpServers,
|
|
@@ -2666,9 +2867,9 @@ async function claudeRemoteLauncher(session) {
|
|
|
2666
2867
|
}
|
|
2667
2868
|
return null;
|
|
2668
2869
|
},
|
|
2669
|
-
onSessionFound: (sessionId) => {
|
|
2870
|
+
onSessionFound: (sessionId, data) => {
|
|
2670
2871
|
sdkToLogConverter.updateSessionId(sessionId);
|
|
2671
|
-
session.onSessionFound(sessionId);
|
|
2872
|
+
session.onSessionFound(sessionId, data);
|
|
2672
2873
|
},
|
|
2673
2874
|
onThinkingChange: session.onThinkingChange,
|
|
2674
2875
|
claudeEnvVars: session.claudeEnvVars,
|
|
@@ -2857,13 +3058,20 @@ async function startHookServer(options) {
|
|
|
2857
3058
|
}
|
|
2858
3059
|
clearTimeout(timeout);
|
|
2859
3060
|
const body = Buffer.concat(chunks).toString("utf-8");
|
|
2860
|
-
api.logger.debug("[hookServer] Received session hook:", body);
|
|
2861
3061
|
let data = {};
|
|
2862
3062
|
try {
|
|
2863
3063
|
data = JSON.parse(body);
|
|
2864
3064
|
} catch (parseError) {
|
|
2865
3065
|
api.logger.debug("[hookServer] Failed to parse hook data as JSON:", parseError);
|
|
2866
3066
|
}
|
|
3067
|
+
api.logger.debug("[hookServer] Received session hook", {
|
|
3068
|
+
sessionId: data.session_id || data.sessionId || null,
|
|
3069
|
+
transcriptPath: data.transcript_path || data.transcriptPath || null,
|
|
3070
|
+
cwd: data.cwd,
|
|
3071
|
+
hookEventName: data.hook_event_name,
|
|
3072
|
+
source: data.source,
|
|
3073
|
+
bodyLength: body.length
|
|
3074
|
+
});
|
|
2867
3075
|
const sessionId = data.session_id || data.sessionId;
|
|
2868
3076
|
if (sessionId) {
|
|
2869
3077
|
api.logger.debug(`[hookServer] Session hook received session ID: ${sessionId}`);
|
|
@@ -2907,11 +3115,11 @@ async function startHookServer(options) {
|
|
|
2907
3115
|
}
|
|
2908
3116
|
|
|
2909
3117
|
function generateHookSettingsFile(port) {
|
|
2910
|
-
const hooksDir =
|
|
2911
|
-
|
|
3118
|
+
const hooksDir = node_path.join(api.configuration.happyCloudHomeDir, "tmp", "hooks");
|
|
3119
|
+
node_fs.mkdirSync(hooksDir, { recursive: true });
|
|
2912
3120
|
const filename = `session-hook-${process.pid}.json`;
|
|
2913
|
-
const filepath =
|
|
2914
|
-
const forwarderScript =
|
|
3121
|
+
const filepath = node_path.join(hooksDir, filename);
|
|
3122
|
+
const forwarderScript = node_path.resolve(index.projectPath(), "scripts", "session_hook_forwarder.cjs");
|
|
2915
3123
|
const hookCommand = `node "${forwarderScript}" ${port}`;
|
|
2916
3124
|
const settings = {
|
|
2917
3125
|
hooks: {
|
|
@@ -2928,14 +3136,14 @@ function generateHookSettingsFile(port) {
|
|
|
2928
3136
|
]
|
|
2929
3137
|
}
|
|
2930
3138
|
};
|
|
2931
|
-
|
|
3139
|
+
node_fs.writeFileSync(filepath, JSON.stringify(settings, null, 2));
|
|
2932
3140
|
api.logger.debug(`[generateHookSettings] Created hook settings file: ${filepath}`);
|
|
2933
3141
|
return filepath;
|
|
2934
3142
|
}
|
|
2935
3143
|
function cleanupHookSettingsFile(filepath) {
|
|
2936
3144
|
try {
|
|
2937
|
-
if (
|
|
2938
|
-
|
|
3145
|
+
if (node_fs.existsSync(filepath)) {
|
|
3146
|
+
node_fs.unlinkSync(filepath);
|
|
2939
3147
|
api.logger.debug(`[generateHookSettings] Cleaned up hook settings file: ${filepath}`);
|
|
2940
3148
|
}
|
|
2941
3149
|
} catch (error) {
|
|
@@ -2976,7 +3184,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
2976
3184
|
homeDir: os.homedir(),
|
|
2977
3185
|
happyHomeDir: api.configuration.happyCloudHomeDir,
|
|
2978
3186
|
happyLibDir: index.projectPath(),
|
|
2979
|
-
happyToolsDir:
|
|
3187
|
+
happyToolsDir: node_path.resolve(index.projectPath(), "tools", "unpacked"),
|
|
2980
3188
|
startedFromDaemon: options.startedBy === "daemon",
|
|
2981
3189
|
hostPid: process.pid,
|
|
2982
3190
|
startedBy: options.startedBy || "terminal",
|
|
@@ -3065,11 +3273,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
3065
3273
|
onSessionHook: (sessionId, data) => {
|
|
3066
3274
|
api.logger.debug(`[START] Session hook received: ${sessionId}`, data);
|
|
3067
3275
|
if (currentSession) {
|
|
3068
|
-
|
|
3069
|
-
if (previousSessionId !== sessionId) {
|
|
3070
|
-
api.logger.debug(`[START] Claude session ID changed: ${previousSessionId} -> ${sessionId}`);
|
|
3071
|
-
currentSession.onSessionFound(sessionId);
|
|
3072
|
-
}
|
|
3276
|
+
currentSession.onSessionFound(sessionId, data);
|
|
3073
3277
|
}
|
|
3074
3278
|
}
|
|
3075
3279
|
});
|