autohand-cli 0.2.0

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 (48) hide show
  1. package/README.md +134 -0
  2. package/dist/agents-RB34F4XE.js +9 -0
  3. package/dist/agents-new-5I3B2W2I.js +9 -0
  4. package/dist/chunk-2EPIFDFM.js +68 -0
  5. package/dist/chunk-2NUX2RAI.js +145 -0
  6. package/dist/chunk-2QAL3HH4.js +79 -0
  7. package/dist/chunk-4UISIRMD.js +288 -0
  8. package/dist/chunk-55DQY6B5.js +49 -0
  9. package/dist/chunk-A7HRTONQ.js +382 -0
  10. package/dist/chunk-ALMJANSA.js +197 -0
  11. package/dist/chunk-GSOEIEOU.js +19 -0
  12. package/dist/chunk-I4HVBWYF.js +55 -0
  13. package/dist/chunk-KZ7VMQTC.js +20 -0
  14. package/dist/chunk-OC5YDNFC.js +373 -0
  15. package/dist/chunk-PQJIQBQ5.js +57 -0
  16. package/dist/chunk-PX5AGAEX.js +105 -0
  17. package/dist/chunk-QJ53OSGF.js +60 -0
  18. package/dist/chunk-SVLBJMYO.js +33 -0
  19. package/dist/chunk-TAZJSKFD.js +57 -0
  20. package/dist/chunk-TVWTD63Y.js +50 -0
  21. package/dist/chunk-UW2LYWIM.js +131 -0
  22. package/dist/chunk-VRI7EXV6.js +20 -0
  23. package/dist/chunk-XDVG3NM4.js +339 -0
  24. package/dist/chunk-YWKZF2SA.js +364 -0
  25. package/dist/chunk-ZWS3KSMK.js +30 -0
  26. package/dist/completion-Y42FKDT3.js +10 -0
  27. package/dist/export-WJ5P6E5Z.js +8 -0
  28. package/dist/feedback-NEDFOKMA.js +9 -0
  29. package/dist/formatters-UG6VZJJ5.js +8 -0
  30. package/dist/help-CNOV6OXY.js +10 -0
  31. package/dist/index.cjs +13418 -0
  32. package/dist/index.d.cts +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +10450 -0
  35. package/dist/init-DML7AOII.js +8 -0
  36. package/dist/lint-TA2ZHVLM.js +8 -0
  37. package/dist/login-GPXDNB2F.js +10 -0
  38. package/dist/logout-43W7N6JU.js +10 -0
  39. package/dist/memory-4GSP7NKV.js +8 -0
  40. package/dist/model-HKEFSH5E.js +8 -0
  41. package/dist/new-EEZC4XXV.js +8 -0
  42. package/dist/quit-RSYIERO5.js +8 -0
  43. package/dist/resume-2NERFSTD.js +8 -0
  44. package/dist/session-H5QWKE5E.js +8 -0
  45. package/dist/sessions-4KXIT76T.js +8 -0
  46. package/dist/status-XAJH67SE.js +8 -0
  47. package/dist/undo-7QJBXARS.js +8 -0
  48. package/package.json +69 -0
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # Autohand CLI
2
+
3
+ [![Bun](https://img.shields.io/badge/Bun-%23c61f33?style=flat&logo=bun&logoColor=white)](https://bun.sh)
4
+
5
+ Autohand implements a CLI-based AI coding assistant utilizing the ReAct (Reason + Act) reasoning pattern. The system processes requests through sequential phases: reasoning, tool invocation (file system, Git operations, shell commands), result interpretation, and JSON-formatted response generation. Implemented in TypeScript with Bun runtime for optimal performance.
6
+
7
+ ## Features
8
+
9
+ - **ReAct Execution Model**: reason → tool calls → observation → final response
10
+ - **Toolset**: 20+ operations including `read_file`, `write_file`, `git_status`, `run_command`, `search`, etc.
11
+ - **Response Protocol**: Structured JSON `{"thought":"...","toolCalls":[...],"finalResponse":"..."}`
12
+ - **Workspace Integration**: Operates within the current project directory with Git state awareness
13
+ - **Runtime**: Bun-native with zero external dependencies, native TypeScript execution
14
+ - **Safety Controls**: Destructive operations require explicit justification in reasoning trace
15
+
16
+ ## Local Development
17
+
18
+ ### Requirements
19
+ - Bun ≥1.0 (`curl -fsSL https://bun.sh/install | bash`)
20
+
21
+ ### Installation
22
+ ```bash
23
+ bun install
24
+ ```
25
+
26
+ ### Execution
27
+ ```bash
28
+ # Development mode
29
+ bun run dev
30
+
31
+ # Production build and execution
32
+ bun build
33
+ ./dist/cli.js
34
+
35
+ # Global installation
36
+ bun add -g .
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ ### LLM Provider Configuration
42
+
43
+ Create a `.autohandrc.json` file in your project root or home directory:
44
+
45
+ ```json
46
+ {
47
+ "openrouter": {
48
+ "apiKey": "your-api-key-here",
49
+ "model": "anthropic/claude-3.5-sonnet"
50
+ },
51
+ "workspace": {
52
+ "defaultRoot": ".",
53
+ "allowDangerousOps": false
54
+ },
55
+ "ui": {
56
+ "theme": "dark",
57
+ "autoConfirm": false,
58
+ "readFileCharLimit": 300
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### API Configuration (Telemetry & Feedback)
64
+
65
+ For telemetry and feedback submission, create a `.env` file in the project root:
66
+
67
+ ```bash
68
+ # Autohand API Configuration
69
+ AUTOHAND_API_URL=https://api.autohand.ai
70
+ AUTOHAND_SECRET=your-company-secret-here
71
+ ```
72
+
73
+ **Note:** The Autohand feedback and telemetry API backend has been extracted to a separate repository:
74
+ 👉 https://github.com/autohandai/api
75
+
76
+ The CLI includes client libraries with offline queueing, retry mechanisms, and privacy features. API authentication uses a compound identifier: `device_id.company_secret`.
77
+
78
+ ### UI Settings
79
+
80
+ - **`readFileCharLimit`** (default: `300`): Maximum characters to display when reading files. Larger files will be truncated with a clear indicator.
81
+ - **`theme`**: UI theme (`"dark"` | `"light"`)
82
+ - **`autoConfirm`**: Skip confirmation prompts for destructive operations
83
+
84
+ See `config.example.json` for a full example.
85
+
86
+ ## Deployment
87
+
88
+ ### Firecracker MicroVM
89
+
90
+ Create `run-microvm.sh`:
91
+ ```bash
92
+ #!/bin/bash
93
+ firecracker --api-sock /tmp/fc.sock &
94
+
95
+ cat > config.json <<EOF
96
+ {
97
+ "boot-source": {
98
+ "kernel_image_path": "vmlinux.bin",
99
+ "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
100
+ },
101
+ "drives": [{
102
+ "drive_id": "rootfs",
103
+ "path_on_host": "rootfs.ext4",
104
+ "is_root_device": true,
105
+ "is_read_only": false
106
+ }],
107
+ "machine-config": { "vcpu_count": 2, "mem_size_mib": 1024 }
108
+ }
109
+ EOF
110
+
111
+ curl --unix-socket /tmp/fc.sock -d @config.json http://localhost/actions
112
+
113
+ # Within MicroVM: bun install && bun run dev
114
+ ```
115
+
116
+ Execute: `chmod +x run-microvm.sh && ./run-microvm.sh`
117
+
118
+ ### Docker
119
+
120
+ `Dockerfile`:
121
+ ```dockerfile
122
+ FROM oven/bun:1
123
+ WORKDIR /app
124
+ COPY . .
125
+ RUN bun install
126
+ RUN bun build
127
+ CMD ["./dist/cli.js"]
128
+ ```
129
+
130
+ Build and run:
131
+ ```bash
132
+ docker build -t autohand .
133
+ docker run -it autohand
134
+ ```
@@ -0,0 +1,9 @@
1
+ import {
2
+ handler,
3
+ metadata
4
+ } from "./chunk-ALMJANSA.js";
5
+ import "./chunk-2EPIFDFM.js";
6
+ export {
7
+ handler,
8
+ metadata
9
+ };
@@ -0,0 +1,9 @@
1
+ import {
2
+ createAgent,
3
+ metadata
4
+ } from "./chunk-PX5AGAEX.js";
5
+ import "./chunk-2EPIFDFM.js";
6
+ export {
7
+ createAgent,
8
+ metadata
9
+ };
@@ -0,0 +1,68 @@
1
+ // src/constants.ts
2
+ import os from "os";
3
+ import path from "path";
4
+ var AUTOHAND_HOME = process.env.AUTOHAND_HOME || path.join(os.homedir(), ".autohand");
5
+ var AUTOHAND_PATHS = {
6
+ /** Configuration files (config.json, config.yaml, config.yml) */
7
+ config: AUTOHAND_HOME,
8
+ /** Session data storage */
9
+ sessions: path.join(AUTOHAND_HOME, "sessions"),
10
+ /** Project knowledge base */
11
+ projects: path.join(AUTOHAND_HOME, "projects"),
12
+ /** User-level memory */
13
+ memory: path.join(AUTOHAND_HOME, "memory"),
14
+ /** Feedback state and responses */
15
+ feedback: path.join(AUTOHAND_HOME, "feedback"),
16
+ /** Telemetry data */
17
+ telemetry: path.join(AUTOHAND_HOME, "telemetry"),
18
+ /** Custom commands */
19
+ commands: path.join(AUTOHAND_HOME, "commands"),
20
+ /** Agent definitions */
21
+ agents: path.join(AUTOHAND_HOME, "agents"),
22
+ /** Custom tools */
23
+ tools: path.join(AUTOHAND_HOME, "tools")
24
+ };
25
+ var AUTOHAND_FILES = {
26
+ /** Main config file */
27
+ configJson: path.join(AUTOHAND_HOME, "config.json"),
28
+ configYaml: path.join(AUTOHAND_HOME, "config.yaml"),
29
+ configYml: path.join(AUTOHAND_HOME, "config.yml"),
30
+ /** Device ID for telemetry */
31
+ deviceId: path.join(AUTOHAND_HOME, "device-id"),
32
+ /** Error log */
33
+ errorLog: path.join(AUTOHAND_HOME, "error.log"),
34
+ /** Feedback log */
35
+ feedbackLog: path.join(AUTOHAND_HOME, "feedback.log"),
36
+ /** Telemetry queue */
37
+ telemetryQueue: path.join(AUTOHAND_PATHS.telemetry, "queue.json"),
38
+ /** Session sync queue */
39
+ sessionSyncQueue: path.join(AUTOHAND_PATHS.telemetry, "session-sync-queue.json")
40
+ };
41
+ var PROJECT_DIR_NAME = ".autohand";
42
+ var getAuthBaseUrl = () => process["env"]["AUTOHAND_API_URL"] || "https://autohand.ai";
43
+ var AUTH_CONFIG = {
44
+ get apiBaseUrl() {
45
+ return `${getAuthBaseUrl()}/api/auth`;
46
+ },
47
+ get authorizationUrl() {
48
+ return `${getAuthBaseUrl()}/cli-auth`;
49
+ },
50
+ pollInterval: 2e3,
51
+ authTimeout: 5 * 60 * 1e3,
52
+ sessionExpiryDays: 30
53
+ };
54
+
55
+ export {
56
+ AUTOHAND_HOME,
57
+ AUTOHAND_PATHS,
58
+ AUTOHAND_FILES,
59
+ PROJECT_DIR_NAME,
60
+ AUTH_CONFIG
61
+ };
62
+ /**
63
+ * @license
64
+ * Copyright 2025 Autohand AI LLC
65
+ * SPDX-License-Identifier: Apache-2.0
66
+ *
67
+ * Centralized constants for Autohand CLI
68
+ */
@@ -0,0 +1,145 @@
1
+ // src/commands/lint.ts
2
+ import chalk2 from "chalk";
3
+
4
+ // src/actions/linters.ts
5
+ import { spawn } from "child_process";
6
+ import path from "path";
7
+ import chalk from "chalk";
8
+ var LINTERS = {
9
+ eslint: {
10
+ name: "eslint",
11
+ command: "eslint",
12
+ extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"],
13
+ description: "Pluggable JavaScript/TypeScript linter",
14
+ checkCmd: ["eslint", "--version"]
15
+ },
16
+ pylint: {
17
+ name: "pylint",
18
+ command: "pylint",
19
+ extensions: [".py"],
20
+ description: "Python static code analysis tool",
21
+ checkCmd: ["pylint", "--version"]
22
+ },
23
+ ruff: {
24
+ name: "ruff",
25
+ command: "ruff",
26
+ extensions: [".py"],
27
+ description: "Extremely fast Python linter (recommended)",
28
+ checkCmd: ["ruff", "--version"]
29
+ },
30
+ clippy: {
31
+ name: "clippy",
32
+ command: "cargo",
33
+ extensions: [".rs"],
34
+ description: "Rust linter with helpful suggestions",
35
+ checkCmd: ["cargo", "clippy", "--version"]
36
+ },
37
+ golangci: {
38
+ name: "golangci-lint",
39
+ command: "golangci-lint",
40
+ extensions: [".go"],
41
+ description: "Fast Go linter aggregator",
42
+ checkCmd: ["golangci-lint", "--version"]
43
+ },
44
+ shellcheck: {
45
+ name: "shellcheck",
46
+ command: "shellcheck",
47
+ extensions: [".sh", ".bash"],
48
+ description: "Shell script static analysis tool",
49
+ checkCmd: ["shellcheck", "--version"]
50
+ },
51
+ stylelint: {
52
+ name: "stylelint",
53
+ command: "stylelint",
54
+ extensions: [".css", ".scss", ".less"],
55
+ description: "CSS linter",
56
+ checkCmd: ["stylelint", "--version"]
57
+ },
58
+ htmlhint: {
59
+ name: "htmlhint",
60
+ command: "htmlhint",
61
+ extensions: [".html", ".htm"],
62
+ description: "HTML linter",
63
+ checkCmd: ["htmlhint", "--version"]
64
+ }
65
+ };
66
+ async function isCommandAvailable(command, args = ["--version"]) {
67
+ return new Promise((resolve) => {
68
+ const proc = spawn(command, args, {
69
+ stdio: "ignore",
70
+ shell: process.platform === "win32"
71
+ });
72
+ proc.on("error", () => resolve(false));
73
+ proc.on("close", (code) => resolve(code === 0));
74
+ setTimeout(() => {
75
+ proc.kill();
76
+ resolve(false);
77
+ }, 3e3);
78
+ });
79
+ }
80
+ async function checkAvailableLinters() {
81
+ const results = {};
82
+ const checks = Object.entries(LINTERS).map(async ([name, info]) => {
83
+ if (name === "clippy") {
84
+ results[name] = await isCommandAvailable("cargo", ["clippy", "--version"]);
85
+ } else {
86
+ results[name] = await isCommandAvailable(info.command);
87
+ }
88
+ });
89
+ await Promise.all(checks);
90
+ return results;
91
+ }
92
+ async function listLinters() {
93
+ const available = await checkAvailableLinters();
94
+ return Object.entries(LINTERS).map(([name, info]) => ({
95
+ ...info,
96
+ installed: available[name] ?? false
97
+ }));
98
+ }
99
+
100
+ // src/commands/lint.ts
101
+ var metadata = {
102
+ command: "/lint",
103
+ description: "List available code linters",
104
+ implemented: true
105
+ };
106
+ async function execute() {
107
+ console.log();
108
+ console.log(chalk2.cyan.bold("Available Code Linters"));
109
+ console.log(chalk2.gray("\u2500".repeat(60)));
110
+ console.log();
111
+ const linters = await listLinters();
112
+ for (const linter of linters) {
113
+ const status = linter.installed ? chalk2.green("\u2713 installed") : chalk2.red("\u2717 not found");
114
+ console.log(` ${linter.installed ? chalk2.green("\u2713") : chalk2.red("\u2717")} ${chalk2.white.bold(linter.name)} ${chalk2.gray(`(${linter.command})`)} - ${status}`);
115
+ console.log(` ${chalk2.gray(linter.description)}`);
116
+ console.log(` ${chalk2.gray("Extensions:")} ${linter.extensions.join(", ")}`);
117
+ console.log();
118
+ }
119
+ console.log(chalk2.gray("\u2500".repeat(60)));
120
+ console.log(chalk2.gray("Usage: The agent can use lint_file action to check code quality."));
121
+ console.log(chalk2.gray("Install missing linters via your package manager:"));
122
+ console.log(chalk2.gray(" npm: npm install -g eslint stylelint"));
123
+ console.log(chalk2.gray(" pip: pip install pylint ruff"));
124
+ console.log(chalk2.gray(" cargo: rustup component add clippy"));
125
+ console.log(chalk2.gray(" go: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"));
126
+ console.log();
127
+ }
128
+
129
+ export {
130
+ metadata,
131
+ execute
132
+ };
133
+ /**
134
+ * @license
135
+ * Copyright 2025 Autohand AI LLC
136
+ * SPDX-License-Identifier: Apache-2.0
137
+ *
138
+ * Code Linters
139
+ * Supports eslint, pylint, clippy, golangci-lint, and more
140
+ */
141
+ /**
142
+ * @license
143
+ * Copyright 2025 Autohand AI LLC
144
+ * SPDX-License-Identifier: Apache-2.0
145
+ */
@@ -0,0 +1,79 @@
1
+ import {
2
+ AUTOHAND_FILES
3
+ } from "./chunk-2EPIFDFM.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
+ */