happy-imou-cloud 2.0.0 → 2.0.1

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-BRCQXCZY.cjs → BaseReasoningProcessor-01KqA3Kz.cjs} +96 -9
  2. package/dist/{BaseReasoningProcessor-BKLRCKTU.mjs → BaseReasoningProcessor-DQE2l7Xu.mjs} +95 -10
  3. package/dist/{api-BGXYX0yH.mjs → api-B5Ui8Fw0.mjs} +68 -6
  4. package/dist/{api-D7OK-mML.cjs → api-B8v4tczT.cjs} +70 -5
  5. package/dist/{command-CnLtKtP-.mjs → command-BfIuJmeo.mjs} +3 -3
  6. package/dist/{command-G85giEAF.cjs → command-D8yNlaDo.cjs} +3 -3
  7. package/dist/{index-C7Y0R-MI.mjs → index-BByhFIIq.mjs} +682 -220
  8. package/dist/{index-B_wlQBy2.cjs → index-BOqJ9hwi.cjs} +684 -220
  9. package/dist/index.cjs +4 -4
  10. package/dist/index.mjs +4 -4
  11. package/dist/lib.cjs +1 -1
  12. package/dist/lib.d.cts +1 -0
  13. package/dist/lib.d.mts +1 -0
  14. package/dist/lib.mjs +1 -1
  15. package/dist/{persistence-DHgf1CTG.cjs → persistence-C33AMdtv.cjs} +1 -1
  16. package/dist/{persistence-BA_unuca.mjs → persistence-CzpZpiL3.mjs} +1 -1
  17. package/dist/{registerKillSessionHandler-CLREXN11.cjs → registerKillSessionHandler-BkzQulD9.cjs} +6 -4
  18. package/dist/{registerKillSessionHandler-C2-yHm1V.mjs → registerKillSessionHandler-BtSK7IOa.mjs} +6 -4
  19. package/dist/{runClaude-CwAitpX-.cjs → runClaude-CNVufgZb.cjs} +14 -6
  20. package/dist/{runClaude-uNC5Eym4.mjs → runClaude-C_WLfM6c.mjs} +13 -5
  21. package/dist/{runCodex-B-05E-YZ.mjs → runCodex-8eWjTPJr.mjs} +636 -819
  22. package/dist/{runCodex-Cm0VTqw_.cjs → runCodex-Dzy8anlX.cjs} +639 -819
  23. package/dist/{runGemini-CLWjwDYS.cjs → runGemini-CgsVKP7m.cjs} +20 -16
  24. package/dist/{runGemini-_biXvQAH.mjs → runGemini-nbr0mm-S.mjs} +20 -16
  25. package/package.json +14 -14
  26. package/scripts/env-wrapper.cjs +11 -11
  27. package/scripts/setup-dev.cjs +4 -4
@@ -2,8 +2,9 @@
2
2
 
3
3
  var os = require('node:os');
4
4
  var path = require('node:path');
5
- var api = require('./api-D7OK-mML.cjs');
6
- var index = require('./index-B_wlQBy2.cjs');
5
+ var api = require('./api-B8v4tczT.cjs');
6
+ var index = require('./index-BOqJ9hwi.cjs');
7
+ var node_events = require('node:events');
7
8
  var node_crypto = require('node:crypto');
8
9
 
9
10
  function createSessionMetadata(opts) {
@@ -31,7 +32,10 @@ function createSessionMetadata(opts) {
31
32
  }
32
33
 
33
34
  function createOfflineSessionStub(sessionTag) {
34
- return {
35
+ const emitter = new node_events.EventEmitter();
36
+ let metadata = null;
37
+ let agentState = null;
38
+ const stub = {
35
39
  sessionId: `offline-${sessionTag}`,
36
40
  sendCodexMessage: () => {
37
41
  },
@@ -53,20 +57,29 @@ function createOfflineSessionStub(sessionTag) {
53
57
  },
54
58
  close: async () => {
55
59
  },
56
- updateMetadata: () => {
60
+ updateMetadata: (handler) => {
61
+ metadata = handler(metadata || {});
62
+ emitter.emit("metadata-updated", metadata);
57
63
  },
58
- updateAgentState: () => {
64
+ updateAgentState: (handler) => {
65
+ agentState = handler(agentState || {});
66
+ emitter.emit("agent-state-updated", agentState);
59
67
  },
60
- getMetadataSnapshot: () => null,
61
- getAgentStateSnapshot: () => null,
62
- waitForMetadataUpdate: async () => null,
68
+ getMetadataSnapshot: () => metadata,
69
+ getAgentStateSnapshot: () => agentState,
70
+ waitForMetadataUpdate: async () => metadata,
63
71
  onUserMessage: () => {
64
72
  },
65
73
  rpcHandlerManager: {
66
74
  registerHandler: () => {
67
75
  }
68
- }
76
+ },
77
+ on: emitter.on.bind(emitter),
78
+ once: emitter.once.bind(emitter),
79
+ off: emitter.off.bind(emitter),
80
+ emit: emitter.emit.bind(emitter)
69
81
  };
82
+ return stub;
70
83
  }
71
84
 
72
85
  function setupOfflineReconnection(opts) {
@@ -96,6 +109,15 @@ function setupOfflineReconnection(opts) {
96
109
  }
97
110
 
98
111
  const INTERACTION_SUPERSEDED_ERROR = "Interaction superseded by new user message";
112
+ const INTERACTION_TIMED_OUT_ERROR = "Interaction timed out waiting for user response";
113
+ const DEFAULT_INTERACTION_TIMEOUT_MS = 2 * 60 * 1e3;
114
+ function getPendingInteractionTimeoutMs() {
115
+ const raw = Number(process.env.HAPPY_INTERACTION_TIMEOUT_MS);
116
+ if (Number.isFinite(raw) && raw > 0) {
117
+ return raw;
118
+ }
119
+ return DEFAULT_INTERACTION_TIMEOUT_MS;
120
+ }
99
121
  class BasePermissionHandler {
100
122
  pendingRequests = /* @__PURE__ */ new Map();
101
123
  session;
@@ -126,6 +148,7 @@ class BasePermissionHandler {
126
148
  return;
127
149
  }
128
150
  this.pendingRequests.delete(response.id);
151
+ this.clearPendingRequestTimeout(pending);
129
152
  const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
130
153
  pending.resolve(result);
131
154
  this.session.updateAgentState((currentState) => {
@@ -167,6 +190,22 @@ class BasePermissionHandler {
167
190
  }
168
191
  }));
169
192
  }
193
+ registerPendingRequest(toolCallId, toolName, input, logSuffix = "") {
194
+ return new Promise((resolve, reject) => {
195
+ const pending = {
196
+ resolve,
197
+ reject,
198
+ toolName,
199
+ input
200
+ };
201
+ pending.timeoutHandle = setTimeout(() => {
202
+ this.handlePendingRequestTimeout(toolCallId, pending);
203
+ }, getPendingInteractionTimeoutMs());
204
+ this.pendingRequests.set(toolCallId, pending);
205
+ this.addPendingRequestToState(toolCallId, toolName, input);
206
+ api.logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})${logSuffix}`);
207
+ });
208
+ }
170
209
  hasPendingRequests() {
171
210
  return this.pendingRequests.size > 0;
172
211
  }
@@ -178,6 +217,7 @@ class BasePermissionHandler {
178
217
  this.pendingRequests.clear();
179
218
  const completedAt = Date.now();
180
219
  for (const [, pending] of pendingSnapshot) {
220
+ this.clearPendingRequestTimeout(pending);
181
221
  pending.resolve({ decision: "abort" });
182
222
  }
183
223
  this.session.updateAgentState((currentState) => {
@@ -221,6 +261,7 @@ class BasePermissionHandler {
221
261
  this.pendingRequests.clear();
222
262
  for (const [id, pending] of pendingSnapshot) {
223
263
  try {
264
+ this.clearPendingRequestTimeout(pending);
224
265
  pending.reject(new Error("Session reset"));
225
266
  } catch (err) {
226
267
  api.logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
@@ -248,6 +289,50 @@ class BasePermissionHandler {
248
289
  this.isResetting = false;
249
290
  }
250
291
  }
292
+ clearPendingRequestTimeout(pending) {
293
+ if (pending?.timeoutHandle) {
294
+ clearTimeout(pending.timeoutHandle);
295
+ pending.timeoutHandle = void 0;
296
+ }
297
+ }
298
+ handlePendingRequestTimeout(toolCallId, pending) {
299
+ const active = this.pendingRequests.get(toolCallId);
300
+ if (!active || active !== pending) {
301
+ return;
302
+ }
303
+ this.pendingRequests.delete(toolCallId);
304
+ this.clearPendingRequestTimeout(active);
305
+ active.resolve({ decision: "abort" });
306
+ this.session.updateAgentState((currentState) => {
307
+ const request = currentState.requests?.[toolCallId] || {
308
+ tool: active.toolName,
309
+ arguments: active.input,
310
+ createdAt: Date.now(),
311
+ requestKind: "permission"
312
+ };
313
+ const { [toolCallId]: _, ...remainingRequests } = currentState.requests || {};
314
+ return {
315
+ ...currentState,
316
+ requests: remainingRequests,
317
+ completedRequests: {
318
+ ...currentState.completedRequests,
319
+ [toolCallId]: {
320
+ ...request,
321
+ completedAt: Date.now(),
322
+ status: "canceled",
323
+ reason: INTERACTION_TIMED_OUT_ERROR,
324
+ decision: "abort",
325
+ requestKind: request.requestKind || "permission"
326
+ }
327
+ }
328
+ };
329
+ });
330
+ this.session.sendSessionEvent({
331
+ type: "message",
332
+ message: "Pending interaction timed out waiting for a response. Send a new message to continue."
333
+ });
334
+ api.logger.debug(`${this.getLogPrefix()} Permission request timed out for ${active.toolName} (${toolCallId})`);
335
+ }
251
336
  }
252
337
 
253
338
  class BaseReasoningProcessor {
@@ -447,5 +532,7 @@ class BaseReasoningProcessor {
447
532
  exports.BasePermissionHandler = BasePermissionHandler;
448
533
  exports.BaseReasoningProcessor = BaseReasoningProcessor;
449
534
  exports.INTERACTION_SUPERSEDED_ERROR = INTERACTION_SUPERSEDED_ERROR;
535
+ exports.INTERACTION_TIMED_OUT_ERROR = INTERACTION_TIMED_OUT_ERROR;
450
536
  exports.createSessionMetadata = createSessionMetadata;
537
+ exports.getPendingInteractionTimeoutMs = getPendingInteractionTimeoutMs;
451
538
  exports.setupOfflineReconnection = setupOfflineReconnection;
@@ -1,7 +1,8 @@
1
1
  import os from 'node:os';
2
2
  import { resolve } from 'node:path';
3
- import { c as configuration, p as packageJson, s as startOfflineReconnection, l as logger } from './api-BGXYX0yH.mjs';
4
- import { p as projectPath } from './index-C7Y0R-MI.mjs';
3
+ import { c as configuration, p as packageJson, s as startOfflineReconnection, l as logger } from './api-B5Ui8Fw0.mjs';
4
+ import { p as projectPath } from './index-BByhFIIq.mjs';
5
+ import { EventEmitter } from 'node:events';
5
6
  import { randomUUID } from 'node:crypto';
6
7
 
7
8
  function createSessionMetadata(opts) {
@@ -29,7 +30,10 @@ function createSessionMetadata(opts) {
29
30
  }
30
31
 
31
32
  function createOfflineSessionStub(sessionTag) {
32
- return {
33
+ const emitter = new EventEmitter();
34
+ let metadata = null;
35
+ let agentState = null;
36
+ const stub = {
33
37
  sessionId: `offline-${sessionTag}`,
34
38
  sendCodexMessage: () => {
35
39
  },
@@ -51,20 +55,29 @@ function createOfflineSessionStub(sessionTag) {
51
55
  },
52
56
  close: async () => {
53
57
  },
54
- updateMetadata: () => {
58
+ updateMetadata: (handler) => {
59
+ metadata = handler(metadata || {});
60
+ emitter.emit("metadata-updated", metadata);
55
61
  },
56
- updateAgentState: () => {
62
+ updateAgentState: (handler) => {
63
+ agentState = handler(agentState || {});
64
+ emitter.emit("agent-state-updated", agentState);
57
65
  },
58
- getMetadataSnapshot: () => null,
59
- getAgentStateSnapshot: () => null,
60
- waitForMetadataUpdate: async () => null,
66
+ getMetadataSnapshot: () => metadata,
67
+ getAgentStateSnapshot: () => agentState,
68
+ waitForMetadataUpdate: async () => metadata,
61
69
  onUserMessage: () => {
62
70
  },
63
71
  rpcHandlerManager: {
64
72
  registerHandler: () => {
65
73
  }
66
- }
74
+ },
75
+ on: emitter.on.bind(emitter),
76
+ once: emitter.once.bind(emitter),
77
+ off: emitter.off.bind(emitter),
78
+ emit: emitter.emit.bind(emitter)
67
79
  };
80
+ return stub;
68
81
  }
69
82
 
70
83
  function setupOfflineReconnection(opts) {
@@ -94,6 +107,15 @@ function setupOfflineReconnection(opts) {
94
107
  }
95
108
 
96
109
  const INTERACTION_SUPERSEDED_ERROR = "Interaction superseded by new user message";
110
+ const INTERACTION_TIMED_OUT_ERROR = "Interaction timed out waiting for user response";
111
+ const DEFAULT_INTERACTION_TIMEOUT_MS = 2 * 60 * 1e3;
112
+ function getPendingInteractionTimeoutMs() {
113
+ const raw = Number(process.env.HAPPY_INTERACTION_TIMEOUT_MS);
114
+ if (Number.isFinite(raw) && raw > 0) {
115
+ return raw;
116
+ }
117
+ return DEFAULT_INTERACTION_TIMEOUT_MS;
118
+ }
97
119
  class BasePermissionHandler {
98
120
  pendingRequests = /* @__PURE__ */ new Map();
99
121
  session;
@@ -124,6 +146,7 @@ class BasePermissionHandler {
124
146
  return;
125
147
  }
126
148
  this.pendingRequests.delete(response.id);
149
+ this.clearPendingRequestTimeout(pending);
127
150
  const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
128
151
  pending.resolve(result);
129
152
  this.session.updateAgentState((currentState) => {
@@ -165,6 +188,22 @@ class BasePermissionHandler {
165
188
  }
166
189
  }));
167
190
  }
191
+ registerPendingRequest(toolCallId, toolName, input, logSuffix = "") {
192
+ return new Promise((resolve, reject) => {
193
+ const pending = {
194
+ resolve,
195
+ reject,
196
+ toolName,
197
+ input
198
+ };
199
+ pending.timeoutHandle = setTimeout(() => {
200
+ this.handlePendingRequestTimeout(toolCallId, pending);
201
+ }, getPendingInteractionTimeoutMs());
202
+ this.pendingRequests.set(toolCallId, pending);
203
+ this.addPendingRequestToState(toolCallId, toolName, input);
204
+ logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})${logSuffix}`);
205
+ });
206
+ }
168
207
  hasPendingRequests() {
169
208
  return this.pendingRequests.size > 0;
170
209
  }
@@ -176,6 +215,7 @@ class BasePermissionHandler {
176
215
  this.pendingRequests.clear();
177
216
  const completedAt = Date.now();
178
217
  for (const [, pending] of pendingSnapshot) {
218
+ this.clearPendingRequestTimeout(pending);
179
219
  pending.resolve({ decision: "abort" });
180
220
  }
181
221
  this.session.updateAgentState((currentState) => {
@@ -219,6 +259,7 @@ class BasePermissionHandler {
219
259
  this.pendingRequests.clear();
220
260
  for (const [id, pending] of pendingSnapshot) {
221
261
  try {
262
+ this.clearPendingRequestTimeout(pending);
222
263
  pending.reject(new Error("Session reset"));
223
264
  } catch (err) {
224
265
  logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
@@ -246,6 +287,50 @@ class BasePermissionHandler {
246
287
  this.isResetting = false;
247
288
  }
248
289
  }
290
+ clearPendingRequestTimeout(pending) {
291
+ if (pending?.timeoutHandle) {
292
+ clearTimeout(pending.timeoutHandle);
293
+ pending.timeoutHandle = void 0;
294
+ }
295
+ }
296
+ handlePendingRequestTimeout(toolCallId, pending) {
297
+ const active = this.pendingRequests.get(toolCallId);
298
+ if (!active || active !== pending) {
299
+ return;
300
+ }
301
+ this.pendingRequests.delete(toolCallId);
302
+ this.clearPendingRequestTimeout(active);
303
+ active.resolve({ decision: "abort" });
304
+ this.session.updateAgentState((currentState) => {
305
+ const request = currentState.requests?.[toolCallId] || {
306
+ tool: active.toolName,
307
+ arguments: active.input,
308
+ createdAt: Date.now(),
309
+ requestKind: "permission"
310
+ };
311
+ const { [toolCallId]: _, ...remainingRequests } = currentState.requests || {};
312
+ return {
313
+ ...currentState,
314
+ requests: remainingRequests,
315
+ completedRequests: {
316
+ ...currentState.completedRequests,
317
+ [toolCallId]: {
318
+ ...request,
319
+ completedAt: Date.now(),
320
+ status: "canceled",
321
+ reason: INTERACTION_TIMED_OUT_ERROR,
322
+ decision: "abort",
323
+ requestKind: request.requestKind || "permission"
324
+ }
325
+ }
326
+ };
327
+ });
328
+ this.session.sendSessionEvent({
329
+ type: "message",
330
+ message: "Pending interaction timed out waiting for a response. Send a new message to continue."
331
+ });
332
+ logger.debug(`${this.getLogPrefix()} Permission request timed out for ${active.toolName} (${toolCallId})`);
333
+ }
249
334
  }
250
335
 
251
336
  class BaseReasoningProcessor {
@@ -442,4 +527,4 @@ class BaseReasoningProcessor {
442
527
  }
443
528
  }
444
529
 
445
- export { BasePermissionHandler as B, INTERACTION_SUPERSEDED_ERROR as I, BaseReasoningProcessor as a, createSessionMetadata as c, setupOfflineReconnection as s };
530
+ export { BasePermissionHandler as B, INTERACTION_SUPERSEDED_ERROR as I, BaseReasoningProcessor as a, INTERACTION_TIMED_OUT_ERROR as b, createSessionMetadata as c, getPendingInteractionTimeoutMs as g, setupOfflineReconnection as s };
@@ -17,7 +17,7 @@ import { resolve, join as join$1 } from 'path';
17
17
  import { Expo } from 'expo-server-sdk';
18
18
 
19
19
  var name = "happy-imou-cloud";
20
- var version = "2.0.0";
20
+ var version = "2.0.1";
21
21
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
22
22
  var author = "long.zhu";
23
23
  var license = "MIT";
@@ -100,7 +100,7 @@ var scripts = {
100
100
  "unlink:dev": "node scripts/link-dev.cjs unlink"
101
101
  };
102
102
  var dependencies = {
103
- "@agentclientprotocol/sdk": "^0.8.0",
103
+ "@agentclientprotocol/sdk": "^0.14.1",
104
104
  "@modelcontextprotocol/sdk": "^1.25.3",
105
105
  "@stablelib/base64": "^2.0.1",
106
106
  "@stablelib/hex": "^2.0.1",
@@ -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-BA_unuca.mjs');
434
+ const { readDaemonState } = await import('./persistence-CzpZpiL3.mjs');
435
435
  const state = await readDaemonState();
436
436
  if (!state) {
437
437
  return logs;
@@ -2097,6 +2097,42 @@ class PushNotificationClient {
2097
2097
  }
2098
2098
  }
2099
2099
 
2100
+ const AUTHENTICATION_REQUIRED_MESSAGE = 'Happy authentication failed. Run "hicloud auth login --force" to re-authenticate.';
2101
+ const SIGNING_BOOTSTRAP_REQUIRED_MESSAGE = 'Happy request signing initialization failed. Run "hicloud auth login --force" to retry. If it still fails, inspect the server response and local credentials state.';
2102
+ let authenticationWarningShown = false;
2103
+ class AuthenticationRequiredError extends Error {
2104
+ constructor(message = AUTHENTICATION_REQUIRED_MESSAGE) {
2105
+ super(message);
2106
+ this.name = "AuthenticationRequiredError";
2107
+ }
2108
+ }
2109
+ function isAuthenticationRequiredError(error) {
2110
+ return error instanceof AuthenticationRequiredError;
2111
+ }
2112
+ class SigningBootstrapRequiredError extends AuthenticationRequiredError {
2113
+ constructor(message = SIGNING_BOOTSTRAP_REQUIRED_MESSAGE) {
2114
+ super(message);
2115
+ this.name = "SigningBootstrapRequiredError";
2116
+ }
2117
+ }
2118
+ function isSigningBootstrapRequiredError(error) {
2119
+ return error instanceof SigningBootstrapRequiredError;
2120
+ }
2121
+ function printAuthenticationRequiredWarning(error) {
2122
+ if (authenticationWarningShown) {
2123
+ return;
2124
+ }
2125
+ authenticationWarningShown = true;
2126
+ if (isSigningBootstrapRequiredError(error)) {
2127
+ console.log(chalk.yellow("\u26A0\uFE0F Happy request signing initialization failed"));
2128
+ console.log(chalk.gray(' Run "hicloud auth login --force" to retry signing initialization.'));
2129
+ console.log(chalk.gray(" If it still fails, inspect the server response and local credentials state."));
2130
+ return;
2131
+ }
2132
+ console.log(chalk.yellow("\u26A0\uFE0F Happy authentication failed"));
2133
+ console.log(chalk.gray(' Run "hicloud auth login --force" to re-authenticate.'));
2134
+ }
2135
+
2100
2136
  function startOfflineReconnection(config) {
2101
2137
  let reconnected = false;
2102
2138
  let session = null;
@@ -2123,9 +2159,19 @@ function startOfflineReconnection(config) {
2123
2159
  config.onNotify("\u2705 Reconnected! Session syncing in background.");
2124
2160
  logger.debug("[OfflineReconnection] Successfully reconnected");
2125
2161
  } catch (e) {
2162
+ if (isSigningBootstrapRequiredError(e)) {
2163
+ logger.debug("[OfflineReconnection] Signing bootstrap incomplete, stopping retries");
2164
+ config.onNotify("\u274C Request signing initialization failed. Re-run `hicloud auth login --force`; if it still fails, inspect the server response and local credentials state.");
2165
+ return;
2166
+ }
2126
2167
  if (axios.isAxiosError(e) && e.response?.status === 401) {
2127
2168
  logger.debug("[OfflineReconnection] Authentication error, stopping retries");
2128
- config.onNotify("\u274C Authentication failed. Please re-authenticate with `happy-cloud auth`.");
2169
+ config.onNotify("\u274C Authentication failed. Please re-authenticate with `hicloud auth`.");
2170
+ return;
2171
+ }
2172
+ if (isAuthenticationRequiredError(e)) {
2173
+ logger.debug("[OfflineReconnection] Authentication error, stopping retries");
2174
+ config.onNotify("\u274C Authentication failed. Please re-authenticate with `hicloud auth`.");
2129
2175
  return;
2130
2176
  }
2131
2177
  failureCount++;
@@ -2170,7 +2216,7 @@ const ERROR_DESCRIPTIONS = {
2170
2216
  EHOSTUNREACH: "server host unreachable",
2171
2217
  ENETUNREACH: "network unreachable",
2172
2218
  // HTTP errors
2173
- "401": "authentication failed - run `happy-cloud auth`",
2219
+ "401": "authentication failed - run `hicloud auth`",
2174
2220
  "403": "access forbidden",
2175
2221
  "404": "endpoint not found, check server deployment",
2176
2222
  "500": "server internal error",
@@ -2232,6 +2278,12 @@ class ApiClient {
2232
2278
  this.credential = credential;
2233
2279
  this.pushClient = new PushNotificationClient(credential, configuration.serverUrl);
2234
2280
  }
2281
+ createAuthenticationError() {
2282
+ if (!this.credential.signing) {
2283
+ return new SigningBootstrapRequiredError(SIGNING_BOOTSTRAP_REQUIRED_MESSAGE);
2284
+ }
2285
+ return new AuthenticationRequiredError(AUTHENTICATION_REQUIRED_MESSAGE);
2286
+ }
2235
2287
  async request(opts) {
2236
2288
  return axios.request({
2237
2289
  method: opts.method,
@@ -2316,6 +2368,11 @@ class ApiClient {
2316
2368
  });
2317
2369
  return null;
2318
2370
  }
2371
+ if (axios.isAxiosError(error) && error.response?.status === 401) {
2372
+ const authError = this.createAuthenticationError();
2373
+ printAuthenticationRequiredWarning(authError);
2374
+ throw authError;
2375
+ }
2319
2376
  if (axios.isAxiosError(error) && error.response?.status) {
2320
2377
  const status = error.response.status;
2321
2378
  if (status >= 500) {
@@ -2395,6 +2452,11 @@ class ApiClient {
2395
2452
  }
2396
2453
  if (axios.isAxiosError(error) && error.response?.status) {
2397
2454
  const status = error.response.status;
2455
+ if (status === 401) {
2456
+ const authError = this.createAuthenticationError();
2457
+ printAuthenticationRequiredWarning(authError);
2458
+ throw authError;
2459
+ }
2398
2460
  if (status === 403 || status === 409) {
2399
2461
  console.log(chalk.yellow(
2400
2462
  `\u26A0\uFE0F Machine registration rejected by the server with status ${status}`
@@ -2537,4 +2599,4 @@ var api = /*#__PURE__*/Object.freeze({
2537
2599
  ApiClient: ApiClient
2538
2600
  });
2539
2601
 
2540
- export { ApiClient as A, HAPPY_CLOUD_DAEMON_PORT as H, ApiSessionClient as a, connectionState as b, configuration as c, backoff as d, encodeBase64 as e, delay as f, AsyncLock as g, buildAuthenticatedHeaders as h, encodeBase64Url as i, buildClientHeaders as j, decodeBase64 as k, logger as l, getLatestDaemonLog as m, api as n, packageJson as p, startOfflineReconnection as s };
2602
+ export { ApiClient as A, HAPPY_CLOUD_DAEMON_PORT as H, SigningBootstrapRequiredError as S, ApiSessionClient as a, connectionState as b, configuration as c, backoff as d, encodeBase64 as e, delay as f, AsyncLock as g, buildAuthenticatedHeaders as h, isAuthenticationRequiredError as i, SIGNING_BOOTSTRAP_REQUIRED_MESSAGE as j, encodeBase64Url as k, logger as l, buildClientHeaders as m, decodeBase64 as n, getLatestDaemonLog as o, packageJson as p, api as q, startOfflineReconnection as s };
@@ -19,7 +19,7 @@ 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 = "2.0.0";
22
+ var version = "2.0.1";
23
23
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
24
24
  var author = "long.zhu";
25
25
  var license = "MIT";
@@ -102,7 +102,7 @@ var scripts = {
102
102
  "unlink:dev": "node scripts/link-dev.cjs unlink"
103
103
  };
104
104
  var dependencies = {
105
- "@agentclientprotocol/sdk": "^0.8.0",
105
+ "@agentclientprotocol/sdk": "^0.14.1",
106
106
  "@modelcontextprotocol/sdk": "^1.25.3",
107
107
  "@stablelib/base64": "^2.0.1",
108
108
  "@stablelib/hex": "^2.0.1",
@@ -433,7 +433,7 @@ async function listDaemonLogFiles(limit = 50) {
433
433
  return { file, path: fullPath, modified: stats.mtime };
434
434
  }).sort((a, b) => b.modified.getTime() - a.modified.getTime());
435
435
  try {
436
- const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-DHgf1CTG.cjs'); });
436
+ const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-C33AMdtv.cjs'); });
437
437
  const state = await readDaemonState();
438
438
  if (!state) {
439
439
  return logs;
@@ -2099,6 +2099,42 @@ class PushNotificationClient {
2099
2099
  }
2100
2100
  }
2101
2101
 
2102
+ const AUTHENTICATION_REQUIRED_MESSAGE = 'Happy authentication failed. Run "hicloud auth login --force" to re-authenticate.';
2103
+ const SIGNING_BOOTSTRAP_REQUIRED_MESSAGE = 'Happy request signing initialization failed. Run "hicloud auth login --force" to retry. If it still fails, inspect the server response and local credentials state.';
2104
+ let authenticationWarningShown = false;
2105
+ class AuthenticationRequiredError extends Error {
2106
+ constructor(message = AUTHENTICATION_REQUIRED_MESSAGE) {
2107
+ super(message);
2108
+ this.name = "AuthenticationRequiredError";
2109
+ }
2110
+ }
2111
+ function isAuthenticationRequiredError(error) {
2112
+ return error instanceof AuthenticationRequiredError;
2113
+ }
2114
+ class SigningBootstrapRequiredError extends AuthenticationRequiredError {
2115
+ constructor(message = SIGNING_BOOTSTRAP_REQUIRED_MESSAGE) {
2116
+ super(message);
2117
+ this.name = "SigningBootstrapRequiredError";
2118
+ }
2119
+ }
2120
+ function isSigningBootstrapRequiredError(error) {
2121
+ return error instanceof SigningBootstrapRequiredError;
2122
+ }
2123
+ function printAuthenticationRequiredWarning(error) {
2124
+ if (authenticationWarningShown) {
2125
+ return;
2126
+ }
2127
+ authenticationWarningShown = true;
2128
+ if (isSigningBootstrapRequiredError(error)) {
2129
+ console.log(chalk.yellow("\u26A0\uFE0F Happy request signing initialization failed"));
2130
+ console.log(chalk.gray(' Run "hicloud auth login --force" to retry signing initialization.'));
2131
+ console.log(chalk.gray(" If it still fails, inspect the server response and local credentials state."));
2132
+ return;
2133
+ }
2134
+ console.log(chalk.yellow("\u26A0\uFE0F Happy authentication failed"));
2135
+ console.log(chalk.gray(' Run "hicloud auth login --force" to re-authenticate.'));
2136
+ }
2137
+
2102
2138
  function startOfflineReconnection(config) {
2103
2139
  let reconnected = false;
2104
2140
  let session = null;
@@ -2125,9 +2161,19 @@ function startOfflineReconnection(config) {
2125
2161
  config.onNotify("\u2705 Reconnected! Session syncing in background.");
2126
2162
  logger.debug("[OfflineReconnection] Successfully reconnected");
2127
2163
  } catch (e) {
2164
+ if (isSigningBootstrapRequiredError(e)) {
2165
+ logger.debug("[OfflineReconnection] Signing bootstrap incomplete, stopping retries");
2166
+ config.onNotify("\u274C Request signing initialization failed. Re-run `hicloud auth login --force`; if it still fails, inspect the server response and local credentials state.");
2167
+ return;
2168
+ }
2128
2169
  if (axios.isAxiosError(e) && e.response?.status === 401) {
2129
2170
  logger.debug("[OfflineReconnection] Authentication error, stopping retries");
2130
- config.onNotify("\u274C Authentication failed. Please re-authenticate with `happy-cloud auth`.");
2171
+ config.onNotify("\u274C Authentication failed. Please re-authenticate with `hicloud auth`.");
2172
+ return;
2173
+ }
2174
+ if (isAuthenticationRequiredError(e)) {
2175
+ logger.debug("[OfflineReconnection] Authentication error, stopping retries");
2176
+ config.onNotify("\u274C Authentication failed. Please re-authenticate with `hicloud auth`.");
2131
2177
  return;
2132
2178
  }
2133
2179
  failureCount++;
@@ -2172,7 +2218,7 @@ const ERROR_DESCRIPTIONS = {
2172
2218
  EHOSTUNREACH: "server host unreachable",
2173
2219
  ENETUNREACH: "network unreachable",
2174
2220
  // HTTP errors
2175
- "401": "authentication failed - run `happy-cloud auth`",
2221
+ "401": "authentication failed - run `hicloud auth`",
2176
2222
  "403": "access forbidden",
2177
2223
  "404": "endpoint not found, check server deployment",
2178
2224
  "500": "server internal error",
@@ -2234,6 +2280,12 @@ class ApiClient {
2234
2280
  this.credential = credential;
2235
2281
  this.pushClient = new PushNotificationClient(credential, configuration.serverUrl);
2236
2282
  }
2283
+ createAuthenticationError() {
2284
+ if (!this.credential.signing) {
2285
+ return new SigningBootstrapRequiredError(SIGNING_BOOTSTRAP_REQUIRED_MESSAGE);
2286
+ }
2287
+ return new AuthenticationRequiredError(AUTHENTICATION_REQUIRED_MESSAGE);
2288
+ }
2237
2289
  async request(opts) {
2238
2290
  return axios.request({
2239
2291
  method: opts.method,
@@ -2318,6 +2370,11 @@ class ApiClient {
2318
2370
  });
2319
2371
  return null;
2320
2372
  }
2373
+ if (axios.isAxiosError(error) && error.response?.status === 401) {
2374
+ const authError = this.createAuthenticationError();
2375
+ printAuthenticationRequiredWarning(authError);
2376
+ throw authError;
2377
+ }
2321
2378
  if (axios.isAxiosError(error) && error.response?.status) {
2322
2379
  const status = error.response.status;
2323
2380
  if (status >= 500) {
@@ -2397,6 +2454,11 @@ class ApiClient {
2397
2454
  }
2398
2455
  if (axios.isAxiosError(error) && error.response?.status) {
2399
2456
  const status = error.response.status;
2457
+ if (status === 401) {
2458
+ const authError = this.createAuthenticationError();
2459
+ printAuthenticationRequiredWarning(authError);
2460
+ throw authError;
2461
+ }
2400
2462
  if (status === 403 || status === 409) {
2401
2463
  console.log(chalk.yellow(
2402
2464
  `\u26A0\uFE0F Machine registration rejected by the server with status ${status}`
@@ -2543,6 +2605,8 @@ exports.ApiClient = ApiClient;
2543
2605
  exports.ApiSessionClient = ApiSessionClient;
2544
2606
  exports.AsyncLock = AsyncLock;
2545
2607
  exports.HAPPY_CLOUD_DAEMON_PORT = HAPPY_CLOUD_DAEMON_PORT;
2608
+ exports.SIGNING_BOOTSTRAP_REQUIRED_MESSAGE = SIGNING_BOOTSTRAP_REQUIRED_MESSAGE;
2609
+ exports.SigningBootstrapRequiredError = SigningBootstrapRequiredError;
2546
2610
  exports.api = api;
2547
2611
  exports.backoff = backoff;
2548
2612
  exports.buildAuthenticatedHeaders = buildAuthenticatedHeaders;
@@ -2554,6 +2618,7 @@ exports.delay = delay;
2554
2618
  exports.encodeBase64 = encodeBase64;
2555
2619
  exports.encodeBase64Url = encodeBase64Url;
2556
2620
  exports.getLatestDaemonLog = getLatestDaemonLog;
2621
+ exports.isAuthenticationRequiredError = isAuthenticationRequiredError;
2557
2622
  exports.logger = logger;
2558
2623
  exports.packageJson = packageJson;
2559
2624
  exports.startOfflineReconnection = startOfflineReconnection;
@@ -1,6 +1,6 @@
1
- import { c as createDefaultRuntimeShell } from './index-C7Y0R-MI.mjs';
1
+ import { c as createDefaultRuntimeShell } from './index-BByhFIIq.mjs';
2
2
  import 'chalk';
3
- import './api-BGXYX0yH.mjs';
3
+ import './api-B5Ui8Fw0.mjs';
4
4
  import 'axios';
5
5
  import 'fs';
6
6
  import 'node:fs';
@@ -17,7 +17,7 @@ import 'fs/promises';
17
17
  import 'crypto';
18
18
  import 'path';
19
19
  import 'expo-server-sdk';
20
- import './persistence-BA_unuca.mjs';
20
+ import './persistence-CzpZpiL3.mjs';
21
21
  import 'node:fs/promises';
22
22
  import 'os';
23
23
  import 'tmp';
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-B_wlQBy2.cjs');
3
+ var index = require('./index-BOqJ9hwi.cjs');
4
4
  require('chalk');
5
- require('./api-D7OK-mML.cjs');
5
+ require('./api-B8v4tczT.cjs');
6
6
  require('axios');
7
7
  require('fs');
8
8
  require('node:fs');
@@ -19,7 +19,7 @@ require('fs/promises');
19
19
  require('crypto');
20
20
  require('path');
21
21
  require('expo-server-sdk');
22
- require('./persistence-DHgf1CTG.cjs');
22
+ require('./persistence-C33AMdtv.cjs');
23
23
  require('node:fs/promises');
24
24
  require('os');
25
25
  require('tmp');