happy-imou-cloud 1.1.7 → 2.0.0

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.
Files changed (36) hide show
  1. package/dist/{setupOfflineReconnection-ndObLZk0.mjs → BaseReasoningProcessor-BKLRCKTU.mjs} +133 -90
  2. package/dist/{setupOfflineReconnection-obypStdD.cjs → BaseReasoningProcessor-BRCQXCZY.cjs} +134 -90
  3. package/dist/{types-BXyraW9R.mjs → api-BGXYX0yH.mjs} +198 -170
  4. package/dist/{types-BSTmyv9d.cjs → api-D7OK-mML.cjs} +219 -192
  5. package/dist/command-CnLtKtP-.mjs +51 -0
  6. package/dist/command-G85giEAF.cjs +54 -0
  7. package/dist/future-Dq4Ha1Dn.cjs +24 -0
  8. package/dist/future-xRdLl3vf.mjs +22 -0
  9. package/dist/{index-DVI4b0mv.cjs → index-B_wlQBy2.cjs} +5493 -7142
  10. package/dist/{index-CUmYqKWt.mjs → index-C7Y0R-MI.mjs} +5482 -7143
  11. package/dist/index.cjs +19 -21
  12. package/dist/index.mjs +19 -21
  13. package/dist/lib.cjs +3 -2
  14. package/dist/lib.d.cts +17 -0
  15. package/dist/lib.d.mts +17 -0
  16. package/dist/lib.mjs +2 -1
  17. package/dist/{persistence-BGsuPqaO.mjs → persistence-BA_unuca.mjs} +8 -4
  18. package/dist/{persistence-BRH9F6RS.cjs → persistence-DHgf1CTG.cjs} +10 -6
  19. package/dist/registerKillSessionHandler-C2-yHm1V.mjs +428 -0
  20. package/dist/registerKillSessionHandler-CLREXN11.cjs +433 -0
  21. package/dist/runClaude-CwAitpX-.cjs +3274 -0
  22. package/dist/runClaude-uNC5Eym4.mjs +3271 -0
  23. package/dist/runCodex-B-05E-YZ.mjs +1846 -0
  24. package/dist/runCodex-Cm0VTqw_.cjs +1848 -0
  25. package/dist/{runGemini-C3dDtGOV.cjs → runGemini-CLWjwDYS.cjs} +25 -1366
  26. package/dist/{runGemini-B-EK_BJQ.mjs → runGemini-_biXvQAH.mjs} +12 -1353
  27. package/dist/types-CiliQpqS.mjs +52 -0
  28. package/dist/types-DVk3crez.cjs +54 -0
  29. package/package.json +13 -12
  30. package/scripts/devtools/README.md +9 -0
  31. package/scripts/devtools/generate-mock-credentials.ts +94 -0
  32. package/scripts/release-smoke.mjs +62 -0
  33. package/dist/config-BQNrtwRY.cjs +0 -183
  34. package/dist/config-Dn99YH37.mjs +0 -173
  35. package/dist/runCodex-Cez8cuIh.cjs +0 -1143
  36. package/dist/runCodex-X0BfjcZH.mjs +0 -1140
@@ -5,7 +5,7 @@ var chalk = require('chalk');
5
5
  var fs$1 = require('fs');
6
6
  var fs = require('node:fs');
7
7
  var os = require('node:os');
8
- var node_path = require('node:path');
8
+ var path = require('node:path');
9
9
  var node_events = require('node:events');
10
10
  var socket_ioClient = require('socket.io-client');
11
11
  var z = require('zod');
@@ -15,11 +15,11 @@ var child_process = require('child_process');
15
15
  var util = require('util');
16
16
  var fs$2 = require('fs/promises');
17
17
  var crypto = require('crypto');
18
- var path = require('path');
18
+ var path$1 = require('path');
19
19
  var expoServerSdk = require('expo-server-sdk');
20
20
 
21
21
  var name = "happy-imou-cloud";
22
- var version = "1.1.7";
22
+ var version = "2.0.0";
23
23
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
24
24
  var author = "long.zhu";
25
25
  var license = "MIT";
@@ -64,22 +64,23 @@ var scripts = {
64
64
  typecheck: "tsc --noEmit",
65
65
  build: "shx rm -rf dist && npx tsc --noEmit && pkgroll",
66
66
  "// ==== Testing ====": "",
67
- test: "$npm_execpath run build && vitest run",
68
- "test:integration": "$npm_execpath run build && vitest run --config vitest.integration.config.ts",
67
+ test: "yarn build && vitest run",
68
+ "test:integration": "yarn build && vitest run --config vitest.integration.config.ts",
69
69
  "test:integration:watch": "vitest run --config vitest.integration.config.ts --watch",
70
- "test:coverage": "$npm_execpath run build && vitest run --coverage && node scripts/generate-coverage-report.js",
70
+ "test:coverage": "yarn build && vitest run --coverage && node scripts/generate-coverage-report.js",
71
71
  "// ==== Benchmarks ====": "",
72
- bench: "$npm_execpath run build && vitest bench src/daemon/integration/benchmarks/",
73
- "bench:auth": "$npm_execpath run build && vitest bench src/daemon/integration/benchmarks/auth.bench.ts",
72
+ bench: "yarn build && vitest bench src/daemon/integration/benchmarks/",
73
+ "bench:auth": "yarn build && vitest bench src/daemon/integration/benchmarks/auth.bench.ts",
74
74
  "bench:report": "node scripts/generate-benchmark-report.js",
75
75
  "// ==== Start & Dev ====": "",
76
- start: "$npm_execpath run build && node ./bin/happy-cloud.mjs",
76
+ start: "yarn build && node ./bin/happy-cloud.mjs",
77
77
  dev: "tsx src/index.ts",
78
- "dev:local-server": "$npm_execpath run build && tsx --env-file .env.dev-local-server src/index.ts",
79
- "dev:integration-test-env": "$npm_execpath run build && tsx --env-file .env.integration-test src/index.ts",
78
+ "dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
79
+ "dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
80
80
  "// ==== Release ====": "",
81
81
  prepublishOnly: "npm run build",
82
- release: "$npm_execpath install && release-it",
82
+ release: "yarn install && release-it",
83
+ "release:smoke": "node ./scripts/release-smoke.mjs",
83
84
  "// ==== Dev/Stable Variant Management ====": "",
84
85
  stable: "node scripts/env-wrapper.cjs stable",
85
86
  "dev:variant": "node scripts/env-wrapper.cjs dev",
@@ -217,7 +218,7 @@ class Configuration {
217
218
  const expandedPath = process.env.HAPPY_CLOUD_HOME_DIR.replace(/^~/, os.homedir());
218
219
  this.happyCloudHomeDir = expandedPath;
219
220
  } else {
220
- this.happyCloudHomeDir = node_path.join(os.homedir(), ".happy-cloud");
221
+ this.happyCloudHomeDir = path.join(os.homedir(), ".happy-cloud");
221
222
  }
222
223
  this.happyHomeDir = this.happyCloudHomeDir;
223
224
  } else {
@@ -225,15 +226,15 @@ class Configuration {
225
226
  const expandedPath = process.env.HAPPY_HOME_DIR.replace(/^~/, os.homedir());
226
227
  this.happyHomeDir = expandedPath;
227
228
  } else {
228
- this.happyHomeDir = node_path.join(os.homedir(), ".happy");
229
+ this.happyHomeDir = path.join(os.homedir(), ".happy");
229
230
  }
230
231
  this.happyCloudHomeDir = this.happyHomeDir;
231
232
  }
232
- this.logsDir = node_path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "logs");
233
- this.settingsFile = node_path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "settings.json");
234
- this.privateKeyFile = node_path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "access.key");
235
- this.daemonStateFile = node_path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "daemon.state.json");
236
- this.daemonLockFile = node_path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "daemon.state.json.lock");
233
+ this.logsDir = path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "logs");
234
+ this.settingsFile = path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "settings.json");
235
+ this.privateKeyFile = path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "access.key");
236
+ this.daemonStateFile = path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "daemon.state.json");
237
+ this.daemonLockFile = path.join(this.isHappyCloudMode ? this.happyCloudHomeDir : this.happyHomeDir, "daemon.state.json.lock");
237
238
  this.isExperimentalEnabled = ["true", "1", "yes"].includes(process.env.HAPPY_EXPERIMENTAL?.toLowerCase() || "");
238
239
  this.disableCaffeinate = ["true", "1", "yes"].includes(process.env.HAPPY_DISABLE_CAFFEINATE?.toLowerCase() || "");
239
240
  this.currentCliVersion = packageJson.version;
@@ -285,7 +286,7 @@ function createTimestampForLogEntry(date = /* @__PURE__ */ new Date()) {
285
286
  function getSessionLogPath() {
286
287
  const timestamp = createTimestampForFilename();
287
288
  const filename = configuration.isDaemonProcess ? `${timestamp}-daemon.log` : `${timestamp}.log`;
288
- return node_path.join(configuration.logsDir, filename);
289
+ return path.join(configuration.logsDir, filename);
289
290
  }
290
291
  class Logger {
291
292
  constructor(logFilePath = getSessionLogPath()) {
@@ -427,12 +428,12 @@ async function listDaemonLogFiles(limit = 50) {
427
428
  return [];
428
429
  }
429
430
  const logs = fs.readdirSync(logsDir).filter((file) => file.endsWith("-daemon.log")).map((file) => {
430
- const fullPath = node_path.join(logsDir, file);
431
+ const fullPath = path.join(logsDir, file);
431
432
  const stats = fs.statSync(fullPath);
432
433
  return { file, path: fullPath, modified: stats.mtime };
433
434
  }).sort((a, b) => b.modified.getTime() - a.modified.getTime());
434
435
  try {
435
- const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-BRH9F6RS.cjs'); });
436
+ const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-DHgf1CTG.cjs'); });
436
437
  const state = await readDaemonState();
437
438
  if (!state) {
438
439
  return logs;
@@ -440,7 +441,7 @@ async function listDaemonLogFiles(limit = 50) {
440
441
  if (state.daemonLogPath && fs.existsSync(state.daemonLogPath)) {
441
442
  const stats = fs.statSync(state.daemonLogPath);
442
443
  const persisted = {
443
- file: node_path.basename(state.daemonLogPath),
444
+ file: path.basename(state.daemonLogPath),
444
445
  path: state.daemonLogPath,
445
446
  modified: stats.mtime
446
447
  };
@@ -464,6 +465,108 @@ async function getLatestDaemonLog() {
464
465
  return latest || null;
465
466
  }
466
467
 
468
+ function encodeBase64(buffer, variant = "base64") {
469
+ if (variant === "base64url") {
470
+ return encodeBase64Url(buffer);
471
+ }
472
+ return Buffer.from(buffer).toString("base64");
473
+ }
474
+ function encodeBase64Url(buffer) {
475
+ return Buffer.from(buffer).toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
476
+ }
477
+ function decodeBase64(base64, variant = "base64") {
478
+ if (variant === "base64url") {
479
+ const base64Standard = base64.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - base64.length % 4) % 4);
480
+ return new Uint8Array(Buffer.from(base64Standard, "base64"));
481
+ }
482
+ return new Uint8Array(Buffer.from(base64, "base64"));
483
+ }
484
+ function getRandomBytes(size) {
485
+ return new Uint8Array(node_crypto.randomBytes(size));
486
+ }
487
+ function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
488
+ const ephemeralKeyPair = tweetnacl.box.keyPair();
489
+ const nonce = getRandomBytes(tweetnacl.box.nonceLength);
490
+ const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
491
+ const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
492
+ result.set(ephemeralKeyPair.publicKey, 0);
493
+ result.set(nonce, ephemeralKeyPair.publicKey.length);
494
+ result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
495
+ return result;
496
+ }
497
+ function encryptLegacy(data, secret) {
498
+ const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
499
+ const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
500
+ const result = new Uint8Array(nonce.length + encrypted.length);
501
+ result.set(nonce);
502
+ result.set(encrypted, nonce.length);
503
+ return result;
504
+ }
505
+ function decryptLegacy(data, secret) {
506
+ const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
507
+ const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
508
+ const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
509
+ if (!decrypted) {
510
+ return null;
511
+ }
512
+ return JSON.parse(new TextDecoder().decode(decrypted));
513
+ }
514
+ function encryptWithDataKey(data, dataKey) {
515
+ const nonce = getRandomBytes(12);
516
+ const cipher = node_crypto.createCipheriv("aes-256-gcm", dataKey, nonce);
517
+ const plaintext = new TextEncoder().encode(JSON.stringify(data));
518
+ const encrypted = Buffer.concat([
519
+ cipher.update(plaintext),
520
+ cipher.final()
521
+ ]);
522
+ const authTag = cipher.getAuthTag();
523
+ const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
524
+ bundle.set([0], 0);
525
+ bundle.set(nonce, 1);
526
+ bundle.set(new Uint8Array(encrypted), 13);
527
+ bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
528
+ return bundle;
529
+ }
530
+ function decryptWithDataKey(bundle, dataKey) {
531
+ if (bundle.length < 1) {
532
+ return null;
533
+ }
534
+ if (bundle[0] !== 0) {
535
+ return null;
536
+ }
537
+ if (bundle.length < 12 + 16 + 1) {
538
+ return null;
539
+ }
540
+ const nonce = bundle.slice(1, 13);
541
+ const authTag = bundle.slice(bundle.length - 16);
542
+ const ciphertext = bundle.slice(13, bundle.length - 16);
543
+ try {
544
+ const decipher = node_crypto.createDecipheriv("aes-256-gcm", dataKey, nonce);
545
+ decipher.setAuthTag(authTag);
546
+ const decrypted = Buffer.concat([
547
+ decipher.update(ciphertext),
548
+ decipher.final()
549
+ ]);
550
+ return JSON.parse(new TextDecoder().decode(decrypted));
551
+ } catch (error) {
552
+ return null;
553
+ }
554
+ }
555
+ function encrypt(key, variant, data) {
556
+ if (variant === "legacy") {
557
+ return encryptLegacy(data, key);
558
+ } else {
559
+ return encryptWithDataKey(data, key);
560
+ }
561
+ }
562
+ function decrypt(key, variant, data) {
563
+ if (variant === "legacy") {
564
+ return decryptLegacy(data, key);
565
+ } else {
566
+ return decryptWithDataKey(data, key);
567
+ }
568
+ }
569
+
467
570
  const SessionMessageContentSchema = z.z.object({
468
571
  c: z.z.string(),
469
572
  // Base64 encoded encrypted content
@@ -595,108 +698,6 @@ const AgentMessageSchema = z.z.object({
595
698
  });
596
699
  z.z.union([UserMessageSchema, AgentMessageSchema]);
597
700
 
598
- function encodeBase64(buffer, variant = "base64") {
599
- if (variant === "base64url") {
600
- return encodeBase64Url(buffer);
601
- }
602
- return Buffer.from(buffer).toString("base64");
603
- }
604
- function encodeBase64Url(buffer) {
605
- return Buffer.from(buffer).toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
606
- }
607
- function decodeBase64(base64, variant = "base64") {
608
- if (variant === "base64url") {
609
- const base64Standard = base64.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - base64.length % 4) % 4);
610
- return new Uint8Array(Buffer.from(base64Standard, "base64"));
611
- }
612
- return new Uint8Array(Buffer.from(base64, "base64"));
613
- }
614
- function getRandomBytes(size) {
615
- return new Uint8Array(node_crypto.randomBytes(size));
616
- }
617
- function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
618
- const ephemeralKeyPair = tweetnacl.box.keyPair();
619
- const nonce = getRandomBytes(tweetnacl.box.nonceLength);
620
- const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
621
- const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
622
- result.set(ephemeralKeyPair.publicKey, 0);
623
- result.set(nonce, ephemeralKeyPair.publicKey.length);
624
- result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
625
- return result;
626
- }
627
- function encryptLegacy(data, secret) {
628
- const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
629
- const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
630
- const result = new Uint8Array(nonce.length + encrypted.length);
631
- result.set(nonce);
632
- result.set(encrypted, nonce.length);
633
- return result;
634
- }
635
- function decryptLegacy(data, secret) {
636
- const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
637
- const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
638
- const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
639
- if (!decrypted) {
640
- return null;
641
- }
642
- return JSON.parse(new TextDecoder().decode(decrypted));
643
- }
644
- function encryptWithDataKey(data, dataKey) {
645
- const nonce = getRandomBytes(12);
646
- const cipher = node_crypto.createCipheriv("aes-256-gcm", dataKey, nonce);
647
- const plaintext = new TextEncoder().encode(JSON.stringify(data));
648
- const encrypted = Buffer.concat([
649
- cipher.update(plaintext),
650
- cipher.final()
651
- ]);
652
- const authTag = cipher.getAuthTag();
653
- const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
654
- bundle.set([0], 0);
655
- bundle.set(nonce, 1);
656
- bundle.set(new Uint8Array(encrypted), 13);
657
- bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
658
- return bundle;
659
- }
660
- function decryptWithDataKey(bundle, dataKey) {
661
- if (bundle.length < 1) {
662
- return null;
663
- }
664
- if (bundle[0] !== 0) {
665
- return null;
666
- }
667
- if (bundle.length < 12 + 16 + 1) {
668
- return null;
669
- }
670
- const nonce = bundle.slice(1, 13);
671
- const authTag = bundle.slice(bundle.length - 16);
672
- const ciphertext = bundle.slice(13, bundle.length - 16);
673
- try {
674
- const decipher = node_crypto.createDecipheriv("aes-256-gcm", dataKey, nonce);
675
- decipher.setAuthTag(authTag);
676
- const decrypted = Buffer.concat([
677
- decipher.update(ciphertext),
678
- decipher.final()
679
- ]);
680
- return JSON.parse(new TextDecoder().decode(decrypted));
681
- } catch (error) {
682
- return null;
683
- }
684
- }
685
- function encrypt(key, variant, data) {
686
- if (variant === "legacy") {
687
- return encryptLegacy(data, key);
688
- } else {
689
- return encryptWithDataKey(data, key);
690
- }
691
- }
692
- function decrypt(key, variant, data) {
693
- if (variant === "legacy") {
694
- return decryptLegacy(data, key);
695
- } else {
696
- return decryptWithDataKey(data, key);
697
- }
698
- }
699
-
700
701
  async function delay(ms) {
701
702
  return new Promise((resolve) => setTimeout(resolve, ms));
702
703
  }
@@ -853,8 +854,8 @@ class RpcHandlerManager {
853
854
  }
854
855
 
855
856
  function validatePath(targetPath, workingDirectory) {
856
- const resolvedTarget = path.resolve(workingDirectory, targetPath);
857
- const resolvedWorkingDir = path.resolve(workingDirectory);
857
+ const resolvedTarget = path$1.resolve(workingDirectory, targetPath);
858
+ const resolvedWorkingDir = path$1.resolve(workingDirectory);
858
859
  const targetNormalized = resolvedTarget.replace(/\\/g, "/");
859
860
  const workingDirNormalized = resolvedWorkingDir.replace(/\\/g, "/");
860
861
  process.platform === "win32" ? "\\" : "/";
@@ -1008,7 +1009,7 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory) {
1008
1009
  const entries = await fs$2.readdir(data.path, { withFileTypes: true });
1009
1010
  const directoryEntries = await Promise.all(
1010
1011
  entries.map(async (entry) => {
1011
- const fullPath = path.join(data.path, entry.name);
1012
+ const fullPath = path$1.join(data.path, entry.name);
1012
1013
  let type = "other";
1013
1014
  let size;
1014
1015
  let modified;
@@ -1049,26 +1050,26 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory) {
1049
1050
  if (!validation.valid) {
1050
1051
  return { success: false, error: validation.error };
1051
1052
  }
1052
- async function buildTree(path$1, name, currentDepth) {
1053
+ async function buildTree(path, name, currentDepth) {
1053
1054
  try {
1054
- const stats = await fs$2.stat(path$1);
1055
+ const stats = await fs$2.stat(path);
1055
1056
  const node = {
1056
1057
  name,
1057
- path: path$1,
1058
+ path,
1058
1059
  type: stats.isDirectory() ? "directory" : "file",
1059
1060
  size: stats.size,
1060
1061
  modified: stats.mtime.getTime()
1061
1062
  };
1062
1063
  if (stats.isDirectory() && currentDepth < data.maxDepth) {
1063
- const entries = await fs$2.readdir(path$1, { withFileTypes: true });
1064
+ const entries = await fs$2.readdir(path, { withFileTypes: true });
1064
1065
  const children = [];
1065
1066
  await Promise.all(
1066
1067
  entries.map(async (entry) => {
1067
1068
  if (entry.isSymbolicLink()) {
1068
- logger.debug(`Skipping symlink: ${path.join(path$1, entry.name)}`);
1069
+ logger.debug(`Skipping symlink: ${path$1.join(path, entry.name)}`);
1069
1070
  return;
1070
1071
  }
1071
- const childPath = path.join(path$1, entry.name);
1072
+ const childPath = path$1.join(path, entry.name);
1072
1073
  const childNode = await buildTree(childPath, entry.name, currentDepth + 1);
1073
1074
  if (childNode) {
1074
1075
  children.push(childNode);
@@ -1084,7 +1085,7 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory) {
1084
1085
  }
1085
1086
  return node;
1086
1087
  } catch (error) {
1087
- logger.debug(`Failed to process ${path$1}:`, error instanceof Error ? error.message : String(error));
1088
+ logger.debug(`Failed to process ${path}:`, error instanceof Error ? error.message : String(error));
1088
1089
  return null;
1089
1090
  }
1090
1091
  }
@@ -1360,6 +1361,7 @@ class ApiSessionClient extends node_events.EventEmitter {
1360
1361
  metadataLock = new AsyncLock();
1361
1362
  encryptionKey;
1362
1363
  encryptionVariant;
1364
+ pendingReliableCodexMessages = [];
1363
1365
  constructor(credentials, session) {
1364
1366
  super();
1365
1367
  this.credentials = credentials;
@@ -1395,6 +1397,7 @@ class ApiSessionClient extends node_events.EventEmitter {
1395
1397
  this.socket.on("connect", () => {
1396
1398
  logger.debug("Socket connected successfully");
1397
1399
  this.rpcHandlerManager.onSocketConnect(this.socket);
1400
+ this.flushReliableCodexMessages();
1398
1401
  });
1399
1402
  this.socket.on("rpc-request", async (data, callback) => {
1400
1403
  callback(await this.rpcHandlerManager.handleRequest(data));
@@ -1431,10 +1434,12 @@ class ApiSessionClient extends node_events.EventEmitter {
1431
1434
  if (data.body.metadata && data.body.metadata.version > this.metadataVersion) {
1432
1435
  this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.metadata.value));
1433
1436
  this.metadataVersion = data.body.metadata.version;
1437
+ this.emit("metadata-updated", this.metadata);
1434
1438
  }
1435
1439
  if (data.body.agentState && data.body.agentState.version > this.agentStateVersion) {
1436
1440
  this.agentState = data.body.agentState.value ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.agentState.value)) : null;
1437
1441
  this.agentStateVersion = data.body.agentState.version;
1442
+ this.emit("agent-state-updated", this.agentState);
1438
1443
  }
1439
1444
  } else if (data.body.t === "update-machine") {
1440
1445
  logger.debug(`[SOCKET] WARNING: Session client received unexpected machine update - ignoring`);
@@ -1456,6 +1461,33 @@ class ApiSessionClient extends node_events.EventEmitter {
1456
1461
  callback(this.pendingMessages.shift());
1457
1462
  }
1458
1463
  }
1464
+ getMetadataSnapshot() {
1465
+ return this.metadata;
1466
+ }
1467
+ getAgentStateSnapshot() {
1468
+ return this.agentState;
1469
+ }
1470
+ async waitForMetadataUpdate(signal) {
1471
+ if (signal?.aborted) {
1472
+ throw createAbortError();
1473
+ }
1474
+ return await new Promise((resolve, reject) => {
1475
+ const onAbort = () => {
1476
+ cleanup();
1477
+ reject(createAbortError());
1478
+ };
1479
+ const onMetadataUpdate = (metadata) => {
1480
+ cleanup();
1481
+ resolve(metadata);
1482
+ };
1483
+ const cleanup = () => {
1484
+ signal?.removeEventListener("abort", onAbort);
1485
+ this.off("metadata-updated", onMetadataUpdate);
1486
+ };
1487
+ signal?.addEventListener("abort", onAbort, { once: true });
1488
+ this.on("metadata-updated", onMetadataUpdate);
1489
+ });
1490
+ }
1459
1491
  /**
1460
1492
  * Send message to session
1461
1493
  * @param body - Message body (can be MessageContent or raw content for agent messages)
@@ -1514,25 +1546,28 @@ class ApiSessionClient extends node_events.EventEmitter {
1514
1546
  }
1515
1547
  }
1516
1548
  sendCodexMessage(body) {
1517
- let content = {
1549
+ const content = {
1518
1550
  role: "agent",
1519
1551
  content: {
1520
1552
  type: "codex",
1521
1553
  data: body
1522
- // This wraps the entire Claude message
1523
1554
  },
1524
1555
  meta: {
1525
1556
  sentFrom: "cli"
1526
1557
  }
1527
1558
  };
1528
1559
  const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
1560
+ const eventType = typeof body?.type === "string" ? body.type : "unknown";
1529
1561
  if (!this.socket.connected) {
1530
- logger.debug("[API] Socket not connected, cannot send message. Message will be lost:", { type: body.type });
1562
+ if (this.shouldBufferReliableCodexMessage(body)) {
1563
+ logger.debug("[API] Socket not connected, buffering reliable Codex message:", { type: eventType });
1564
+ this.pendingReliableCodexMessages.push({ encrypted, type: eventType });
1565
+ } else {
1566
+ logger.debug("[API] Socket not connected, dropping non-critical Codex message:", { type: eventType });
1567
+ }
1568
+ return;
1531
1569
  }
1532
- this.socket.emit("message", {
1533
- sid: this.sessionId,
1534
- message: encrypted
1535
- });
1570
+ this.emitEncryptedSessionMessage(encrypted);
1536
1571
  }
1537
1572
  /**
1538
1573
  * Send a generic agent message to the session using ACP (Agent Communication Protocol) format.
@@ -1632,10 +1667,12 @@ class ApiSessionClient extends node_events.EventEmitter {
1632
1667
  if (answer.result === "success") {
1633
1668
  this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
1634
1669
  this.metadataVersion = answer.version;
1670
+ this.emit("metadata-updated", this.metadata);
1635
1671
  } else if (answer.result === "version-mismatch") {
1636
1672
  if (answer.version > this.metadataVersion) {
1637
1673
  this.metadataVersion = answer.version;
1638
1674
  this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
1675
+ this.emit("metadata-updated", this.metadata);
1639
1676
  }
1640
1677
  throw new Error("Metadata version mismatch");
1641
1678
  } else if (answer.result === "error") ;
@@ -1655,11 +1692,13 @@ class ApiSessionClient extends node_events.EventEmitter {
1655
1692
  if (answer.result === "success") {
1656
1693
  this.agentState = answer.agentState ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.agentState)) : null;
1657
1694
  this.agentStateVersion = answer.version;
1695
+ this.emit("agent-state-updated", this.agentState);
1658
1696
  logger.debug("Agent state updated", this.agentState);
1659
1697
  } else if (answer.result === "version-mismatch") {
1660
1698
  if (answer.version > this.agentStateVersion) {
1661
1699
  this.agentStateVersion = answer.version;
1662
1700
  this.agentState = answer.agentState ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.agentState)) : null;
1701
+ this.emit("agent-state-updated", this.agentState);
1663
1702
  }
1664
1703
  throw new Error("Agent state version mismatch");
1665
1704
  } else if (answer.result === "error") ;
@@ -1686,6 +1725,44 @@ class ApiSessionClient extends node_events.EventEmitter {
1686
1725
  logger.debug("[API] socket.close() called");
1687
1726
  this.socket.close();
1688
1727
  }
1728
+ emitEncryptedSessionMessage(encrypted) {
1729
+ this.socket.emit("message", {
1730
+ sid: this.sessionId,
1731
+ message: encrypted
1732
+ });
1733
+ }
1734
+ flushReliableCodexMessages() {
1735
+ if (!this.socket.connected || this.pendingReliableCodexMessages.length === 0) {
1736
+ return;
1737
+ }
1738
+ const buffered = this.pendingReliableCodexMessages.splice(0, this.pendingReliableCodexMessages.length);
1739
+ logger.debug("[API] Flushing buffered Codex messages after reconnect", {
1740
+ count: buffered.length,
1741
+ types: buffered.map((message) => message.type)
1742
+ });
1743
+ for (const message of buffered) {
1744
+ this.emitEncryptedSessionMessage(message.encrypted);
1745
+ }
1746
+ }
1747
+ shouldBufferReliableCodexMessage(body) {
1748
+ switch (body?.type) {
1749
+ case "message":
1750
+ case "tool-call":
1751
+ case "tool-call-result":
1752
+ case "permission-request":
1753
+ case "task_started":
1754
+ case "task_complete":
1755
+ case "turn_aborted":
1756
+ return true;
1757
+ default:
1758
+ return false;
1759
+ }
1760
+ }
1761
+ }
1762
+ function createAbortError() {
1763
+ const error = new Error("The operation was aborted");
1764
+ error.name = "AbortError";
1765
+ return error;
1689
1766
  }
1690
1767
 
1691
1768
  class ApiMachineClient {
@@ -2462,60 +2539,10 @@ var api = /*#__PURE__*/Object.freeze({
2462
2539
  ApiClient: ApiClient
2463
2540
  });
2464
2541
 
2465
- const UsageSchema = z.z.object({
2466
- input_tokens: z.z.number().int().nonnegative(),
2467
- cache_creation_input_tokens: z.z.number().int().nonnegative().optional(),
2468
- cache_read_input_tokens: z.z.number().int().nonnegative().optional(),
2469
- output_tokens: z.z.number().int().nonnegative(),
2470
- service_tier: z.z.string().optional()
2471
- }).passthrough();
2472
- const RawJSONLinesSchema = z.z.discriminatedUnion("type", [
2473
- // User message - validates uuid and message.content
2474
- z.z.object({
2475
- type: z.z.literal("user"),
2476
- isSidechain: z.z.boolean().optional(),
2477
- isMeta: z.z.boolean().optional(),
2478
- uuid: z.z.string(),
2479
- // Used in getMessageKey()
2480
- message: z.z.object({
2481
- content: z.z.union([z.z.string(), z.z.any()])
2482
- // Used in sessionScanner.ts
2483
- }).passthrough()
2484
- }).passthrough(),
2485
- // Assistant message - only validates uuid and type
2486
- // message object is optional to handle synthetic error messages (isApiErrorMessage: true)
2487
- // which may have different structure than normal assistant messages
2488
- z.z.object({
2489
- uuid: z.z.string(),
2490
- type: z.z.literal("assistant"),
2491
- message: z.z.object({
2492
- usage: UsageSchema.optional(),
2493
- // Used in apiSession.ts
2494
- model: z.z.string().optional()
2495
- // Used for cost calculation
2496
- }).passthrough().optional()
2497
- }).passthrough(),
2498
- // Summary message - validates summary and leafUuid
2499
- z.z.object({
2500
- type: z.z.literal("summary"),
2501
- summary: z.z.string(),
2502
- // Used in apiSession.ts
2503
- leafUuid: z.z.string()
2504
- // Used in getMessageKey()
2505
- }).passthrough(),
2506
- // System message - validates uuid
2507
- z.z.object({
2508
- type: z.z.literal("system"),
2509
- uuid: z.z.string()
2510
- // Used in getMessageKey()
2511
- }).passthrough()
2512
- ]);
2513
-
2514
2542
  exports.ApiClient = ApiClient;
2515
2543
  exports.ApiSessionClient = ApiSessionClient;
2516
2544
  exports.AsyncLock = AsyncLock;
2517
2545
  exports.HAPPY_CLOUD_DAEMON_PORT = HAPPY_CLOUD_DAEMON_PORT;
2518
- exports.RawJSONLinesSchema = RawJSONLinesSchema;
2519
2546
  exports.api = api;
2520
2547
  exports.backoff = backoff;
2521
2548
  exports.buildAuthenticatedHeaders = buildAuthenticatedHeaders;
@@ -0,0 +1,51 @@
1
+ import { c as createDefaultRuntimeShell } from './index-C7Y0R-MI.mjs';
2
+ import 'chalk';
3
+ import './api-BGXYX0yH.mjs';
4
+ import 'axios';
5
+ import 'fs';
6
+ import 'node:fs';
7
+ import 'node:os';
8
+ import 'node:path';
9
+ import 'node:events';
10
+ import 'socket.io-client';
11
+ import 'zod';
12
+ import 'node:crypto';
13
+ import 'tweetnacl';
14
+ import 'child_process';
15
+ import 'util';
16
+ import 'fs/promises';
17
+ import 'crypto';
18
+ import 'path';
19
+ import 'expo-server-sdk';
20
+ import './persistence-BA_unuca.mjs';
21
+ import 'node:fs/promises';
22
+ import 'os';
23
+ import 'tmp';
24
+ import 'qrcode-terminal';
25
+ import 'node:module';
26
+ import 'open';
27
+ import 'react';
28
+ import 'ink';
29
+ import 'url';
30
+ import 'node:child_process';
31
+ import 'ps-list';
32
+ import 'cross-spawn';
33
+ import 'fastify';
34
+ import 'fastify-type-provider-zod';
35
+ import 'node:readline';
36
+ import 'http';
37
+ import '@agentclientprotocol/sdk';
38
+
39
+ function listRuntimeProviders() {
40
+ const shell = createDefaultRuntimeShell();
41
+ const providers = ["claude", "codex", "gemini", "cursor"];
42
+ return providers.map((provider) => ({
43
+ provider,
44
+ supported: shell.supports(provider)
45
+ }));
46
+ }
47
+ function renderRuntimeProviders() {
48
+ return listRuntimeProviders().map(({ provider, supported }) => `${provider}: ${supported ? "registered" : "missing"}`).join("\n");
49
+ }
50
+
51
+ export { listRuntimeProviders, renderRuntimeProviders };