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.
- package/README.md +134 -0
- package/dist/agents-RB34F4XE.js +9 -0
- package/dist/agents-new-5I3B2W2I.js +9 -0
- package/dist/chunk-2EPIFDFM.js +68 -0
- package/dist/chunk-2NUX2RAI.js +145 -0
- package/dist/chunk-2QAL3HH4.js +79 -0
- package/dist/chunk-4UISIRMD.js +288 -0
- package/dist/chunk-55DQY6B5.js +49 -0
- package/dist/chunk-A7HRTONQ.js +382 -0
- package/dist/chunk-ALMJANSA.js +197 -0
- package/dist/chunk-GSOEIEOU.js +19 -0
- package/dist/chunk-I4HVBWYF.js +55 -0
- package/dist/chunk-KZ7VMQTC.js +20 -0
- package/dist/chunk-OC5YDNFC.js +373 -0
- package/dist/chunk-PQJIQBQ5.js +57 -0
- package/dist/chunk-PX5AGAEX.js +105 -0
- package/dist/chunk-QJ53OSGF.js +60 -0
- package/dist/chunk-SVLBJMYO.js +33 -0
- package/dist/chunk-TAZJSKFD.js +57 -0
- package/dist/chunk-TVWTD63Y.js +50 -0
- package/dist/chunk-UW2LYWIM.js +131 -0
- package/dist/chunk-VRI7EXV6.js +20 -0
- package/dist/chunk-XDVG3NM4.js +339 -0
- package/dist/chunk-YWKZF2SA.js +364 -0
- package/dist/chunk-ZWS3KSMK.js +30 -0
- package/dist/completion-Y42FKDT3.js +10 -0
- package/dist/export-WJ5P6E5Z.js +8 -0
- package/dist/feedback-NEDFOKMA.js +9 -0
- package/dist/formatters-UG6VZJJ5.js +8 -0
- package/dist/help-CNOV6OXY.js +10 -0
- package/dist/index.cjs +13418 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10450 -0
- package/dist/init-DML7AOII.js +8 -0
- package/dist/lint-TA2ZHVLM.js +8 -0
- package/dist/login-GPXDNB2F.js +10 -0
- package/dist/logout-43W7N6JU.js +10 -0
- package/dist/memory-4GSP7NKV.js +8 -0
- package/dist/model-HKEFSH5E.js +8 -0
- package/dist/new-EEZC4XXV.js +8 -0
- package/dist/quit-RSYIERO5.js +8 -0
- package/dist/resume-2NERFSTD.js +8 -0
- package/dist/session-H5QWKE5E.js +8 -0
- package/dist/sessions-4KXIT76T.js +8 -0
- package/dist/status-XAJH67SE.js +8 -0
- package/dist/undo-7QJBXARS.js +8 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Autohand CLI
|
|
2
|
+
|
|
3
|
+
[](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,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
|
+
*/
|