autohand-cli 0.6.1 → 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-PDF2U23T.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-5UF37IH2.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,288 @@
|
|
|
1
|
+
// src/commands/status.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import readline from "readline";
|
|
4
|
+
|
|
5
|
+
// package.json
|
|
6
|
+
var package_default = {
|
|
7
|
+
name: "autohand-cli",
|
|
8
|
+
version: "0.1.1",
|
|
9
|
+
description: "Autohand interactive coding agent CLI powered by LLMs.",
|
|
10
|
+
type: "module",
|
|
11
|
+
bin: {
|
|
12
|
+
autohand: "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
main: "dist/index.js",
|
|
15
|
+
files: [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
scripts: {
|
|
19
|
+
go: 'bun run build && ./install-local.sh && echo "COMPLETED"',
|
|
20
|
+
build: "tsup src/index.ts --format esm,cjs --dts",
|
|
21
|
+
dev: "tsx src/index.ts",
|
|
22
|
+
typecheck: "tsc --noEmit",
|
|
23
|
+
lint: "eslint .",
|
|
24
|
+
test: "vitest run",
|
|
25
|
+
start: "node dist/index.js",
|
|
26
|
+
"compile:macos-arm64": "bun build ./src/index.ts --compile --target=bun-darwin-arm64 --outfile ./binaries/autohand-macos-arm64",
|
|
27
|
+
"compile:macos-x64": "bun build ./src/index.ts --compile --target=bun-darwin-x64 --outfile ./binaries/autohand-macos-x64",
|
|
28
|
+
"compile:linux-x64": "bun build ./src/index.ts --compile --target=bun-linux-x64 --outfile ./binaries/autohand-linux-x64",
|
|
29
|
+
"compile:linux-arm64": "bun build ./src/index.ts --compile --target=bun-linux-arm64 --outfile ./binaries/autohand-linux-arm64",
|
|
30
|
+
"compile:windows-x64": "bun build ./src/index.ts --compile --target=bun-windows-x64 --outfile ./binaries/autohand-windows-x64.exe",
|
|
31
|
+
"compile:all": "bun run compile:macos-arm64 && bun run compile:macos-x64 && bun run compile:linux-x64 && bun run compile:linux-arm64 && bun run compile:windows-x64",
|
|
32
|
+
link: "bun link"
|
|
33
|
+
},
|
|
34
|
+
keywords: [
|
|
35
|
+
"cli",
|
|
36
|
+
"llm",
|
|
37
|
+
"agent",
|
|
38
|
+
"autohand"
|
|
39
|
+
],
|
|
40
|
+
engines: {
|
|
41
|
+
node: ">=18.17.0"
|
|
42
|
+
},
|
|
43
|
+
dependencies: {
|
|
44
|
+
chalk: "^5.6.2",
|
|
45
|
+
commander: "^14.0.2",
|
|
46
|
+
diff: "^8.0.2",
|
|
47
|
+
dotenv: "^17.2.3",
|
|
48
|
+
enquirer: "^2.4.1",
|
|
49
|
+
"fs-extra": "^11.3.2",
|
|
50
|
+
ignore: "^5.3.1",
|
|
51
|
+
ink: "^4.4.1",
|
|
52
|
+
open: "^10.1.0",
|
|
53
|
+
ora: "^9.0.0",
|
|
54
|
+
react: "^18.2.0",
|
|
55
|
+
"terminal-link": "^3.0.0",
|
|
56
|
+
yaml: "^2.8.2",
|
|
57
|
+
zod: "^4.1.12"
|
|
58
|
+
},
|
|
59
|
+
devDependencies: {
|
|
60
|
+
"@types/diff": "^8.0.0",
|
|
61
|
+
"@types/fs-extra": "^11.0.4",
|
|
62
|
+
"@types/node": "^24.10.1",
|
|
63
|
+
"@types/react": "^18.3.3",
|
|
64
|
+
"@types/terminal-link": "^1.2.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
|
66
|
+
"@typescript-eslint/parser": "^8.48.1",
|
|
67
|
+
eslint: "^9.39.1",
|
|
68
|
+
"react-devtools-core": "^7.0.1",
|
|
69
|
+
tsup: "^8.5.1",
|
|
70
|
+
tsx: "^4.20.6",
|
|
71
|
+
typescript: "^5.9.3",
|
|
72
|
+
vitest: "^1.6.0"
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/commands/status.ts
|
|
77
|
+
var metadata = {
|
|
78
|
+
command: "/status",
|
|
79
|
+
description: "Show Autohand status including version, model, API connectivity, and usage",
|
|
80
|
+
implemented: true
|
|
81
|
+
};
|
|
82
|
+
async function status(ctx) {
|
|
83
|
+
const data = await gatherStatusData(ctx);
|
|
84
|
+
await renderStatusUI(data);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
async function gatherStatusData(ctx) {
|
|
88
|
+
const currentSession = ctx.sessionManager.getCurrentSession();
|
|
89
|
+
const allSessions = await ctx.sessionManager.listSessions();
|
|
90
|
+
let apiConnected = false;
|
|
91
|
+
try {
|
|
92
|
+
apiConnected = await ctx.llm.isAvailable();
|
|
93
|
+
} catch {
|
|
94
|
+
apiConnected = false;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
version: package_default.version,
|
|
98
|
+
sessionId: currentSession?.metadata.sessionId ?? null,
|
|
99
|
+
cwd: ctx.workspaceRoot,
|
|
100
|
+
provider: ctx.provider ?? "openrouter",
|
|
101
|
+
model: ctx.model,
|
|
102
|
+
apiConnected,
|
|
103
|
+
sessionsCount: allSessions.length,
|
|
104
|
+
contextPercentLeft: ctx.getContextPercentLeft?.() ?? 100,
|
|
105
|
+
totalTokensUsed: ctx.getTotalTokensUsed?.() ?? 0,
|
|
106
|
+
config: ctx.config
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function renderStatusUI(data) {
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
const tabs = ["Status", "Config", "Usage"];
|
|
112
|
+
let currentTab = 0;
|
|
113
|
+
const input = process.stdin;
|
|
114
|
+
const isTTY = input.isTTY;
|
|
115
|
+
const wasRaw = input.isRaw;
|
|
116
|
+
const wasPaused = typeof input.isPaused === "function" ? input.isPaused() : false;
|
|
117
|
+
if (wasPaused && typeof input.resume === "function") {
|
|
118
|
+
input.resume();
|
|
119
|
+
}
|
|
120
|
+
if (isTTY) {
|
|
121
|
+
readline.emitKeypressEvents(input);
|
|
122
|
+
if (!wasRaw && typeof input.setRawMode === "function") {
|
|
123
|
+
input.setRawMode(true);
|
|
124
|
+
}
|
|
125
|
+
if (typeof input.setEncoding === "function") {
|
|
126
|
+
input.setEncoding("utf8");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const render = () => {
|
|
130
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
131
|
+
renderTabHeader(tabs, currentTab);
|
|
132
|
+
renderTabContent(tabs[currentTab], data);
|
|
133
|
+
console.log(chalk.gray("\nEsc to exit"));
|
|
134
|
+
};
|
|
135
|
+
let buffer = "";
|
|
136
|
+
const handler = (chunk) => {
|
|
137
|
+
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
138
|
+
const processNext = () => {
|
|
139
|
+
if (!buffer.length) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const first = buffer[0];
|
|
143
|
+
if (first === "\x1B") {
|
|
144
|
+
if (buffer.length === 1) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (buffer[1] === "[") {
|
|
148
|
+
if (buffer.length < 3) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const seq = buffer.slice(0, 3);
|
|
152
|
+
buffer = buffer.slice(3);
|
|
153
|
+
handleSequence(seq);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
buffer = buffer.slice(1);
|
|
157
|
+
handleSequence("\x1B");
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
buffer = buffer.slice(1);
|
|
161
|
+
handleSequence(first);
|
|
162
|
+
return true;
|
|
163
|
+
};
|
|
164
|
+
while (processNext()) {
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const handleSequence = (sequence) => {
|
|
168
|
+
switch (sequence) {
|
|
169
|
+
case "\x1B":
|
|
170
|
+
// ESC
|
|
171
|
+
case "":
|
|
172
|
+
cleanup();
|
|
173
|
+
resolve();
|
|
174
|
+
return;
|
|
175
|
+
case " ":
|
|
176
|
+
// Tab
|
|
177
|
+
case "\x1B[C":
|
|
178
|
+
currentTab = (currentTab + 1) % tabs.length;
|
|
179
|
+
render();
|
|
180
|
+
return;
|
|
181
|
+
case "\x1B[Z":
|
|
182
|
+
// Shift+Tab
|
|
183
|
+
case "\x1B[D":
|
|
184
|
+
currentTab = (currentTab - 1 + tabs.length) % tabs.length;
|
|
185
|
+
render();
|
|
186
|
+
return;
|
|
187
|
+
default:
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
const cleanup = () => {
|
|
192
|
+
input.off("data", handler);
|
|
193
|
+
if (isTTY && !wasRaw && typeof input.setRawMode === "function") {
|
|
194
|
+
input.setRawMode(false);
|
|
195
|
+
}
|
|
196
|
+
if (wasPaused && typeof input.pause === "function") {
|
|
197
|
+
input.pause();
|
|
198
|
+
}
|
|
199
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
200
|
+
};
|
|
201
|
+
input.on("data", handler);
|
|
202
|
+
render();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function renderTabHeader(tabs, currentIndex) {
|
|
206
|
+
const header = tabs.map((tab, i) => {
|
|
207
|
+
return i === currentIndex ? chalk.bgWhite.black(` ${tab} `) : chalk.gray(` ${tab} `);
|
|
208
|
+
}).join(" ");
|
|
209
|
+
console.log(`Settings: ${header} ${chalk.gray("(tab to cycle)")}
|
|
210
|
+
`);
|
|
211
|
+
}
|
|
212
|
+
function renderTabContent(tab, data) {
|
|
213
|
+
switch (tab) {
|
|
214
|
+
case "Status":
|
|
215
|
+
renderStatusTab(data);
|
|
216
|
+
break;
|
|
217
|
+
case "Config":
|
|
218
|
+
renderConfigTab(data);
|
|
219
|
+
break;
|
|
220
|
+
case "Usage":
|
|
221
|
+
renderUsageTab(data);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function renderStatusTab(data) {
|
|
226
|
+
console.log(chalk.bold("Version:"), data.version);
|
|
227
|
+
console.log(chalk.bold("Session ID:"), data.sessionId ?? chalk.gray("none"));
|
|
228
|
+
console.log(chalk.bold("cwd:"), data.cwd);
|
|
229
|
+
console.log(chalk.bold("Provider:"), data.provider);
|
|
230
|
+
console.log(chalk.bold("Model:"), data.model);
|
|
231
|
+
console.log();
|
|
232
|
+
console.log(
|
|
233
|
+
chalk.bold("API Status:"),
|
|
234
|
+
data.apiConnected ? chalk.green("Connected") : chalk.red("Disconnected")
|
|
235
|
+
);
|
|
236
|
+
console.log(chalk.bold("Sessions:"), `${data.sessionsCount} total`);
|
|
237
|
+
console.log(chalk.bold("Memory:"), "user (~/.autohand/memory/), project (.autohand/memory/)");
|
|
238
|
+
}
|
|
239
|
+
function renderConfigTab(data) {
|
|
240
|
+
const config = data.config;
|
|
241
|
+
console.log(chalk.bold("Autohand preferences\n"));
|
|
242
|
+
const settings = [
|
|
243
|
+
["Theme", config?.ui?.theme ?? "dark"],
|
|
244
|
+
["Auto-confirm", config?.ui?.autoConfirm ? "true" : "false"],
|
|
245
|
+
["Show thinking", config?.ui?.showThinking !== false ? "true" : "false"],
|
|
246
|
+
["Show completion notification", config?.ui?.showCompletionNotification !== false ? "true" : "false"],
|
|
247
|
+
["Permission mode", config?.permissions?.mode ?? "interactive"],
|
|
248
|
+
["Telemetry", config?.telemetry?.enabled !== false ? "true" : "false"],
|
|
249
|
+
["Network retries", String(config?.network?.maxRetries ?? 3)],
|
|
250
|
+
["Network timeout", `${config?.network?.timeout ?? 3e4}ms`]
|
|
251
|
+
];
|
|
252
|
+
for (const [name, value] of settings) {
|
|
253
|
+
console.log(` ${chalk.cyan(name.padEnd(30))} ${value}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function renderUsageTab(data) {
|
|
257
|
+
const contextUsed = 100 - data.contextPercentLeft;
|
|
258
|
+
console.log(chalk.bold("Current session\n"));
|
|
259
|
+
renderProgressBar("Context used", contextUsed, 100);
|
|
260
|
+
console.log();
|
|
261
|
+
console.log(chalk.bold("Tokens used:"), formatTokens(data.totalTokensUsed));
|
|
262
|
+
}
|
|
263
|
+
function renderProgressBar(label, value, max) {
|
|
264
|
+
const width = 30;
|
|
265
|
+
const filled = Math.round(value / max * width);
|
|
266
|
+
const empty = width - filled;
|
|
267
|
+
const bar = chalk.cyan("\u2588".repeat(filled)) + chalk.gray("\u2591".repeat(empty));
|
|
268
|
+
const percent = Math.round(value / max * 100);
|
|
269
|
+
console.log(label);
|
|
270
|
+
console.log(`${bar} ${percent}% used`);
|
|
271
|
+
}
|
|
272
|
+
function formatTokens(tokens) {
|
|
273
|
+
if (tokens >= 1e3) {
|
|
274
|
+
return `${(tokens / 1e3).toFixed(1)}k tokens`;
|
|
275
|
+
}
|
|
276
|
+
return `${tokens} tokens`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export {
|
|
280
|
+
package_default,
|
|
281
|
+
metadata,
|
|
282
|
+
status
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* @license
|
|
286
|
+
* Copyright 2025 Autohand AI LLC
|
|
287
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
288
|
+
*/
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// src/commands/status.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import readline from "readline";
|
|
4
|
+
|
|
5
|
+
// package.json
|
|
6
|
+
var package_default = {
|
|
7
|
+
name: "autohand-cli",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
description: "Autohand interactive coding agent CLI powered by LLMs.",
|
|
10
|
+
type: "module",
|
|
11
|
+
bin: {
|
|
12
|
+
autohand: "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
main: "dist/index.js",
|
|
15
|
+
files: [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
scripts: {
|
|
19
|
+
go: 'bun run build && ./install-local.sh && echo "COMPLETED"',
|
|
20
|
+
build: "tsup src/index.ts --format esm,cjs --dts",
|
|
21
|
+
dev: "tsx src/index.ts",
|
|
22
|
+
typecheck: "tsc --noEmit",
|
|
23
|
+
lint: "eslint .",
|
|
24
|
+
test: "vitest run",
|
|
25
|
+
start: "node dist/index.js",
|
|
26
|
+
"compile:macos-arm64": "bun build ./src/index.ts --compile --target=bun-darwin-arm64 --outfile ./binaries/autohand-macos-arm64",
|
|
27
|
+
"compile:macos-x64": "bun build ./src/index.ts --compile --target=bun-darwin-x64 --outfile ./binaries/autohand-macos-x64",
|
|
28
|
+
"compile:linux-x64": "bun build ./src/index.ts --compile --target=bun-linux-x64 --outfile ./binaries/autohand-linux-x64",
|
|
29
|
+
"compile:linux-arm64": "bun build ./src/index.ts --compile --target=bun-linux-arm64 --outfile ./binaries/autohand-linux-arm64",
|
|
30
|
+
"compile:windows-x64": "bun build ./src/index.ts --compile --target=bun-windows-x64 --outfile ./binaries/autohand-windows-x64.exe",
|
|
31
|
+
"compile:all": "bun run compile:macos-arm64 && bun run compile:macos-x64 && bun run compile:linux-x64 && bun run compile:linux-arm64 && bun run compile:windows-x64",
|
|
32
|
+
link: "bun link"
|
|
33
|
+
},
|
|
34
|
+
keywords: [
|
|
35
|
+
"cli",
|
|
36
|
+
"llm",
|
|
37
|
+
"agent",
|
|
38
|
+
"autohand"
|
|
39
|
+
],
|
|
40
|
+
engines: {
|
|
41
|
+
node: ">=18.17.0"
|
|
42
|
+
},
|
|
43
|
+
dependencies: {
|
|
44
|
+
chalk: "^5.6.2",
|
|
45
|
+
commander: "^14.0.2",
|
|
46
|
+
diff: "^8.0.2",
|
|
47
|
+
enquirer: "^2.4.1",
|
|
48
|
+
"fs-extra": "^11.3.2",
|
|
49
|
+
ignore: "^5.3.1",
|
|
50
|
+
ink: "^4.4.1",
|
|
51
|
+
open: "^10.1.0",
|
|
52
|
+
ora: "^9.0.0",
|
|
53
|
+
react: "^18.2.0",
|
|
54
|
+
"terminal-link": "^3.0.0",
|
|
55
|
+
yaml: "^2.8.2",
|
|
56
|
+
zod: "^4.1.12"
|
|
57
|
+
},
|
|
58
|
+
devDependencies: {
|
|
59
|
+
"@types/diff": "^8.0.0",
|
|
60
|
+
"@types/fs-extra": "^11.0.4",
|
|
61
|
+
"@types/node": "^24.10.1",
|
|
62
|
+
"@types/react": "^18.3.3",
|
|
63
|
+
"@types/terminal-link": "^1.2.0",
|
|
64
|
+
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
|
65
|
+
"@typescript-eslint/parser": "^8.48.1",
|
|
66
|
+
eslint: "^9.39.1",
|
|
67
|
+
"react-devtools-core": "^7.0.1",
|
|
68
|
+
tsup: "^8.5.1",
|
|
69
|
+
tsx: "^4.20.6",
|
|
70
|
+
typescript: "^5.9.3",
|
|
71
|
+
vitest: "^1.6.0"
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/commands/status.ts
|
|
76
|
+
var metadata = {
|
|
77
|
+
command: "/status",
|
|
78
|
+
description: "Show Autohand status including version, model, API connectivity, and usage",
|
|
79
|
+
implemented: true
|
|
80
|
+
};
|
|
81
|
+
async function status(ctx) {
|
|
82
|
+
const data = await gatherStatusData(ctx);
|
|
83
|
+
await renderStatusUI(data);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
async function gatherStatusData(ctx) {
|
|
87
|
+
const currentSession = ctx.sessionManager.getCurrentSession();
|
|
88
|
+
const allSessions = await ctx.sessionManager.listSessions();
|
|
89
|
+
let apiConnected = false;
|
|
90
|
+
try {
|
|
91
|
+
apiConnected = await ctx.llm.isAvailable();
|
|
92
|
+
} catch {
|
|
93
|
+
apiConnected = false;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
version: package_default.version,
|
|
97
|
+
sessionId: currentSession?.metadata.sessionId ?? null,
|
|
98
|
+
cwd: ctx.workspaceRoot,
|
|
99
|
+
provider: ctx.provider ?? "openrouter",
|
|
100
|
+
model: ctx.model,
|
|
101
|
+
apiConnected,
|
|
102
|
+
sessionsCount: allSessions.length,
|
|
103
|
+
contextPercentLeft: ctx.getContextPercentLeft?.() ?? 100,
|
|
104
|
+
totalTokensUsed: ctx.getTotalTokensUsed?.() ?? 0,
|
|
105
|
+
config: ctx.config
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function renderStatusUI(data) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
const tabs = ["Status", "Config", "Usage"];
|
|
111
|
+
let currentTab = 0;
|
|
112
|
+
const input = process.stdin;
|
|
113
|
+
const isTTY = input.isTTY;
|
|
114
|
+
const wasRaw = input.isRaw;
|
|
115
|
+
const wasPaused = typeof input.isPaused === "function" ? input.isPaused() : false;
|
|
116
|
+
if (wasPaused && typeof input.resume === "function") {
|
|
117
|
+
input.resume();
|
|
118
|
+
}
|
|
119
|
+
if (isTTY) {
|
|
120
|
+
readline.emitKeypressEvents(input);
|
|
121
|
+
if (!wasRaw && typeof input.setRawMode === "function") {
|
|
122
|
+
input.setRawMode(true);
|
|
123
|
+
}
|
|
124
|
+
if (typeof input.setEncoding === "function") {
|
|
125
|
+
input.setEncoding("utf8");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const render = () => {
|
|
129
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
130
|
+
renderTabHeader(tabs, currentTab);
|
|
131
|
+
renderTabContent(tabs[currentTab], data);
|
|
132
|
+
console.log(chalk.gray("\nEsc to exit"));
|
|
133
|
+
};
|
|
134
|
+
let buffer = "";
|
|
135
|
+
const handler = (chunk) => {
|
|
136
|
+
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
137
|
+
const processNext = () => {
|
|
138
|
+
if (!buffer.length) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const first = buffer[0];
|
|
142
|
+
if (first === "\x1B") {
|
|
143
|
+
if (buffer.length === 1) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (buffer[1] === "[") {
|
|
147
|
+
if (buffer.length < 3) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const seq = buffer.slice(0, 3);
|
|
151
|
+
buffer = buffer.slice(3);
|
|
152
|
+
handleSequence(seq);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
buffer = buffer.slice(1);
|
|
156
|
+
handleSequence("\x1B");
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
buffer = buffer.slice(1);
|
|
160
|
+
handleSequence(first);
|
|
161
|
+
return true;
|
|
162
|
+
};
|
|
163
|
+
while (processNext()) {
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const handleSequence = (sequence) => {
|
|
167
|
+
switch (sequence) {
|
|
168
|
+
case "\x1B":
|
|
169
|
+
// ESC
|
|
170
|
+
case "":
|
|
171
|
+
cleanup();
|
|
172
|
+
resolve();
|
|
173
|
+
return;
|
|
174
|
+
case " ":
|
|
175
|
+
// Tab
|
|
176
|
+
case "\x1B[C":
|
|
177
|
+
currentTab = (currentTab + 1) % tabs.length;
|
|
178
|
+
render();
|
|
179
|
+
return;
|
|
180
|
+
case "\x1B[Z":
|
|
181
|
+
// Shift+Tab
|
|
182
|
+
case "\x1B[D":
|
|
183
|
+
currentTab = (currentTab - 1 + tabs.length) % tabs.length;
|
|
184
|
+
render();
|
|
185
|
+
return;
|
|
186
|
+
default:
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const cleanup = () => {
|
|
191
|
+
input.off("data", handler);
|
|
192
|
+
if (isTTY && !wasRaw && typeof input.setRawMode === "function") {
|
|
193
|
+
input.setRawMode(false);
|
|
194
|
+
}
|
|
195
|
+
if (wasPaused && typeof input.pause === "function") {
|
|
196
|
+
input.pause();
|
|
197
|
+
}
|
|
198
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
199
|
+
};
|
|
200
|
+
input.on("data", handler);
|
|
201
|
+
render();
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function renderTabHeader(tabs, currentIndex) {
|
|
205
|
+
const header = tabs.map((tab, i) => {
|
|
206
|
+
return i === currentIndex ? chalk.bgWhite.black(` ${tab} `) : chalk.gray(` ${tab} `);
|
|
207
|
+
}).join(" ");
|
|
208
|
+
console.log(`Settings: ${header} ${chalk.gray("(tab to cycle)")}
|
|
209
|
+
`);
|
|
210
|
+
}
|
|
211
|
+
function renderTabContent(tab, data) {
|
|
212
|
+
switch (tab) {
|
|
213
|
+
case "Status":
|
|
214
|
+
renderStatusTab(data);
|
|
215
|
+
break;
|
|
216
|
+
case "Config":
|
|
217
|
+
renderConfigTab(data);
|
|
218
|
+
break;
|
|
219
|
+
case "Usage":
|
|
220
|
+
renderUsageTab(data);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function renderStatusTab(data) {
|
|
225
|
+
console.log(chalk.bold("Version:"), data.version);
|
|
226
|
+
console.log(chalk.bold("Session ID:"), data.sessionId ?? chalk.gray("none"));
|
|
227
|
+
console.log(chalk.bold("cwd:"), data.cwd);
|
|
228
|
+
console.log(chalk.bold("Provider:"), data.provider);
|
|
229
|
+
console.log(chalk.bold("Model:"), data.model);
|
|
230
|
+
console.log();
|
|
231
|
+
console.log(
|
|
232
|
+
chalk.bold("API Status:"),
|
|
233
|
+
data.apiConnected ? chalk.green("Connected") : chalk.red("Disconnected")
|
|
234
|
+
);
|
|
235
|
+
console.log(chalk.bold("Sessions:"), `${data.sessionsCount} total`);
|
|
236
|
+
console.log(chalk.bold("Memory:"), "user (~/.autohand/memory/), project (.autohand/memory/)");
|
|
237
|
+
}
|
|
238
|
+
function renderConfigTab(data) {
|
|
239
|
+
const config = data.config;
|
|
240
|
+
console.log(chalk.bold("Autohand preferences\n"));
|
|
241
|
+
const settings = [
|
|
242
|
+
["Theme", config?.ui?.theme ?? "dark"],
|
|
243
|
+
["Auto-confirm", config?.ui?.autoConfirm ? "true" : "false"],
|
|
244
|
+
["Show thinking", config?.ui?.showThinking !== false ? "true" : "false"],
|
|
245
|
+
["Show completion notification", config?.ui?.showCompletionNotification !== false ? "true" : "false"],
|
|
246
|
+
["Permission mode", config?.permissions?.mode ?? "interactive"],
|
|
247
|
+
["Telemetry", config?.telemetry?.enabled !== false ? "true" : "false"],
|
|
248
|
+
["Network retries", String(config?.network?.maxRetries ?? 3)],
|
|
249
|
+
["Network timeout", `${config?.network?.timeout ?? 3e4}ms`]
|
|
250
|
+
];
|
|
251
|
+
for (const [name, value] of settings) {
|
|
252
|
+
console.log(` ${chalk.cyan(name.padEnd(30))} ${value}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function renderUsageTab(data) {
|
|
256
|
+
const contextUsed = 100 - data.contextPercentLeft;
|
|
257
|
+
console.log(chalk.bold("Current session\n"));
|
|
258
|
+
renderProgressBar("Context used", contextUsed, 100);
|
|
259
|
+
console.log();
|
|
260
|
+
console.log(chalk.bold("Tokens used:"), formatTokens(data.totalTokensUsed));
|
|
261
|
+
}
|
|
262
|
+
function renderProgressBar(label, value, max) {
|
|
263
|
+
const width = 30;
|
|
264
|
+
const filled = Math.round(value / max * width);
|
|
265
|
+
const empty = width - filled;
|
|
266
|
+
const bar = chalk.cyan("\u2588".repeat(filled)) + chalk.gray("\u2591".repeat(empty));
|
|
267
|
+
const percent = Math.round(value / max * 100);
|
|
268
|
+
console.log(label);
|
|
269
|
+
console.log(`${bar} ${percent}% used`);
|
|
270
|
+
}
|
|
271
|
+
function formatTokens(tokens) {
|
|
272
|
+
if (tokens >= 1e3) {
|
|
273
|
+
return `${(tokens / 1e3).toFixed(1)}k tokens`;
|
|
274
|
+
}
|
|
275
|
+
return `${tokens} tokens`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
package_default,
|
|
280
|
+
metadata,
|
|
281
|
+
status
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* @license
|
|
285
|
+
* Copyright 2025 Autohand AI LLC
|
|
286
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
287
|
+
*/
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AUTOHAND_FILES
|
|
3
|
+
} from "./chunk-RAL2W5UX.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
|
+
*/
|