happy-imou-cloud 2.1.7 → 2.1.9

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 (27) hide show
  1. package/dist/{BaseReasoningProcessor-C0A6Jr8V.mjs → BaseReasoningProcessor-CgEO6Vh-.mjs} +4 -3
  2. package/dist/{BaseReasoningProcessor-iSuaFeZH.cjs → BaseReasoningProcessor-DV6TAtd7.cjs} +4 -3
  3. package/dist/{ProviderSelectionHandler-DI9QK1iY.cjs → ProviderSelectionHandler-C6ILAmE3.cjs} +2 -2
  4. package/dist/{ProviderSelectionHandler-WT-tvePy.mjs → ProviderSelectionHandler-dczuX21U.mjs} +2 -2
  5. package/dist/{api-BYKV7vX6.mjs → api-CfHYTLZX.mjs} +141 -35
  6. package/dist/{api-CdGT5hsH.cjs → api-CfmTDha2.cjs} +141 -35
  7. package/dist/{command-C1cKqmsa.mjs → command-B0HfYWYW.mjs} +3 -3
  8. package/dist/{command-uyA8cYmL.cjs → command-Bw2XKjA9.cjs} +3 -3
  9. package/dist/{index-BAhlFq45.mjs → index-BKjWLXkN.mjs} +146 -30
  10. package/dist/{index-D_S_7bqK.cjs → index-C3bSe5_d.cjs} +149 -33
  11. package/dist/index.cjs +3 -3
  12. package/dist/index.mjs +3 -3
  13. package/dist/lib.cjs +1 -1
  14. package/dist/lib.d.cts +8 -4
  15. package/dist/lib.d.mts +8 -4
  16. package/dist/lib.mjs +1 -1
  17. package/dist/{persistence-CMvrZ4SA.cjs → persistence-Db4p7gsX.cjs} +1 -1
  18. package/dist/{persistence-B8Wgn6aN.mjs → persistence-Nun5c360.mjs} +1 -1
  19. package/dist/{registerKillSessionHandler-5DVlZaJx.mjs → registerKillSessionHandler-C1S9ytML.mjs} +3 -3
  20. package/dist/{registerKillSessionHandler-DjxtkGMv.cjs → registerKillSessionHandler-FIQEW2Rx.cjs} +3 -3
  21. package/dist/{runClaude-WB884iOO.mjs → runClaude-ClXU2LZA.mjs} +9 -5
  22. package/dist/{runClaude-DNZFsQY0.cjs → runClaude-Dxye_oZf.cjs} +9 -5
  23. package/dist/{runCodex-MJar-238.mjs → runCodex-CXu7_Wgk.mjs} +96 -21
  24. package/dist/{runCodex-WZ91ZLK7.cjs → runCodex-IaL6Vqwc.cjs} +96 -21
  25. package/dist/{runGemini-B_wCHgPU.cjs → runGemini-BgcZcZsv.cjs} +11 -5
  26. package/dist/{runGemini-BPGpwljp.mjs → runGemini-BlJjRWN1.mjs} +11 -5
  27. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { a as createSessionMetadata, p as publishSessionRegistration } from './index-BAhlFq45.mjs';
2
- import { s as startOfflineReconnection, c as configuration, i as isAuthenticationRequiredError, l as logger } from './api-BYKV7vX6.mjs';
1
+ import { a as createSessionMetadata, p as publishSessionRegistration } from './index-BKjWLXkN.mjs';
2
+ import { s as startOfflineReconnection, c as configuration, i as isAuthenticationRequiredError, l as logger } from './api-CfHYTLZX.mjs';
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { randomUUID } from 'node:crypto';
5
5
 
@@ -103,7 +103,8 @@ async function bootstrapManagedProviderSession(opts) {
103
103
  response = await opts.api.getOrCreateSession({
104
104
  tag: opts.sessionTag,
105
105
  metadata,
106
- state
106
+ state,
107
+ stableDataKeyPath: ["managed-session-tag", opts.sessionTag]
107
108
  });
108
109
  } catch (error) {
109
110
  if (!isAuthenticationRequiredError(error)) {
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-D_S_7bqK.cjs');
4
- var api = require('./api-CdGT5hsH.cjs');
3
+ var index = require('./index-C3bSe5_d.cjs');
4
+ var api = require('./api-CfmTDha2.cjs');
5
5
  var node_events = require('node:events');
6
6
  var node_crypto = require('node:crypto');
7
7
 
@@ -105,7 +105,8 @@ async function bootstrapManagedProviderSession(opts) {
105
105
  response = await opts.api.getOrCreateSession({
106
106
  tag: opts.sessionTag,
107
107
  metadata,
108
- state
108
+ state,
109
+ stableDataKeyPath: ["managed-session-tag", opts.sessionTag]
109
110
  });
110
111
  } catch (error) {
111
112
  if (!api.isAuthenticationRequiredError(error)) {
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var api = require('./api-CdGT5hsH.cjs');
4
- var registerKillSessionHandler = require('./registerKillSessionHandler-DjxtkGMv.cjs');
3
+ var api = require('./api-CfmTDha2.cjs');
4
+ var registerKillSessionHandler = require('./registerKillSessionHandler-FIQEW2Rx.cjs');
5
5
 
6
6
  async function runModeLoop(opts) {
7
7
  let currentMode = opts.startingMode;
@@ -1,5 +1,5 @@
1
- import { l as logger } from './api-BYKV7vX6.mjs';
2
- import { g as getPendingInteractionTimeoutMs, I as INTERACTION_SUPERSEDED_ERROR, a as INTERACTION_TIMED_OUT_ERROR } from './registerKillSessionHandler-5DVlZaJx.mjs';
1
+ import { l as logger } from './api-CfHYTLZX.mjs';
2
+ import { g as getPendingInteractionTimeoutMs, I as INTERACTION_SUPERSEDED_ERROR, a as INTERACTION_TIMED_OUT_ERROR } from './registerKillSessionHandler-C1S9ytML.mjs';
3
3
 
4
4
  async function runModeLoop(opts) {
5
5
  let currentMode = opts.startingMode;
@@ -16,7 +16,7 @@ import { spawn } from 'node:child_process';
16
16
  import { Expo } from 'expo-server-sdk';
17
17
 
18
18
  var name = "happy-imou-cloud";
19
- var version = "2.1.7";
19
+ var version = "2.1.9";
20
20
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
21
21
  var author = "long.zhu";
22
22
  var license = "MIT";
@@ -431,7 +431,7 @@ async function listDaemonLogFiles(limit = 50) {
431
431
  return { file, path: fullPath, modified: stats.mtime };
432
432
  }).sort((a, b) => b.modified.getTime() - a.modified.getTime());
433
433
  try {
434
- const { readDaemonState } = await import('./persistence-B8Wgn6aN.mjs');
434
+ const { readDaemonState } = await import('./persistence-Nun5c360.mjs');
435
435
  const state = await readDaemonState();
436
436
  if (!state) {
437
437
  return logs;
@@ -1732,8 +1732,8 @@ function buildSocketAuth(opts) {
1732
1732
  return auth;
1733
1733
  }
1734
1734
 
1735
- const MAX_PENDING_RELIABLE_CODEX_MESSAGES = 200;
1736
- const MAX_PENDING_RELIABLE_CODEX_MESSAGE_BYTES = 512 * 1024;
1735
+ const MAX_PENDING_RELIABLE_SESSION_MESSAGES = 200;
1736
+ const MAX_PENDING_RELIABLE_SESSION_MESSAGE_BYTES = 512 * 1024;
1737
1737
  const PROTOCOL_V3_INITIAL_SNAPSHOT_LIMIT = 150;
1738
1738
  const PROTOCOL_V3_CHANGES_PAGE_LIMIT = 200;
1739
1739
  const PROTOCOL_V3_CAPABILITIES_WAIT_MS = 250;
@@ -1752,8 +1752,8 @@ class ApiSessionClient extends EventEmitter {
1752
1752
  metadataLock = new AsyncLock();
1753
1753
  encryptionKey;
1754
1754
  encryptionVariant;
1755
- pendingReliableCodexMessages = [];
1756
- pendingReliableCodexMessageBytes = 0;
1755
+ pendingReliableSessionMessages = [];
1756
+ pendingReliableSessionMessageBytes = 0;
1757
1757
  reconnectAfterServerDisconnectTimer = null;
1758
1758
  lastSocketServerError = null;
1759
1759
  protocolV3SessionSync = null;
@@ -1782,7 +1782,14 @@ class ApiSessionClient extends EventEmitter {
1782
1782
  encryptionVariant: this.encryptionVariant,
1783
1783
  logger: (msg, data) => logger.debug(msg, data)
1784
1784
  });
1785
- registerCommonHandlers(this.rpcHandlerManager, this.metadata.path);
1785
+ const workingDirectory = this.metadata?.path ?? process.cwd();
1786
+ if (!this.metadata?.path) {
1787
+ logger.debug("[API] Session metadata missing path during client initialization, falling back to process.cwd()", {
1788
+ sessionId: this.sessionId,
1789
+ workingDirectory
1790
+ });
1791
+ }
1792
+ registerCommonHandlers(this.rpcHandlerManager, workingDirectory);
1786
1793
  this.socket = io(configuration.serverUrl, {
1787
1794
  auth: (cb) => cb(buildSocketAuth({
1788
1795
  credentials: this.credentials,
@@ -1803,7 +1810,7 @@ class ApiSessionClient extends EventEmitter {
1803
1810
  this.clearReconnectAfterServerDisconnectTimer();
1804
1811
  this.lastSocketServerError = null;
1805
1812
  this.rpcHandlerManager.onSocketConnect(this.socket);
1806
- this.flushReliableCodexMessages();
1813
+ this.flushReliableSessionMessages();
1807
1814
  this.protocolV3Descriptor = null;
1808
1815
  this.protocolV3SocketCapabilities = null;
1809
1816
  this.scheduleProtocolV3SessionSync();
@@ -1986,9 +1993,7 @@ class ApiSessionClient extends EventEmitter {
1986
1993
  if (!this.socket.connected) {
1987
1994
  if (this.shouldBufferReliableCodexMessage(body)) {
1988
1995
  logger.debug("[API] Socket not connected, buffering reliable Codex message:", { type: eventType });
1989
- this.pendingReliableCodexMessages.push({ encrypted, type: eventType });
1990
- this.pendingReliableCodexMessageBytes += encrypted.length;
1991
- this.trimPendingReliableCodexMessages();
1996
+ this.bufferReliableSessionMessage({ encrypted, type: `codex:${eventType}` });
1992
1997
  } else {
1993
1998
  logger.debug("[API] Socket not connected, dropping non-critical Codex message:", { type: eventType });
1994
1999
  }
@@ -2017,10 +2022,23 @@ class ApiSessionClient extends EventEmitter {
2017
2022
  };
2018
2023
  logger.debug(`[SOCKET] Sending ACP message from ${provider}:`, { type: body.type, hasMessage: "message" in body });
2019
2024
  const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
2020
- this.socket.emit("message", {
2021
- sid: this.sessionId,
2022
- message: encrypted
2023
- });
2025
+ const eventType = typeof body?.type === "string" ? body.type : "unknown";
2026
+ if (!this.socket.connected) {
2027
+ if (this.shouldBufferReliableAcpMessage(body)) {
2028
+ logger.debug("[API] Socket not connected, buffering reliable ACP message:", {
2029
+ provider,
2030
+ type: eventType
2031
+ });
2032
+ this.bufferReliableSessionMessage({ encrypted, type: `acp:${provider}:${eventType}` });
2033
+ } else {
2034
+ logger.debug("[API] Socket not connected, dropping non-critical ACP message:", {
2035
+ provider,
2036
+ type: eventType
2037
+ });
2038
+ }
2039
+ return;
2040
+ }
2041
+ this.emitEncryptedSessionMessage(encrypted);
2024
2042
  }
2025
2043
  sendSessionEvent(event, id) {
2026
2044
  let content = {
@@ -2032,10 +2050,16 @@ class ApiSessionClient extends EventEmitter {
2032
2050
  }
2033
2051
  };
2034
2052
  const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
2035
- this.socket.emit("message", {
2036
- sid: this.sessionId,
2037
- message: encrypted
2038
- });
2053
+ if (!this.socket.connected) {
2054
+ if (this.shouldBufferReliableSessionEvent(event)) {
2055
+ logger.debug("[API] Socket not connected, buffering session event:", { type: event.type });
2056
+ this.bufferReliableSessionMessage({ encrypted, type: `event:${event.type}` });
2057
+ } else {
2058
+ logger.debug("[API] Socket not connected, dropping session event:", { type: event.type });
2059
+ }
2060
+ return;
2061
+ }
2062
+ this.emitEncryptedSessionMessage(encrypted);
2039
2063
  }
2040
2064
  /**
2041
2065
  * Send a ping message to keep the connection alive
@@ -2089,7 +2113,7 @@ class ApiSessionClient extends EventEmitter {
2089
2113
  * @param handler - Handler function that returns the updated metadata
2090
2114
  */
2091
2115
  updateMetadata(handler) {
2092
- this.metadataLock.inLock(async () => {
2116
+ void this.metadataLock.inLock(async () => {
2093
2117
  await backoff(async () => {
2094
2118
  let updated = handler(this.metadata);
2095
2119
  const sessionIndex = buildSessionRuntimeIndex(updated);
@@ -2112,6 +2136,8 @@ class ApiSessionClient extends EventEmitter {
2112
2136
  throw new Error("Metadata version mismatch");
2113
2137
  } else if (answer.result === "error") ;
2114
2138
  });
2139
+ }).catch((error) => {
2140
+ logger.debug("[API] Metadata update failed unexpectedly", error);
2115
2141
  });
2116
2142
  }
2117
2143
  /**
@@ -2120,7 +2146,7 @@ class ApiSessionClient extends EventEmitter {
2120
2146
  */
2121
2147
  updateAgentState(handler) {
2122
2148
  logger.debugLargeJson("Updating agent state", this.agentState);
2123
- this.agentStateLock.inLock(async () => {
2149
+ void this.agentStateLock.inLock(async () => {
2124
2150
  await backoff(async () => {
2125
2151
  let updated = handler(this.agentState || {});
2126
2152
  const answer = await this.socket.emitWithAck("update-state", { sid: this.sessionId, expectedVersion: this.agentStateVersion, agentState: updated ? encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, updated)) : null });
@@ -2138,6 +2164,8 @@ class ApiSessionClient extends EventEmitter {
2138
2164
  throw new Error("Agent state version mismatch");
2139
2165
  } else if (answer.result === "error") ;
2140
2166
  });
2167
+ }).catch((error) => {
2168
+ logger.debug("[API] Agent state update failed unexpectedly", error);
2141
2169
  });
2142
2170
  }
2143
2171
  /**
@@ -2439,13 +2467,18 @@ class ApiSessionClient extends EventEmitter {
2439
2467
  message: encrypted
2440
2468
  });
2441
2469
  }
2442
- flushReliableCodexMessages() {
2443
- if (!this.socket.connected || this.pendingReliableCodexMessages.length === 0) {
2470
+ bufferReliableSessionMessage(message) {
2471
+ this.pendingReliableSessionMessages.push(message);
2472
+ this.pendingReliableSessionMessageBytes += message.encrypted.length;
2473
+ this.trimPendingReliableSessionMessages();
2474
+ }
2475
+ flushReliableSessionMessages() {
2476
+ if (!this.socket.connected || this.pendingReliableSessionMessages.length === 0) {
2444
2477
  return;
2445
2478
  }
2446
- const buffered = this.pendingReliableCodexMessages.splice(0, this.pendingReliableCodexMessages.length);
2447
- this.pendingReliableCodexMessageBytes = 0;
2448
- logger.debug("[API] Flushing buffered Codex messages after reconnect", {
2479
+ const buffered = this.pendingReliableSessionMessages.splice(0, this.pendingReliableSessionMessages.length);
2480
+ this.pendingReliableSessionMessageBytes = 0;
2481
+ logger.debug("[API] Flushing buffered session messages after reconnect", {
2449
2482
  count: buffered.length,
2450
2483
  types: buffered.map((message) => message.type)
2451
2484
  });
@@ -2469,21 +2502,49 @@ class ApiSessionClient extends EventEmitter {
2469
2502
  return false;
2470
2503
  }
2471
2504
  }
2472
- trimPendingReliableCodexMessages() {
2505
+ shouldBufferReliableAcpMessage(body) {
2506
+ switch (body?.type) {
2507
+ case "message":
2508
+ case "tool-call":
2509
+ case "tool-result":
2510
+ case "file-edit":
2511
+ case "terminal-output":
2512
+ case "task_started":
2513
+ case "task_complete":
2514
+ case "turn_aborted":
2515
+ case "turn-report":
2516
+ case "permission-request":
2517
+ return true;
2518
+ default:
2519
+ return false;
2520
+ }
2521
+ }
2522
+ shouldBufferReliableSessionEvent(event) {
2523
+ switch (event.type) {
2524
+ case "switch":
2525
+ case "message":
2526
+ case "permission-mode-changed":
2527
+ case "ready":
2528
+ return true;
2529
+ default:
2530
+ return false;
2531
+ }
2532
+ }
2533
+ trimPendingReliableSessionMessages() {
2473
2534
  let dropped = 0;
2474
- while (this.pendingReliableCodexMessages.length > MAX_PENDING_RELIABLE_CODEX_MESSAGES || this.pendingReliableCodexMessageBytes > MAX_PENDING_RELIABLE_CODEX_MESSAGE_BYTES) {
2475
- const removed = this.pendingReliableCodexMessages.shift();
2535
+ while (this.pendingReliableSessionMessages.length > MAX_PENDING_RELIABLE_SESSION_MESSAGES || this.pendingReliableSessionMessageBytes > MAX_PENDING_RELIABLE_SESSION_MESSAGE_BYTES) {
2536
+ const removed = this.pendingReliableSessionMessages.shift();
2476
2537
  if (!removed) {
2477
2538
  break;
2478
2539
  }
2479
- this.pendingReliableCodexMessageBytes -= removed.encrypted.length;
2540
+ this.pendingReliableSessionMessageBytes -= removed.encrypted.length;
2480
2541
  dropped += 1;
2481
2542
  }
2482
2543
  if (dropped > 0) {
2483
- logger.debug("[API] Dropped oldest buffered Codex messages to cap reconnect memory usage", {
2544
+ logger.debug("[API] Dropped oldest buffered session messages to cap reconnect memory usage", {
2484
2545
  dropped,
2485
- remaining: this.pendingReliableCodexMessages.length,
2486
- bytes: this.pendingReliableCodexMessageBytes
2546
+ remaining: this.pendingReliableSessionMessages.length,
2547
+ bytes: this.pendingReliableSessionMessageBytes
2487
2548
  });
2488
2549
  }
2489
2550
  }
@@ -3203,6 +3264,39 @@ class OfflineState {
3203
3264
  }
3204
3265
  const connectionState = new OfflineState();
3205
3266
 
3267
+ async function hmac_sha512(key, data) {
3268
+ const hmac = createHmac("sha512", key);
3269
+ hmac.update(data);
3270
+ return new Uint8Array(hmac.digest());
3271
+ }
3272
+
3273
+ async function deriveSecretKeyTreeRoot(seed, usage) {
3274
+ const I = await hmac_sha512(new TextEncoder().encode(usage + " Master Seed"), seed);
3275
+ return {
3276
+ key: I.slice(0, 32),
3277
+ chainCode: I.slice(32)
3278
+ };
3279
+ }
3280
+ async function deriveSecretKeyTreeChild(chainCode, index) {
3281
+ const data = new Uint8Array([0, ...new TextEncoder().encode(index)]);
3282
+ const I = await hmac_sha512(chainCode, data);
3283
+ return {
3284
+ key: I.subarray(0, 32),
3285
+ chainCode: I.subarray(32)
3286
+ };
3287
+ }
3288
+ async function deriveKey(master, usage, path) {
3289
+ let state = await deriveSecretKeyTreeRoot(master, usage);
3290
+ let remaining = [...path];
3291
+ while (remaining.length > 0) {
3292
+ let index = remaining[0];
3293
+ remaining = remaining.slice(1);
3294
+ state = await deriveSecretKeyTreeChild(state.chainCode, index);
3295
+ }
3296
+ return state.key;
3297
+ }
3298
+
3299
+ const SESSION_DATA_KEY_USAGE = "Happy Session Data Key";
3206
3300
  class ApiClient {
3207
3301
  static async create(credential) {
3208
3302
  return new ApiClient(credential);
@@ -3344,7 +3438,15 @@ class ApiClient {
3344
3438
  let encryptionKey;
3345
3439
  let encryptionVariant;
3346
3440
  if (this.credential.encryption.type === "dataKey") {
3347
- encryptionKey = getRandomBytes(32);
3441
+ if (opts.stableDataKeyPath && opts.stableDataKeyPath.length > 0) {
3442
+ encryptionKey = await deriveKey(
3443
+ this.credential.encryption.machineKey,
3444
+ SESSION_DATA_KEY_USAGE,
3445
+ opts.stableDataKeyPath
3446
+ );
3447
+ } else {
3448
+ encryptionKey = getRandomBytes(32);
3449
+ }
3348
3450
  encryptionVariant = "dataKey";
3349
3451
  let encryptedDataKey = libsodiumEncryptForPublicKey(encryptionKey, this.credential.encryption.publicKey);
3350
3452
  dataEncryptionKey = new Uint8Array(encryptedDataKey.length + 1);
@@ -3370,10 +3472,14 @@ class ApiClient {
3370
3472
  });
3371
3473
  logger.debug(`Session created/loaded: ${response.data.session.id} (tag: ${opts.tag})`);
3372
3474
  let raw = response.data.session;
3475
+ const metadata = decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.metadata));
3476
+ if (metadata === null) {
3477
+ throw new Error(`Failed to decrypt session metadata for tag ${opts.tag}`);
3478
+ }
3373
3479
  let session = {
3374
3480
  id: raw.id,
3375
3481
  seq: raw.seq,
3376
- metadata: decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.metadata)),
3482
+ metadata,
3377
3483
  metadataVersion: raw.metadataVersion,
3378
3484
  agentState: raw.agentState ? decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.agentState)) : null,
3379
3485
  agentStateVersion: raw.agentStateVersion,