autohand-cli 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +1 -0
  2. package/dist/chunk-KT55HW6V.js +168 -0
  3. package/dist/{chunk-7WBK33MM.js → chunk-KZ2UXXLH.js} +4 -2
  4. package/dist/{chunk-KERHTHMK.js → chunk-KZ4QOKII.js} +9 -7
  5. package/dist/{chunk-RUQVXU6K.js → chunk-MRQV5HMC.js} +4 -2
  6. package/dist/chunk-NWXYG5PQ.js +93 -0
  7. package/dist/chunk-UBGEAEKS.js +1135 -0
  8. package/dist/{chunk-TVWTD63Y.js → chunk-Z3Q2AFDS.js} +1 -0
  9. package/dist/{help-CNOV6OXY.js → help-PKC6QCNG.js} +1 -1
  10. package/dist/index.cjs +9191 -2964
  11. package/dist/index.js +8009 -2834
  12. package/dist/{login-Y7XXSNOZ.js → login-MBMAXHG6.js} +3 -2
  13. package/dist/{logout-6KCD4WA3.js → logout-VI6YMV7P.js} +3 -2
  14. package/dist/{status-IT5CYW37.js → status-XQSGXTHN.js} +1 -1
  15. package/dist/theme-B5QZLGKP.js +12 -0
  16. package/package.json +9 -7
  17. package/dist/agents-32JB7KMB.js +0 -9
  18. package/dist/agents-3K6PHXQ6.js +0 -9
  19. package/dist/agents-A7AUMVQD.js +0 -8
  20. package/dist/agents-AHFECO5Q.js +0 -9
  21. package/dist/agents-DQFYBMJG.js +0 -8
  22. package/dist/agents-GX6L7BXZ.js +0 -9
  23. package/dist/agents-IWJJ7YJM.js +0 -8
  24. package/dist/agents-J2QLDVOP.js +0 -9
  25. package/dist/agents-OWTSY74S.js +0 -9
  26. package/dist/agents-RB34F4XE.js +0 -9
  27. package/dist/agents-XL27P67O.js +0 -9
  28. package/dist/agents-new-5I3B2W2I.js +0 -9
  29. package/dist/agents-new-CHV2AV34.js +0 -9
  30. package/dist/agents-new-F6F2VMDB.js +0 -9
  31. package/dist/agents-new-FDMUH7NL.js +0 -9
  32. package/dist/agents-new-GBF6JJIA.js +0 -9
  33. package/dist/agents-new-GCZEY4TE.js +0 -8
  34. package/dist/agents-new-OCIB72NU.js +0 -9
  35. package/dist/agents-new-PQGD47BZ.js +0 -9
  36. package/dist/agents-new-V6BNVJAB.js +0 -9
  37. package/dist/agents-new-WQUEZ2XH.js +0 -8
  38. package/dist/chunk-2DEJU7WQ.js +0 -373
  39. package/dist/chunk-2EPIFDFM.js +0 -68
  40. package/dist/chunk-2FUWKZFN.js +0 -68
  41. package/dist/chunk-2HIILNYH.js +0 -197
  42. package/dist/chunk-2QAL3HH4.js +0 -79
  43. package/dist/chunk-3FRM7HJY.js +0 -57
  44. package/dist/chunk-3OD5MR23.js +0 -384
  45. package/dist/chunk-4LDR3Y3A.js +0 -79
  46. package/dist/chunk-4LLTISFP.js +0 -288
  47. package/dist/chunk-4UISIRMD.js +0 -288
  48. package/dist/chunk-4VWPX2X3.js +0 -131
  49. package/dist/chunk-7FMMKTRG.js +0 -64
  50. package/dist/chunk-7MFSCH7E.js +0 -382
  51. package/dist/chunk-7TV5KURP.js +0 -79
  52. package/dist/chunk-7XN6PAKV.js +0 -79
  53. package/dist/chunk-A7HRTONQ.js +0 -382
  54. package/dist/chunk-ALMJANSA.js +0 -197
  55. package/dist/chunk-CD7GNBIE.js +0 -288
  56. package/dist/chunk-CV3LEQRD.js +0 -57
  57. package/dist/chunk-CYY7D5TQ.js +0 -57
  58. package/dist/chunk-DAHMHLM6.js +0 -102
  59. package/dist/chunk-DAMLAWGE.js +0 -68
  60. package/dist/chunk-F4YPGOQJ.js +0 -105
  61. package/dist/chunk-FQDXFNOI.js +0 -57
  62. package/dist/chunk-FQI7EJY2.js +0 -105
  63. package/dist/chunk-GAJCZDZ5.js +0 -286
  64. package/dist/chunk-GEOP77H3.js +0 -79
  65. package/dist/chunk-GRX3IQHC.js +0 -131
  66. package/dist/chunk-GX24PC3L.js +0 -288
  67. package/dist/chunk-H53NQAC2.js +0 -131
  68. package/dist/chunk-HJYISR7Y.js +0 -382
  69. package/dist/chunk-HLSI4HQM.js +0 -105
  70. package/dist/chunk-IAOMCEYU.js +0 -68
  71. package/dist/chunk-J7RENRJG.js +0 -382
  72. package/dist/chunk-JUDX6E53.js +0 -105
  73. package/dist/chunk-JZQKOM7X.js +0 -382
  74. package/dist/chunk-K75NWR5V.js +0 -108
  75. package/dist/chunk-KCMWJB53.js +0 -288
  76. package/dist/chunk-KJ4M6KAK.js +0 -57
  77. package/dist/chunk-L3JXU574.js +0 -77
  78. package/dist/chunk-LR2XPUPT.js +0 -236
  79. package/dist/chunk-MCWNGAZG.js +0 -198
  80. package/dist/chunk-MQTBFYEG.js +0 -288
  81. package/dist/chunk-NCUJWSGP.js +0 -287
  82. package/dist/chunk-NWEUBPSG.js +0 -79
  83. package/dist/chunk-OJ5EBWOQ.js +0 -232
  84. package/dist/chunk-PKQZWNS2.js +0 -131
  85. package/dist/chunk-PQJIQBQ5.js +0 -57
  86. package/dist/chunk-PX5AGAEX.js +0 -105
  87. package/dist/chunk-Q7HX4VZD.js +0 -197
  88. package/dist/chunk-QE5RKNVN.js +0 -30
  89. package/dist/chunk-QLVXFPE3.js +0 -145
  90. package/dist/chunk-QUC577LO.js +0 -79
  91. package/dist/chunk-RAL2W5UX.js +0 -55
  92. package/dist/chunk-RANNBYFJ.js +0 -105
  93. package/dist/chunk-RCSSFUGL.js +0 -131
  94. package/dist/chunk-RZ7TASUI.js +0 -57
  95. package/dist/chunk-SN7D2PJO.js +0 -68
  96. package/dist/chunk-T4WQUJAE.js +0 -79
  97. package/dist/chunk-U2Z5BABG.js +0 -57
  98. package/dist/chunk-UHC4DIK5.js +0 -105
  99. package/dist/chunk-UNS4S6J3.js +0 -197
  100. package/dist/chunk-UW2LYWIM.js +0 -131
  101. package/dist/chunk-VRCQBFSX.js +0 -102
  102. package/dist/chunk-W76N6IZV.js +0 -197
  103. package/dist/chunk-WMC556GK.js +0 -131
  104. package/dist/chunk-WTEZYXD2.js +0 -67
  105. package/dist/chunk-X7EWON4T.js +0 -105
  106. package/dist/chunk-XARAKKJ4.js +0 -197
  107. package/dist/chunk-Y6JDGDEE.js +0 -197
  108. package/dist/chunk-Y7FSNXMR.js +0 -382
  109. package/dist/chunk-YPZMUIB5.js +0 -50
  110. package/dist/chunk-ZMDUVLR4.js +0 -148
  111. package/dist/chunk-ZRFAICDG.js +0 -382
  112. package/dist/export-HEFUNSR4.js +0 -8
  113. package/dist/feedback-3U2WYQK6.js +0 -9
  114. package/dist/feedback-5IIX372K.js +0 -9
  115. package/dist/feedback-6S6DWGIU.js +0 -9
  116. package/dist/feedback-7DEOY2AP.js +0 -9
  117. package/dist/feedback-BBQT42R6.js +0 -9
  118. package/dist/feedback-CGCSAWQT.js +0 -9
  119. package/dist/feedback-NEDFOKMA.js +0 -9
  120. package/dist/feedback-OXGGJVNA.js +0 -9
  121. package/dist/feedback-ZJECE2FS.js +0 -8
  122. package/dist/help-NQUZ7TNJ.js +0 -10
  123. package/dist/login-D53NQ7UY.js +0 -10
  124. package/dist/login-GPXDNB2F.js +0 -10
  125. package/dist/login-HDF4GSTP.js +0 -10
  126. package/dist/login-HXQ3FDA7.js +0 -10
  127. package/dist/login-SDAZTJAK.js +0 -10
  128. package/dist/login-SM6LEDDA.js +0 -10
  129. package/dist/login-TDI7HBRZ.js +0 -10
  130. package/dist/logout-32RNT7G2.js +0 -10
  131. package/dist/logout-43W7N6JU.js +0 -10
  132. package/dist/logout-BMHTSXIY.js +0 -10
  133. package/dist/logout-JNNJJYYL.js +0 -10
  134. package/dist/logout-LW42QASH.js +0 -10
  135. package/dist/logout-QLWM6P26.js +0 -10
  136. package/dist/logout-TL7GLGWU.js +0 -10
  137. package/dist/memory-GVYG653L.js +0 -8
  138. package/dist/new-MCN36AOD.js +0 -8
  139. package/dist/status-DCVSUWZG.js +0 -8
  140. package/dist/status-F6TQOCON.js +0 -8
  141. package/dist/status-MRJOSVE3.js +0 -8
  142. package/dist/status-MWFV2DZG.js +0 -8
  143. package/dist/status-N3PMJRSB.js +0 -8
  144. package/dist/status-NK7YSBXZ.js +0 -8
  145. package/dist/status-QLQ5ZKJ3.js +0 -8
  146. package/dist/status-SQEFMII5.js +0 -8
  147. package/dist/status-U33PEUBO.js +0 -8
  148. package/dist/status-XAJH67SE.js +0 -8
@@ -1,384 +0,0 @@
1
- import {
2
- AUTH_CONFIG,
3
- AUTOHAND_FILES
4
- } from "./chunk-737A24RB.js";
5
-
6
- // src/config.ts
7
- import fs from "fs-extra";
8
- import path from "path";
9
- import YAML from "yaml";
10
- var DEFAULT_CONFIG_PATH = AUTOHAND_FILES.configJson;
11
- var YAML_CONFIG_PATH = AUTOHAND_FILES.configYaml;
12
- var YML_CONFIG_PATH = AUTOHAND_FILES.configYml;
13
- var DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
14
- var DEFAULT_OLLAMA_URL = "http://localhost:11434";
15
- var DEFAULT_LLAMACPP_URL = "http://localhost:8080";
16
- var DEFAULT_OPENAI_URL = "https://api.openai.com/v1";
17
- async function detectConfigPath(customPath) {
18
- if (customPath) {
19
- return path.resolve(customPath);
20
- }
21
- const envPath = process.env.AUTOHAND_CONFIG;
22
- if (envPath) {
23
- return path.resolve(envPath);
24
- }
25
- if (await fs.pathExists(YAML_CONFIG_PATH)) {
26
- return YAML_CONFIG_PATH;
27
- }
28
- if (await fs.pathExists(YML_CONFIG_PATH)) {
29
- return YML_CONFIG_PATH;
30
- }
31
- return DEFAULT_CONFIG_PATH;
32
- }
33
- function isYamlFile(filePath) {
34
- const ext = path.extname(filePath).toLowerCase();
35
- return ext === ".yaml" || ext === ".yml";
36
- }
37
- async function parseConfigFile(configPath) {
38
- const content = await fs.readFile(configPath, "utf8");
39
- if (isYamlFile(configPath)) {
40
- return YAML.parse(content);
41
- }
42
- return JSON.parse(content);
43
- }
44
- async function loadConfig(customPath) {
45
- const configPath = await detectConfigPath(customPath);
46
- await fs.ensureDir(path.dirname(configPath));
47
- let isNewConfig = false;
48
- if (!await fs.pathExists(configPath)) {
49
- const defaultConfig = {
50
- provider: "openrouter",
51
- openrouter: {
52
- apiKey: "",
53
- baseUrl: "https://openrouter.ai/api/v1",
54
- model: "anthropic/claude-sonnet-4-20250514"
55
- },
56
- workspace: {
57
- defaultRoot: process.cwd(),
58
- allowDangerousOps: false
59
- },
60
- ui: {
61
- theme: "dark",
62
- autoConfirm: false
63
- },
64
- telemetry: {
65
- enabled: true
66
- }
67
- };
68
- await fs.writeJson(configPath, defaultConfig, { spaces: 2 });
69
- isNewConfig = true;
70
- }
71
- let parsed;
72
- try {
73
- parsed = await parseConfigFile(configPath);
74
- } catch (error) {
75
- throw new Error(`Failed to parse config at ${configPath}: ${error.message}`);
76
- }
77
- const normalized = normalizeConfig(parsed);
78
- const withEnv = mergeEnvVariables(normalized);
79
- validateConfig(withEnv, configPath);
80
- return { ...withEnv, configPath, isNewConfig };
81
- }
82
- function mergeEnvVariables(config) {
83
- return {
84
- ...config,
85
- api: {
86
- baseUrl: process.env.AUTOHAND_API_URL || config.api?.baseUrl || "https://api.autohand.ai",
87
- companySecret: process.env.AUTOHAND_SECRET || config.api?.companySecret || ""
88
- }
89
- };
90
- }
91
- function normalizeConfig(config) {
92
- if (isModernConfig(config)) {
93
- const provider = config.provider ?? "openrouter";
94
- return { provider, ...config };
95
- }
96
- if (isLegacyConfig(config)) {
97
- return {
98
- provider: "openrouter",
99
- openrouter: {
100
- apiKey: config.api_key ?? "replace-me",
101
- baseUrl: config.base_url ?? DEFAULT_BASE_URL,
102
- model: config.model ?? "anthropic/claude-3.5-sonnet"
103
- },
104
- workspace: {
105
- defaultRoot: process.cwd(),
106
- allowDangerousOps: false
107
- },
108
- ui: {
109
- autoConfirm: config.dry_run ?? false,
110
- theme: "dark"
111
- }
112
- };
113
- }
114
- return config;
115
- }
116
- function isModernConfig(config) {
117
- return typeof config.openrouter === "object" || typeof config.ollama === "object" || typeof config.llamacpp === "object" || typeof config.openai === "object";
118
- }
119
- function isLegacyConfig(config) {
120
- return typeof config.api_key === "string";
121
- }
122
- function validateConfig(config, configPath) {
123
- const provider = config.provider ?? "openrouter";
124
- const providerConfig = getProviderConfig(config, provider);
125
- if (config.workspace) {
126
- if (config.workspace.defaultRoot && typeof config.workspace.defaultRoot !== "string") {
127
- throw new Error(`workspace.defaultRoot must be a string in ${configPath}`);
128
- }
129
- if (config.workspace.allowDangerousOps !== void 0 && typeof config.workspace.allowDangerousOps !== "boolean") {
130
- throw new Error(`workspace.allowDangerousOps must be boolean in ${configPath}`);
131
- }
132
- }
133
- if (config.ui) {
134
- if (config.ui.theme && config.ui.theme !== "dark" && config.ui.theme !== "light") {
135
- throw new Error(`ui.theme must be 'dark' or 'light' in ${configPath}`);
136
- }
137
- if (config.ui.autoConfirm !== void 0 && typeof config.ui.autoConfirm !== "boolean") {
138
- throw new Error(`ui.autoConfirm must be boolean in ${configPath}`);
139
- }
140
- }
141
- if (config.externalAgents) {
142
- if (config.externalAgents.enabled !== void 0 && typeof config.externalAgents.enabled !== "boolean") {
143
- throw new Error(`externalAgents.enabled must be boolean in ${configPath}`);
144
- }
145
- if (config.externalAgents.paths !== void 0) {
146
- if (!Array.isArray(config.externalAgents.paths)) {
147
- throw new Error(`externalAgents.paths must be an array in ${configPath}`);
148
- }
149
- for (const p of config.externalAgents.paths) {
150
- if (typeof p !== "string") {
151
- throw new Error(`externalAgents.paths must contain only strings in ${configPath}`);
152
- }
153
- }
154
- }
155
- }
156
- }
157
- function resolveWorkspaceRoot(config, requestedPath) {
158
- const candidate = requestedPath ?? process.cwd() ?? config.workspace?.defaultRoot;
159
- return path.resolve(candidate);
160
- }
161
- function getProviderConfig(config, provider) {
162
- const chosen = provider ?? config.provider ?? "openrouter";
163
- const configByProvider = {
164
- openrouter: config.openrouter,
165
- ollama: config.ollama,
166
- llamacpp: config.llamacpp,
167
- openai: config.openai
168
- };
169
- const entry = configByProvider[chosen];
170
- if (!entry) {
171
- return null;
172
- }
173
- if (chosen === "openrouter") {
174
- const { apiKey, model } = entry;
175
- if (!apiKey || apiKey === "replace-me" || !model) {
176
- return null;
177
- }
178
- } else {
179
- if (!entry.model) {
180
- return null;
181
- }
182
- }
183
- return {
184
- ...entry,
185
- baseUrl: entry.baseUrl ?? defaultBaseUrlFor(chosen, entry.port)
186
- };
187
- }
188
- function defaultBaseUrlFor(provider, port) {
189
- if (provider === "openrouter") return DEFAULT_BASE_URL;
190
- const p = port ? port.toString() : void 0;
191
- switch (provider) {
192
- case "ollama":
193
- return p ? `http://localhost:${p}` : DEFAULT_OLLAMA_URL;
194
- case "llamacpp":
195
- return p ? `http://localhost:${p}` : DEFAULT_LLAMACPP_URL;
196
- case "openai":
197
- return DEFAULT_OPENAI_URL;
198
- default:
199
- return void 0;
200
- }
201
- }
202
- async function saveConfig(config) {
203
- const { configPath, ...data } = config;
204
- if (isYamlFile(configPath)) {
205
- const yamlContent = YAML.stringify(data, { indent: 2 });
206
- await fs.writeFile(configPath, yamlContent, "utf8");
207
- } else {
208
- await fs.writeJson(configPath, data, { spaces: 2 });
209
- }
210
- }
211
-
212
- // src/auth/AuthClient.ts
213
- var DEFAULT_TIMEOUT = 1e4;
214
- var AuthClient = class {
215
- constructor(config = {}) {
216
- this.baseUrl = config.baseUrl || AUTH_CONFIG.apiBaseUrl;
217
- this.timeout = config.timeout || DEFAULT_TIMEOUT;
218
- }
219
- /**
220
- * Initiate device authorization flow
221
- * Returns device code and user code for display
222
- */
223
- async initiateDeviceAuth() {
224
- const controller = new AbortController();
225
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
226
- try {
227
- const response = await fetch(`${this.baseUrl}/cli/initiate`, {
228
- method: "POST",
229
- headers: {
230
- "Content-Type": "application/json"
231
- },
232
- body: JSON.stringify({ clientId: "autohand-cli" }),
233
- signal: controller.signal
234
- });
235
- clearTimeout(timeoutId);
236
- const data = await response.json();
237
- if (!response.ok) {
238
- return {
239
- success: false,
240
- error: data.error || data.message || `HTTP ${response.status}`
241
- };
242
- }
243
- return {
244
- success: true,
245
- deviceCode: data.deviceCode,
246
- userCode: data.userCode,
247
- verificationUri: data.verificationUri,
248
- verificationUriComplete: data.verificationUriComplete,
249
- expiresIn: data.expiresIn,
250
- interval: data.interval
251
- };
252
- } catch (error) {
253
- clearTimeout(timeoutId);
254
- if (error.name === "AbortError") {
255
- return { success: false, error: "Request timeout" };
256
- }
257
- return { success: false, error: error.message };
258
- }
259
- }
260
- /**
261
- * Poll for device authorization status
262
- */
263
- async pollDeviceAuth(deviceCode) {
264
- const controller = new AbortController();
265
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
266
- try {
267
- const response = await fetch(`${this.baseUrl}/cli/poll`, {
268
- method: "POST",
269
- headers: {
270
- "Content-Type": "application/json"
271
- },
272
- body: JSON.stringify({ deviceCode }),
273
- signal: controller.signal
274
- });
275
- clearTimeout(timeoutId);
276
- const data = await response.json();
277
- if (!response.ok && response.status !== 404) {
278
- return {
279
- success: false,
280
- status: "pending",
281
- error: data.error || data.message || `HTTP ${response.status}`
282
- };
283
- }
284
- return {
285
- success: data.success !== false,
286
- status: data.status || "pending",
287
- token: data.token,
288
- user: data.user,
289
- error: data.error
290
- };
291
- } catch (error) {
292
- clearTimeout(timeoutId);
293
- if (error.name === "AbortError") {
294
- return { success: false, status: "pending", error: "Request timeout" };
295
- }
296
- return { success: false, status: "pending", error: error.message };
297
- }
298
- }
299
- /**
300
- * Validate current session token
301
- */
302
- async validateSession(token) {
303
- const controller = new AbortController();
304
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
305
- try {
306
- const response = await fetch(`${this.baseUrl}/me`, {
307
- method: "GET",
308
- headers: {
309
- "Authorization": `Bearer ${token}`,
310
- "Cookie": `auth_session=${token}`
311
- },
312
- signal: controller.signal
313
- });
314
- clearTimeout(timeoutId);
315
- if (!response.ok) {
316
- return { authenticated: false };
317
- }
318
- const data = await response.json();
319
- return {
320
- authenticated: true,
321
- user: data.user || data
322
- };
323
- } catch {
324
- clearTimeout(timeoutId);
325
- return { authenticated: false };
326
- }
327
- }
328
- /**
329
- * Logout and invalidate session
330
- */
331
- async logout(token) {
332
- const controller = new AbortController();
333
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
334
- try {
335
- const response = await fetch(`${this.baseUrl}/logout`, {
336
- method: "POST",
337
- headers: {
338
- "Authorization": `Bearer ${token}`,
339
- "Cookie": `auth_session=${token}`
340
- },
341
- signal: controller.signal
342
- });
343
- clearTimeout(timeoutId);
344
- return { success: response.ok };
345
- } catch {
346
- clearTimeout(timeoutId);
347
- return { success: true };
348
- }
349
- }
350
- };
351
- var instance = null;
352
- function getAuthClient(config) {
353
- if (!instance) {
354
- instance = new AuthClient(config);
355
- }
356
- return instance;
357
- }
358
-
359
- export {
360
- loadConfig,
361
- resolveWorkspaceRoot,
362
- getProviderConfig,
363
- saveConfig,
364
- getAuthClient
365
- };
366
- /**
367
- * @license
368
- * Copyright 2025 Autohand AI LLC
369
- * SPDX-License-Identifier: Apache-2.0
370
- */
371
- /**
372
- * @license
373
- * Copyright 2025 Autohand AI LLC
374
- * SPDX-License-Identifier: Apache-2.0
375
- *
376
- * Auth API Client for CLI authentication
377
- */
378
- /**
379
- * @license
380
- * Copyright 2025 Autohand AI LLC
381
- * SPDX-License-Identifier: Apache-2.0
382
- *
383
- * Auth module exports
384
- */
@@ -1,79 +0,0 @@
1
- import {
2
- AUTOHAND_FILES
3
- } from "./chunk-SN7D2PJO.js";
4
-
5
- // src/commands/feedback.ts
6
- import fs from "fs-extra";
7
- import chalk from "chalk";
8
- import enquirer from "enquirer";
9
- var metadata = {
10
- command: "/feedback",
11
- description: "share feedback with environment details",
12
- implemented: true
13
- };
14
- async function feedback(_ctx) {
15
- const answer = await enquirer.prompt([
16
- {
17
- type: "input",
18
- name: "feedback",
19
- message: "What worked? What broke?"
20
- }
21
- ]);
22
- if (!answer.feedback?.trim()) {
23
- console.log(chalk.gray("Feedback discarded (empty)."));
24
- return null;
25
- }
26
- const now = (/* @__PURE__ */ new Date()).toISOString();
27
- const runtimeError = getLastRuntimeError();
28
- const payload = {
29
- timestamp: now,
30
- feedback: answer.feedback.trim(),
31
- env: {
32
- platform: `${process.platform}-${process.arch}`,
33
- node: process.version,
34
- bun: process.versions?.bun,
35
- cwd: process.cwd(),
36
- shell: process.env.SHELL
37
- },
38
- runtimeError: runtimeError ? formatError(runtimeError) : null
39
- };
40
- try {
41
- const feedbackPath = AUTOHAND_FILES.feedbackLog;
42
- await fs.ensureFile(feedbackPath);
43
- await fs.appendFile(feedbackPath, JSON.stringify(payload) + "\n", "utf8");
44
- console.log(chalk.green("Feedback recorded."));
45
- console.log(chalk.gray(`Saved to ${feedbackPath}`));
46
- } catch (error) {
47
- console.error(chalk.red(`Failed to save feedback: ${error.message}`));
48
- }
49
- if (runtimeError) {
50
- console.log(chalk.yellow("Detected a recent runtime error; included in feedback payload."));
51
- }
52
- return null;
53
- }
54
- function getLastRuntimeError() {
55
- const globalAny = globalThis;
56
- return globalAny.__autohandLastError ?? null;
57
- }
58
- function formatError(err) {
59
- if (!err) return {};
60
- if (err instanceof Error) {
61
- return { message: err.message, stack: err.stack };
62
- }
63
- if (typeof err === "object") {
64
- const message = "message" in err ? String(err.message) : void 0;
65
- const stack = "stack" in err ? String(err.stack) : void 0;
66
- return { message, stack };
67
- }
68
- return { message: String(err) };
69
- }
70
-
71
- export {
72
- metadata,
73
- feedback
74
- };
75
- /**
76
- * @license
77
- * Copyright 2025 Autohand AI LLC
78
- * SPDX-License-Identifier: Apache-2.0
79
- */