autohand-cli 0.7.7 → 0.7.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 (175) hide show
  1. package/dist/CommunitySkillsCache-N2RWBCY2.cjs +7 -0
  2. package/dist/{CommunitySkillsCache-Q22FUAR5.js → CommunitySkillsCache-YWDFZBKP.js} +2 -2
  3. package/dist/MemoryManager-J7APSLZ7.js +7 -0
  4. package/dist/MemoryManager-RLLYVIDY.cjs +7 -0
  5. package/dist/PermissionManager-ISI5OAJK.cjs +10 -0
  6. package/dist/{PermissionManager-HATZKTRC.js → PermissionManager-WYP5JPCQ.js} +3 -3
  7. package/dist/SessionManager-7MF76Q3Q.cjs +9 -0
  8. package/dist/{SessionManager-S5R6O3NU.js → SessionManager-SFBDIBGA.js} +2 -2
  9. package/dist/{SkillsRegistry-R5WDM6T3.js → SkillsRegistry-E437FFJV.js} +2 -2
  10. package/dist/SkillsRegistry-UTK2YT4M.cjs +8 -0
  11. package/dist/{SyncApiClient-FAOMIZAP.js → SyncApiClient-AYXYSOJM.js} +1 -1
  12. package/dist/SyncApiClient-ID3KXEMA.cjs +10 -0
  13. package/dist/agents-N2ZB4O2A.cjs +9 -0
  14. package/dist/{agents-ICAC3KD3.js → agents-ZMT7HBRT.js} +2 -2
  15. package/dist/agents-new-3EWS2NR3.cjs +11 -0
  16. package/dist/agents-new-TCGUYK5I.js +11 -0
  17. package/dist/cc-2W6M7J45.cjs +8 -0
  18. package/dist/cc-UTTLESTY.js +8 -0
  19. package/dist/{chunk-XFPITUFJ.cjs → chunk-32R47CAQ.cjs} +50 -8
  20. package/dist/{chunk-2JPUEN44.cjs → chunk-3DGR4GNN.cjs} +57 -84
  21. package/dist/{chunk-WIUGUR5T.js → chunk-3DVEGFBZ.js} +8 -8
  22. package/dist/{chunk-YWKZF2SA.js → chunk-3SDEZTZD.js} +46 -46
  23. package/dist/{chunk-KH7BCZJN.js → chunk-4BZ65NIH.js} +1 -1
  24. package/dist/{chunk-52MLYK5P.js → chunk-4YQ2OJAL.js} +1 -1
  25. package/dist/{chunk-VDZJ3W4M.cjs → chunk-5UC3VAJ2.cjs} +2 -2
  26. package/dist/{chunk-NYQVQYIF.cjs → chunk-6DSJ7XST.cjs} +16 -11
  27. package/dist/chunk-6SM6N7DJ.js +2828 -0
  28. package/dist/{chunk-MDWULS57.js → chunk-6UJMCWRY.js} +56 -33
  29. package/dist/{chunk-Q3WCMY3Z.js → chunk-7GJR65DQ.js} +2 -2
  30. package/dist/{chunk-B5N5UAMO.cjs → chunk-7WKEDH3E.cjs} +5 -5
  31. package/dist/{chunk-B4ZPNXZE.cjs → chunk-A5KU3JZW.cjs} +1 -1
  32. package/dist/{chunk-PMMSDR44.cjs → chunk-AQNY2M6Q.cjs} +3 -1
  33. package/dist/{chunk-AVL4DKQO.js → chunk-BTVNRLSE.js} +1 -1
  34. package/dist/{chunk-PU534KPO.cjs → chunk-CHVXUA3O.cjs} +4 -4
  35. package/dist/{chunk-QXAPHGEW.js → chunk-CMNQAF6C.js} +7 -2
  36. package/dist/{chunk-7TOHYAUF.cjs → chunk-CPO5KEQS.cjs} +2 -2
  37. package/dist/{chunk-PR53E47T.cjs → chunk-DRXFJR7F.cjs} +22 -30
  38. package/dist/{chunk-JBKP2CLA.cjs → chunk-FN5S5OE7.cjs} +47 -47
  39. package/dist/{chunk-SFGJQPGC.cjs → chunk-FPHU2ES6.cjs} +56 -33
  40. package/dist/{chunk-3L76MLO5.cjs → chunk-FSTLJIR5.cjs} +21 -28
  41. package/dist/chunk-HF65HHDU.cjs +83 -0
  42. package/dist/{chunk-A552JHUJ.cjs → chunk-HUA44A35.cjs} +21 -18
  43. package/dist/{chunk-B7EUETGY.cjs → chunk-HWDP4HQO.cjs} +4 -4
  44. package/dist/{chunk-OC5YDNFC.js → chunk-IYZBLUEJ.js} +35 -52
  45. package/dist/chunk-J2RUI7GJ.js +83 -0
  46. package/dist/{chunk-WH3D42BQ.js → chunk-J7VV7JAB.js} +55 -82
  47. package/dist/{chunk-VEDIYPWY.cjs → chunk-JRV4SOJU.cjs} +9 -9
  48. package/dist/{chunk-GWIAMKKF.js → chunk-K6CZ2AGI.js} +6 -3
  49. package/dist/{chunk-SYJLMBLP.cjs → chunk-KJAZ4YAR.cjs} +17 -17
  50. package/dist/{chunk-BAFJQUWR.js → chunk-KS45GREN.js} +12 -19
  51. package/dist/chunk-KXNAGJE6.cjs +589 -0
  52. package/dist/chunk-L5QWMGLV.cjs +2828 -0
  53. package/dist/{chunk-U5WIP4HS.js → chunk-LCBOOA7S.js} +47 -5
  54. package/dist/chunk-LJCSSR5V.cjs +63 -0
  55. package/dist/chunk-LKIKNRUP.js +219 -0
  56. package/dist/{chunk-WQSWU2QA.cjs → chunk-LY5VN3B3.cjs} +9 -6
  57. package/dist/{chunk-YAGD43KA.cjs → chunk-LYMZDJX5.cjs} +36 -37
  58. package/dist/{chunk-SLISYSP4.cjs → chunk-MRDZHNCF.cjs} +4 -4
  59. package/dist/chunk-NCC6ETZS.js +362 -0
  60. package/dist/chunk-NCLCL7JK.js +63 -0
  61. package/dist/chunk-NTFNUTY2.js +589 -0
  62. package/dist/{chunk-GDTZQSJ6.cjs → chunk-O3EX3SAD.cjs} +2 -2
  63. package/dist/chunk-OO7EKEJH.cjs +219 -0
  64. package/dist/{chunk-P2Z6GDEN.js → chunk-OXJCLU3X.js} +1 -1
  65. package/dist/{chunk-23JQSCTO.js → chunk-P6EGMTK4.js} +1 -1
  66. package/dist/{chunk-VPAN5H7Q.js → chunk-PFS5ZOCO.js} +30 -31
  67. package/dist/{chunk-EKY5PKQI.js → chunk-PGH3MHPP.js} +3 -1
  68. package/dist/{chunk-GR7VWN63.js → chunk-PVSYZXS7.js} +18 -26
  69. package/dist/{chunk-NI3BQXKU.js → chunk-QAJM6VG5.js} +2 -2
  70. package/dist/{chunk-OBV3UUIL.js → chunk-R5PZPF55.js} +1 -1
  71. package/dist/{chunk-MJFBVQHB.js → chunk-RDGYHJ52.js} +5 -5
  72. package/dist/{chunk-YDH2BMEN.js → chunk-RX4KPL6H.js} +1 -1
  73. package/dist/{chunk-GFJ6AETU.cjs → chunk-T7HQBZZB.cjs} +6 -6
  74. package/dist/chunk-TSV4LVHK.js +35 -0
  75. package/dist/{chunk-7VW3A7DO.cjs → chunk-TUO5SZRD.cjs} +2 -2
  76. package/dist/{chunk-C3IFF3EH.cjs → chunk-UL5T2XIY.cjs} +36 -53
  77. package/dist/chunk-ULQ6MDSJ.cjs +362 -0
  78. package/dist/{chunk-UL7YPRCU.js → chunk-UP6YRP44.js} +1 -1
  79. package/dist/{chunk-G77ZY4QG.js → chunk-VQDWNDP5.js} +1 -1
  80. package/dist/chunk-VXCMGBXY.cjs +35 -0
  81. package/dist/{chunk-JHFH3N4U.cjs → chunk-WCN5WDOI.cjs} +2 -2
  82. package/dist/{chunk-53BR4MUW.cjs → chunk-WGO4ACS7.cjs} +3 -3
  83. package/dist/{chunk-4M2GX7RH.cjs → chunk-WJICM4SK.cjs} +2 -2
  84. package/dist/{chunk-4RWTUT2Z.js → chunk-WT367RVU.js} +19 -16
  85. package/dist/{chunk-A6QBABQ7.js → chunk-XOSFZHSS.js} +2 -2
  86. package/dist/{chunk-3YEDXG6S.js → chunk-YDJA5ETO.js} +1 -1
  87. package/dist/completion-NCSTSKTL.cjs +11 -0
  88. package/dist/{completion-Y42FKDT3.js → completion-NTZERPAZ.js} +2 -1
  89. package/dist/constants-B2X7KDIH.cjs +20 -0
  90. package/dist/{constants-ZLG6M5SI.js → constants-OFIAR4E5.js} +1 -1
  91. package/dist/export-5AJNVX4O.cjs +9 -0
  92. package/dist/{export-WJ5P6E5Z.js → export-ZQHTLV4W.js} +2 -1
  93. package/dist/feedback-F7BMGSV6.cjs +12 -0
  94. package/dist/feedback-NL7CWTRY.js +12 -0
  95. package/dist/hooks-AX5VPCZ3.cjs +10 -0
  96. package/dist/hooks-V22HVLQT.js +10 -0
  97. package/dist/index.cjs +5306 -3582
  98. package/dist/index.js +3780 -2056
  99. package/dist/language-IEKARNQH.js +13 -0
  100. package/dist/language-ULQCKXAD.cjs +13 -0
  101. package/dist/localProjectPermissions-7FI3XF4K.cjs +17 -0
  102. package/dist/{localProjectPermissions-YFFAKLUZ.js → localProjectPermissions-FD5AK5FB.js} +2 -2
  103. package/dist/login-PD3DFJLM.js +15 -0
  104. package/dist/login-VHGT4YKT.cjs +15 -0
  105. package/dist/logout-2QXNFGDT.js +13 -0
  106. package/dist/logout-A4SMKEFO.cjs +13 -0
  107. package/dist/permissions-S7433NQJ.js +10 -0
  108. package/dist/permissions-YZ6WCDBL.cjs +10 -0
  109. package/dist/plan-B3CW5DXJ.cjs +10 -0
  110. package/dist/plan-JFGNRL2S.js +10 -0
  111. package/dist/resume-54ERVSFM.cjs +10 -0
  112. package/dist/resume-YJ5CVKAP.js +10 -0
  113. package/dist/search-4TEQMUPU.js +11 -0
  114. package/dist/search-QGLS4SV7.cjs +11 -0
  115. package/dist/share-2B2T3AUU.cjs +11 -0
  116. package/dist/share-SZMXZIA3.js +11 -0
  117. package/dist/skills-HVQNCTGK.cjs +12 -0
  118. package/dist/{skills-3YEEODHK.js → skills-PB4HXV4R.js} +1 -1
  119. package/dist/{skills-install-FTGOHOZ4.cjs → skills-install-7SFS24HY.cjs} +10 -9
  120. package/dist/{skills-install-KAXAQSN6.js → skills-install-UBBNXWD5.js} +4 -3
  121. package/dist/skills-new-5FSDAJWE.js +12 -0
  122. package/dist/skills-new-IOTZYE6F.cjs +12 -0
  123. package/dist/{status-7LCXYYY4.js → status-AGPSKXSW.js} +2 -2
  124. package/dist/status-WOINF556.cjs +9 -0
  125. package/dist/{sync-3B7SNBYC.js → sync-64MZDWGG.js} +3 -3
  126. package/dist/sync-F5ECJW25.cjs +39 -0
  127. package/dist/{sync-H4UHHLKU.js → sync-LYKDHRFM.js} +3 -3
  128. package/dist/sync-W5UR7BEP.cjs +14 -0
  129. package/dist/theme-CWG3ZLHB.cjs +13 -0
  130. package/dist/theme-HQKV7YAP.js +13 -0
  131. package/package.json +2 -2
  132. package/dist/CommunitySkillsCache-2BITCEAA.cjs +0 -7
  133. package/dist/MemoryManager-2ATHG7BH.js +0 -7
  134. package/dist/MemoryManager-AENCGCEW.cjs +0 -7
  135. package/dist/PermissionManager-6HZGTK2N.cjs +0 -10
  136. package/dist/SessionManager-AG4WT3DP.cjs +0 -9
  137. package/dist/SkillsRegistry-ZXU6YDRP.cjs +0 -8
  138. package/dist/SyncApiClient-UOA4VLLD.cjs +0 -10
  139. package/dist/agents-YONWPKFS.cjs +0 -9
  140. package/dist/agents-new-NV557UVG.cjs +0 -10
  141. package/dist/agents-new-QHM3CO4B.js +0 -10
  142. package/dist/chunk-3HPUOQJN.cjs +0 -23
  143. package/dist/chunk-5DN5KNXU.js +0 -81
  144. package/dist/chunk-7BYSXAKS.js +0 -23
  145. package/dist/chunk-ARVFUZOB.js +0 -736
  146. package/dist/chunk-GWXXFQ3F.cjs +0 -81
  147. package/dist/chunk-XFQS2VGT.cjs +0 -736
  148. package/dist/completion-WVFWX7XQ.cjs +0 -10
  149. package/dist/constants-G2PLP5HH.cjs +0 -20
  150. package/dist/export-BKBJ7PB2.cjs +0 -8
  151. package/dist/feedback-HZBCTSFG.js +0 -10
  152. package/dist/feedback-JBQ3UPGZ.cjs +0 -10
  153. package/dist/hooks-G4VLYMLX.cjs +0 -9
  154. package/dist/hooks-LN4A6NQL.js +0 -9
  155. package/dist/language-KODBDE5R.js +0 -12
  156. package/dist/language-SJT475NW.cjs +0 -12
  157. package/dist/localProjectPermissions-AYQYGTOE.cjs +0 -17
  158. package/dist/login-TC2KROQI.js +0 -14
  159. package/dist/login-TYMR2ZD3.cjs +0 -14
  160. package/dist/logout-2ECV365P.js +0 -12
  161. package/dist/logout-CO3CPYZJ.cjs +0 -12
  162. package/dist/permissions-5MTH22EF.js +0 -9
  163. package/dist/permissions-IP5SITPI.cjs +0 -9
  164. package/dist/resume-EPOEF3WV.cjs +0 -9
  165. package/dist/resume-LOYD5MMP.js +0 -9
  166. package/dist/share-544SIZOY.js +0 -10
  167. package/dist/share-OETK2GUF.cjs +0 -10
  168. package/dist/skills-CRM55MKM.cjs +0 -12
  169. package/dist/skills-new-JF4FKNUT.cjs +0 -11
  170. package/dist/skills-new-JYX2GBKM.js +0 -11
  171. package/dist/status-E7MZEQ26.cjs +0 -9
  172. package/dist/sync-4RARBQIH.cjs +0 -39
  173. package/dist/sync-YZ6YZ42H.cjs +0 -14
  174. package/dist/theme-3XV5BWUB.js +0 -12
  175. package/dist/theme-Z2WS5XWZ.cjs +0 -12
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  getSyncApiClient
3
- } from "./chunk-MDWULS57.js";
3
+ } from "./chunk-6UJMCWRY.js";
4
4
  import {
5
5
  AUTOHAND_HOME
6
- } from "./chunk-EKY5PKQI.js";
6
+ } from "./chunk-PGH3MHPP.js";
7
7
 
8
8
  // src/sync/types.ts
9
9
  var DEFAULT_SYNC_CONFIG = {
@@ -165,12 +165,14 @@ var SyncService = class {
165
165
  this.timer = null;
166
166
  this.syncing = false;
167
167
  this.started = false;
168
+ this.authFailed = false;
168
169
  this.authToken = options.authToken;
169
170
  this.userId = options.userId;
170
171
  this.config = options.config;
171
172
  this.client = options.apiClient || getSyncApiClient();
172
173
  this.onEvent = options.onEvent || (() => {
173
174
  });
175
+ this.onAuthFailure = options.onAuthFailure;
174
176
  this.basePath = AUTOHAND_HOME;
175
177
  }
176
178
  /**
@@ -179,9 +181,13 @@ var SyncService = class {
179
181
  start() {
180
182
  if (this.started) return;
181
183
  this.started = true;
182
- this.sync().catch(() => {
184
+ this.sync().then((result) => {
185
+ if (!result.success && this.isAuthError(result.error)) {
186
+ }
187
+ }).catch(() => {
183
188
  });
184
189
  this.timer = setInterval(() => {
190
+ if (this.authFailed) return;
185
191
  this.sync().catch(() => {
186
192
  });
187
193
  }, this.config.interval);
@@ -279,7 +285,11 @@ var SyncService = class {
279
285
  this.onEvent({ type: "conflict_resolved", path: file.path, strategy: "cloud_wins" });
280
286
  }
281
287
  } catch (error) {
282
- console.error(`Failed to download ${file.path}:`, error);
288
+ const errorMsg = error.message;
289
+ if (this.isAuthError(errorMsg)) {
290
+ throw error;
291
+ }
292
+ this.onEvent({ type: "download_error", path: file.path, error: errorMsg });
283
293
  }
284
294
  }
285
295
  for (const filePath of actions.localDeletes) {
@@ -311,7 +321,11 @@ var SyncService = class {
311
321
  uploaded++;
312
322
  this.onEvent({ type: "file_uploaded", path: file.path, size: content.length });
313
323
  } catch (error) {
314
- console.error(`Failed to upload ${file.path}:`, error);
324
+ const errorMsg = error.message;
325
+ if (this.isAuthError(errorMsg)) {
326
+ throw error;
327
+ }
328
+ this.onEvent({ type: "upload_error", path: file.path, error: errorMsg });
315
329
  }
316
330
  }
317
331
  await this.client.completeUpload(this.authToken, localManifest);
@@ -333,6 +347,17 @@ var SyncService = class {
333
347
  return result;
334
348
  } catch (error) {
335
349
  const errorMessage = error.message;
350
+ if (this.isAuthError(errorMessage)) {
351
+ this.handleAuthFailure(errorMessage);
352
+ return {
353
+ success: false,
354
+ uploaded: 0,
355
+ downloaded: 0,
356
+ conflicts: 0,
357
+ error: "Authentication expired. Please run /login again.",
358
+ duration: Date.now() - startTime
359
+ };
360
+ }
336
361
  this.onEvent({ type: "sync_failed", error: errorMessage });
337
362
  return {
338
363
  success: false,
@@ -348,6 +373,23 @@ var SyncService = class {
348
373
  });
349
374
  }
350
375
  }
376
+ /**
377
+ * Check if an error message indicates an authentication failure
378
+ */
379
+ isAuthError(errorMessage) {
380
+ if (!errorMessage) return false;
381
+ return errorMessage.includes("401") || errorMessage.toLowerCase().includes("unauthorized") || errorMessage.toLowerCase().includes("authentication");
382
+ }
383
+ /**
384
+ * Handle authentication failure - stop service and notify
385
+ */
386
+ handleAuthFailure(errorMessage) {
387
+ if (this.authFailed) return;
388
+ this.authFailed = true;
389
+ this.stop();
390
+ this.onEvent({ type: "auth_failure", error: errorMessage });
391
+ this.onAuthFailure?.();
392
+ }
351
393
  /**
352
394
  * Build manifest from local ~/.autohand/ files
353
395
  */
@@ -0,0 +1,63 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+ var _chunkL5QWMGLVcjs = require('./chunk-L5QWMGLV.cjs');
7
+
8
+ // src/utils/prompt.ts
9
+ async function safePrompt(questions) {
10
+ const questionArray = Array.isArray(questions) ? questions : [questions];
11
+ const results = {};
12
+ for (const question of questionArray) {
13
+ let value;
14
+ if (question.type === "select") {
15
+ const selectConfig = question;
16
+ const options = selectConfig.choices.map((choice) => ({
17
+ label: choice.message,
18
+ value: choice.name
19
+ }));
20
+ const result = await _chunkL5QWMGLVcjs.showModal.call(void 0, {
21
+ title: selectConfig.message,
22
+ options,
23
+ initialIndex: selectConfig.initial
24
+ });
25
+ value = _optionalChain([result, 'optionalAccess', _ => _.value]);
26
+ } else if (question.type === "confirm") {
27
+ const confirmConfig = question;
28
+ value = await _chunkL5QWMGLVcjs.showConfirm.call(void 0, {
29
+ title: confirmConfig.message,
30
+ defaultValue: confirmConfig.initial
31
+ });
32
+ } else if (question.type === "password") {
33
+ const inputConfig = question;
34
+ value = await _chunkL5QWMGLVcjs.showPassword.call(void 0, {
35
+ title: inputConfig.message,
36
+ validate: inputConfig.validate
37
+ });
38
+ } else if (question.type === "input") {
39
+ const inputConfig = question;
40
+ value = await _chunkL5QWMGLVcjs.showInput.call(void 0, {
41
+ title: inputConfig.message,
42
+ defaultValue: inputConfig.initial,
43
+ validate: inputConfig.validate
44
+ });
45
+ }
46
+ if (value === null || value === void 0) {
47
+ return null;
48
+ }
49
+ results[question.name] = value;
50
+ }
51
+ return results;
52
+ }
53
+
54
+
55
+
56
+ exports.safePrompt = safePrompt;
57
+ /**
58
+ * @license
59
+ * Copyright 2025 Autohand AI LLC
60
+ * SPDX-License-Identifier: Apache-2.0
61
+ *
62
+ * Safe prompt utilities using Ink Modal components
63
+ */
@@ -0,0 +1,219 @@
1
+ import {
2
+ package_default
3
+ } from "./chunk-7GJR65DQ.js";
4
+ import {
5
+ safePrompt
6
+ } from "./chunk-NCLCL7JK.js";
7
+ import {
8
+ AUTOHAND_FILES,
9
+ AUTOHAND_PATHS
10
+ } from "./chunk-PGH3MHPP.js";
11
+
12
+ // src/commands/feedback.ts
13
+ import fs from "fs-extra";
14
+ import os from "os";
15
+ import chalk from "chalk";
16
+ var metadata = {
17
+ command: "/feedback",
18
+ description: "share feedback with environment details",
19
+ implemented: true
20
+ };
21
+ var API_BASE_URL = "https://api.autohand.ai";
22
+ var API_TIMEOUT = 1e4;
23
+ var COOLDOWN_MAX_SUBMISSIONS = 5;
24
+ var COOLDOWN_WINDOW_MS = 60 * 60 * 1e3;
25
+ var COOLDOWN_STATE_PATH = `${AUTOHAND_PATHS.feedback}/cooldown.json`;
26
+ async function checkCooldown() {
27
+ try {
28
+ if (!await fs.pathExists(COOLDOWN_STATE_PATH)) {
29
+ return { allowed: true, remaining: COOLDOWN_MAX_SUBMISSIONS };
30
+ }
31
+ const state = await fs.readJson(COOLDOWN_STATE_PATH);
32
+ const now = Date.now();
33
+ const windowStart = now - COOLDOWN_WINDOW_MS;
34
+ const recentSubmissions = state.submissions.filter((ts) => ts > windowStart);
35
+ if (recentSubmissions.length >= COOLDOWN_MAX_SUBMISSIONS) {
36
+ const oldestRecent = Math.min(...recentSubmissions);
37
+ const waitMs = oldestRecent + COOLDOWN_WINDOW_MS - now;
38
+ const waitMinutes = Math.ceil(waitMs / 6e4);
39
+ return { allowed: false, remaining: 0, waitMinutes };
40
+ }
41
+ return { allowed: true, remaining: COOLDOWN_MAX_SUBMISSIONS - recentSubmissions.length };
42
+ } catch {
43
+ return { allowed: true, remaining: COOLDOWN_MAX_SUBMISSIONS };
44
+ }
45
+ }
46
+ async function recordSubmission() {
47
+ try {
48
+ let state = { submissions: [] };
49
+ if (await fs.pathExists(COOLDOWN_STATE_PATH)) {
50
+ state = await fs.readJson(COOLDOWN_STATE_PATH);
51
+ }
52
+ const now = Date.now();
53
+ const windowStart = now - COOLDOWN_WINDOW_MS;
54
+ state.submissions = state.submissions.filter((ts) => ts > windowStart);
55
+ state.submissions.push(now);
56
+ await fs.ensureDir(AUTOHAND_PATHS.feedback);
57
+ await fs.writeJson(COOLDOWN_STATE_PATH, state, { spaces: 2 });
58
+ } catch {
59
+ }
60
+ }
61
+ async function feedback(_ctx) {
62
+ const cooldown = await checkCooldown();
63
+ if (!cooldown.allowed) {
64
+ console.log(chalk.yellow(`Feedback limit reached (${COOLDOWN_MAX_SUBMISSIONS} per hour).`));
65
+ console.log(chalk.gray(`Please wait ${cooldown.waitMinutes} minute${cooldown.waitMinutes === 1 ? "" : "s"} before submitting again.`));
66
+ return null;
67
+ }
68
+ const ratingAnswer = await safePrompt([
69
+ {
70
+ type: "select",
71
+ name: "rating",
72
+ message: "How would you rate your experience?",
73
+ choices: [
74
+ { name: "5", message: "5 - Excellent" },
75
+ { name: "4", message: "4 - Good" },
76
+ { name: "3", message: "3 - Okay" },
77
+ { name: "2", message: "2 - Poor" },
78
+ { name: "1", message: "1 - Very Poor" },
79
+ { name: "skip", message: "s - Skip rating" }
80
+ ]
81
+ }
82
+ ]);
83
+ if (!ratingAnswer) {
84
+ console.log(chalk.gray("Feedback discarded."));
85
+ return null;
86
+ }
87
+ const textAnswer = await safePrompt([
88
+ {
89
+ type: "input",
90
+ name: "feedback",
91
+ message: "What worked? What broke? (optional)"
92
+ }
93
+ ]);
94
+ if (!textAnswer) {
95
+ console.log(chalk.gray("Feedback discarded."));
96
+ return null;
97
+ }
98
+ const npsScore = ratingAnswer.rating === "skip" ? 0 : parseInt(ratingAnswer.rating, 10);
99
+ const freeformFeedback = textAnswer.feedback?.trim() || void 0;
100
+ const now = (/* @__PURE__ */ new Date()).toISOString();
101
+ const runtimeError = getLastRuntimeError();
102
+ const deviceId = await getDeviceId();
103
+ const payload = {
104
+ npsScore,
105
+ triggerType: "manual",
106
+ timestamp: now,
107
+ deviceId,
108
+ cliVersion: package_default.version,
109
+ platform: process.platform,
110
+ osVersion: os.release(),
111
+ nodeVersion: process.version,
112
+ freeformFeedback,
113
+ env: {
114
+ platform: `${process.platform}-${process.arch}`,
115
+ node: process.version,
116
+ bun: process.versions?.bun,
117
+ cwd: process.cwd(),
118
+ shell: process.env.SHELL
119
+ },
120
+ runtimeError: runtimeError ? formatError(runtimeError) : null
121
+ };
122
+ try {
123
+ const feedbackPath = AUTOHAND_FILES.feedbackLog;
124
+ await fs.ensureFile(feedbackPath);
125
+ await fs.appendFile(feedbackPath, JSON.stringify(payload) + "\n", "utf8");
126
+ } catch {
127
+ }
128
+ try {
129
+ const response = await sendFeedbackToApi(payload);
130
+ if (response.success) {
131
+ console.log(chalk.green("Feedback submitted successfully. Thank you!"));
132
+ } else {
133
+ if (response.error?.includes("Rate limit")) {
134
+ console.log(chalk.yellow("Feedback saved locally (rate limited, will retry later)."));
135
+ } else {
136
+ console.log(chalk.yellow(`Feedback saved locally. ${response.error ? `(${response.error})` : ""}`));
137
+ }
138
+ }
139
+ } catch (error) {
140
+ console.log(chalk.yellow(`Feedback saved locally (${error.message}).`));
141
+ }
142
+ await recordSubmission();
143
+ if (runtimeError) {
144
+ console.log(chalk.gray("Included recent runtime error in feedback."));
145
+ }
146
+ return null;
147
+ }
148
+ async function sendFeedbackToApi(payload) {
149
+ const controller = new AbortController();
150
+ const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT);
151
+ try {
152
+ const response = await fetch(`${API_BASE_URL}/v1/feedback`, {
153
+ method: "POST",
154
+ headers: {
155
+ "Content-Type": "application/json",
156
+ "X-CLI-Version": package_default.version,
157
+ "X-Device-ID": payload.deviceId
158
+ },
159
+ body: JSON.stringify(payload),
160
+ signal: controller.signal
161
+ });
162
+ clearTimeout(timeoutId);
163
+ if (!response.ok) {
164
+ const errorText = await response.text().catch(() => "Unknown error");
165
+ return { success: false, error: `API error: ${response.status} ${errorText}` };
166
+ }
167
+ const data = await response.json();
168
+ return data;
169
+ } catch (error) {
170
+ clearTimeout(timeoutId);
171
+ if (error.name === "AbortError") {
172
+ return { success: false, error: "Request timeout" };
173
+ }
174
+ return { success: false, error: error.message };
175
+ }
176
+ }
177
+ async function getDeviceId() {
178
+ const deviceIdPath = `${AUTOHAND_PATHS.feedback}/.device-id`;
179
+ try {
180
+ if (await fs.pathExists(deviceIdPath)) {
181
+ return (await fs.readFile(deviceIdPath, "utf8")).trim();
182
+ }
183
+ } catch {
184
+ }
185
+ const deviceId = `anon_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
186
+ try {
187
+ await fs.ensureDir(AUTOHAND_PATHS.feedback);
188
+ await fs.writeFile(deviceIdPath, deviceId);
189
+ } catch {
190
+ }
191
+ return deviceId;
192
+ }
193
+ function getLastRuntimeError() {
194
+ const globalAny = globalThis;
195
+ return globalAny.__autohandLastError ?? null;
196
+ }
197
+ function formatError(err) {
198
+ if (!err) return {};
199
+ if (err instanceof Error) {
200
+ return { message: err.message, stack: err.stack };
201
+ }
202
+ if (typeof err === "object" && err !== null) {
203
+ const errObj = err;
204
+ const message = "message" in errObj ? String(errObj.message) : void 0;
205
+ const stack = "stack" in errObj ? String(errObj.stack) : void 0;
206
+ return { message, stack };
207
+ }
208
+ return { message: String(err) };
209
+ }
210
+
211
+ export {
212
+ metadata,
213
+ feedback
214
+ };
215
+ /**
216
+ * @license
217
+ * Copyright 2025 Autohand AI LLC
218
+ * SPDX-License-Identifier: Apache-2.0
219
+ */
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkPMMSDR44cjs = require('./chunk-PMMSDR44.cjs');
3
+ var _chunkAQNY2M6Qcjs = require('./chunk-AQNY2M6Q.cjs');
4
4
 
5
5
  // src/ui/theme/Theme.ts
6
6
  var Theme = class {
@@ -881,14 +881,15 @@ var ThemeContext = _react.createContext.call(void 0, defaultContextValue);
881
881
  var _fsextra = require('fs-extra'); var _fsextra2 = _interopRequireDefault(_fsextra);
882
882
 
883
883
  var _yaml = require('yaml'); var _yaml2 = _interopRequireDefault(_yaml);
884
- var DEFAULT_CONFIG_PATH = _chunkPMMSDR44cjs.AUTOHAND_FILES.configJson;
885
- var YAML_CONFIG_PATH = _chunkPMMSDR44cjs.AUTOHAND_FILES.configYaml;
886
- var YML_CONFIG_PATH = _chunkPMMSDR44cjs.AUTOHAND_FILES.configYml;
884
+ var DEFAULT_CONFIG_PATH = _chunkAQNY2M6Qcjs.AUTOHAND_FILES.configJson;
885
+ var YAML_CONFIG_PATH = _chunkAQNY2M6Qcjs.AUTOHAND_FILES.configYaml;
886
+ var YML_CONFIG_PATH = _chunkAQNY2M6Qcjs.AUTOHAND_FILES.configYml;
887
887
  var DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
888
888
  var DEFAULT_OLLAMA_URL = "http://localhost:11434";
889
889
  var DEFAULT_LLAMACPP_URL = "http://localhost:8080";
890
890
  var DEFAULT_OPENAI_URL = "https://api.openai.com/v1";
891
891
  var DEFAULT_MLX_URL = "http://localhost:8080";
892
+ var DEFAULT_LLMGATEWAY_URL = "https://api.llmgateway.io/v1";
892
893
  async function detectConfigPath(customPath) {
893
894
  if (customPath) {
894
895
  return _path2.default.resolve(customPath);
@@ -1045,13 +1046,14 @@ function getProviderConfig(config, provider) {
1045
1046
  ollama: config.ollama,
1046
1047
  llamacpp: config.llamacpp,
1047
1048
  openai: config.openai,
1048
- mlx: config.mlx
1049
+ mlx: config.mlx,
1050
+ llmgateway: config.llmgateway
1049
1051
  };
1050
1052
  const entry = configByProvider[chosen];
1051
1053
  if (!entry) {
1052
1054
  return null;
1053
1055
  }
1054
- if (chosen === "openrouter") {
1056
+ if (chosen === "openrouter" || chosen === "llmgateway") {
1055
1057
  const { apiKey, model } = entry;
1056
1058
  if (!apiKey || apiKey === "replace-me" || !model) {
1057
1059
  return null;
@@ -1068,6 +1070,7 @@ function getProviderConfig(config, provider) {
1068
1070
  }
1069
1071
  function defaultBaseUrlFor(provider, port) {
1070
1072
  if (provider === "openrouter") return DEFAULT_BASE_URL;
1073
+ if (provider === "llmgateway") return DEFAULT_LLMGATEWAY_URL;
1071
1074
  const p = port ? port.toString() : void 0;
1072
1075
  switch (provider) {
1073
1076
  case "ollama":
@@ -5,62 +5,61 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkWQSWU2QAcjs = require('./chunk-WQSWU2QA.cjs');
8
+ var _chunkLY5VN3B3cjs = require('./chunk-LY5VN3B3.cjs');
9
+
10
+
11
+ var _chunkL5QWMGLVcjs = require('./chunk-L5QWMGLV.cjs');
9
12
 
10
13
  // src/commands/theme.ts
11
14
  var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk);
12
- var _enquirer = require('enquirer'); var _enquirer2 = _interopRequireDefault(_enquirer);
13
15
  async function theme(ctx) {
14
- const { Select } = _enquirer2.default;
15
- const themes = _chunkWQSWU2QAcjs.listAvailableThemes.call(void 0, );
16
- const currentTheme = _chunkWQSWU2QAcjs.isThemeInitialized.call(void 0, ) ? _chunkWQSWU2QAcjs.getTheme.call(void 0, ).name : _optionalChain([ctx, 'access', _ => _.config, 'access', _2 => _2.ui, 'optionalAccess', _3 => _3.theme]) || "dark";
16
+ const themes = _chunkLY5VN3B3cjs.listAvailableThemes.call(void 0, );
17
+ const currentTheme = _chunkLY5VN3B3cjs.isThemeInitialized.call(void 0, ) ? _chunkLY5VN3B3cjs.getTheme.call(void 0, ).name : _optionalChain([ctx, 'access', _ => _.config, 'access', _2 => _2.ui, 'optionalAccess', _3 => _3.theme]) || "dark";
17
18
  console.log(_chalk2.default.cyan("\n\u{1F3A8} Theme Selection\n"));
18
19
  console.log(_chalk2.default.gray(`Current theme: ${_chalk2.default.white(currentTheme)}`));
19
- console.log(_chalk2.default.gray(`Custom themes location: ${_chunkWQSWU2QAcjs.CUSTOM_THEMES_DIR}
20
+ console.log(_chalk2.default.gray(`Custom themes location: ${_chunkLY5VN3B3cjs.CUSTOM_THEMES_DIR}
20
21
  `));
21
- const choices = themes.map((name) => ({
22
- name,
23
- message: name === currentTheme ? `${name} (current)` : name,
24
- hint: name === "dark" ? "Default dark theme" : name === "light" ? "Light theme" : "Custom theme"
22
+ const options = themes.map((name) => ({
23
+ label: name === currentTheme ? `${name} (current)` : name,
24
+ value: name,
25
+ description: name === "dark" ? "Default dark theme" : name === "light" ? "Light theme" : "Custom theme"
25
26
  }));
26
- try {
27
- const prompt = new Select({
28
- name: "theme",
29
- message: "Select a theme:",
30
- choices,
31
- initial: themes.indexOf(currentTheme)
32
- });
33
- const selected = await prompt.run();
34
- if (selected === currentTheme) {
35
- console.log(_chalk2.default.gray("\nNo change made."));
36
- return null;
37
- }
38
- _chunkWQSWU2QAcjs.initTheme.call(void 0, selected);
39
- ctx.config.ui = { ...ctx.config.ui, theme: selected };
40
- await _chunkWQSWU2QAcjs.saveConfig.call(void 0, ctx.config);
41
- console.log(_chalk2.default.green(`
42
- \u2713 Theme changed to '${selected}'`));
43
- const newTheme = _chunkWQSWU2QAcjs.getTheme.call(void 0, );
44
- console.log("\nTheme preview:");
45
- console.log(` ${newTheme.fg("accent", "\u25CF accent")} ${newTheme.fg("success", "\u25CF success")} ${newTheme.fg("error", "\u25CF error")} ${newTheme.fg("warning", "\u25CF warning")}`);
46
- console.log(` ${newTheme.fg("muted", "\u25CF muted")} ${newTheme.fg("dim", "\u25CF dim")} ${newTheme.fg("text", "\u25CF text")}`);
47
- console.log();
48
- return null;
49
- } catch (e) {
27
+ const result = await _chunkL5QWMGLVcjs.showModal.call(void 0, {
28
+ title: "Select a theme:",
29
+ options,
30
+ initialIndex: themes.indexOf(currentTheme)
31
+ });
32
+ if (!result) {
50
33
  console.log(_chalk2.default.gray("\nTheme selection cancelled."));
51
34
  return null;
52
35
  }
36
+ const selected = result.value;
37
+ if (selected === currentTheme) {
38
+ console.log(_chalk2.default.gray("\nNo change made."));
39
+ return null;
40
+ }
41
+ _chunkLY5VN3B3cjs.initTheme.call(void 0, selected);
42
+ ctx.config.ui = { ...ctx.config.ui, theme: selected };
43
+ await _chunkLY5VN3B3cjs.saveConfig.call(void 0, ctx.config);
44
+ console.log(_chalk2.default.green(`
45
+ \u2713 Theme changed to '${selected}'`));
46
+ const newTheme = _chunkLY5VN3B3cjs.getTheme.call(void 0, );
47
+ console.log("\nTheme preview:");
48
+ console.log(` ${newTheme.fg("accent", "\u25CF accent")} ${newTheme.fg("success", "\u25CF success")} ${newTheme.fg("error", "\u25CF error")} ${newTheme.fg("warning", "\u25CF warning")}`);
49
+ console.log(` ${newTheme.fg("muted", "\u25CF muted")} ${newTheme.fg("dim", "\u25CF dim")} ${newTheme.fg("text", "\u25CF text")}`);
50
+ console.log();
51
+ return null;
53
52
  }
54
53
  async function themeInfo() {
55
- if (!_chunkWQSWU2QAcjs.isThemeInitialized.call(void 0, )) {
54
+ if (!_chunkLY5VN3B3cjs.isThemeInitialized.call(void 0, )) {
56
55
  console.log(_chalk2.default.yellow("Theme not initialized."));
57
56
  return null;
58
57
  }
59
- const currentTheme = _chunkWQSWU2QAcjs.getTheme.call(void 0, );
58
+ const currentTheme = _chunkLY5VN3B3cjs.getTheme.call(void 0, );
60
59
  console.log(_chalk2.default.cyan("\n\u{1F3A8} Current Theme Info\n"));
61
60
  console.log(_chalk2.default.gray(`Name: ${_chalk2.default.white(currentTheme.name)}`));
62
61
  console.log(_chalk2.default.gray(`Color mode: ${_chalk2.default.white(currentTheme.getColorMode())}`));
63
- console.log(_chalk2.default.gray(`Custom themes dir: ${_chunkWQSWU2QAcjs.CUSTOM_THEMES_DIR}`));
62
+ console.log(_chalk2.default.gray(`Custom themes dir: ${_chunkLY5VN3B3cjs.CUSTOM_THEMES_DIR}`));
64
63
  console.log();
65
64
  console.log("Color preview:");
66
65
  console.log(` ${currentTheme.fg("accent", "\u25CF accent")} ${currentTheme.fg("success", "\u25CF success")} ${currentTheme.fg("error", "\u25CF error")} ${currentTheme.fg("warning", "\u25CF warning")}`);
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
2
 
3
- var _chunk3HPUOQJNcjs = require('./chunk-3HPUOQJN.cjs');
3
+ var _chunkLJCSSR5Vcjs = require('./chunk-LJCSSR5V.cjs');
4
4
 
5
5
 
6
- var _chunkPMMSDR44cjs = require('./chunk-PMMSDR44.cjs');
6
+ var _chunkAQNY2M6Qcjs = require('./chunk-AQNY2M6Q.cjs');
7
7
 
8
8
  // src/commands/agents-new.ts
9
9
  var _path = require('path'); var _path2 = _interopRequireDefault(_path);
@@ -16,7 +16,7 @@ var metadata = {
16
16
  prd: "prd/sub_agents_architecture.md"
17
17
  };
18
18
  async function createAgent(ctx) {
19
- const answers = await _chunk3HPUOQJNcjs.safePrompt.call(void 0, [
19
+ const answers = await _chunkLJCSSR5Vcjs.safePrompt.call(void 0, [
20
20
  {
21
21
  type: "input",
22
22
  name: "name",
@@ -83,7 +83,7 @@ function buildPrompt(name, description) {
83
83
  ].filter(Boolean).join("\n");
84
84
  }
85
85
  function getAgentsDir() {
86
- return _chunkPMMSDR44cjs.AUTOHAND_PATHS.agents;
86
+ return _chunkAQNY2M6Qcjs.AUTOHAND_PATHS.agents;
87
87
  }
88
88
  function slugify(input) {
89
89
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";