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