ysagc-agent 0.3.0 → 0.5.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 +132 -60
- package/dist/agent.d.ts +17 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +331 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +320 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +152 -0
- package/dist/config.js.map +1 -0
- package/dist/executor.d.ts +48 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +458 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +37 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +121 -0
- package/dist/logger.js.map +1 -0
- package/dist/path-utils.d.ts +44 -0
- package/dist/path-utils.d.ts.map +1 -0
- package/dist/path-utils.js +206 -0
- package/dist/path-utils.js.map +1 -0
- package/dist/protocol.d.ts +92 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +94 -0
- package/dist/protocol.js.map +1 -0
- package/dist/security.d.ts +32 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +228 -0
- package/dist/security.js.map +1 -0
- package/dist/skills.d.ts +16 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +105 -0
- package/dist/skills.js.map +1 -0
- package/dist/tokens.d.ts +26 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +50 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tools.d.ts +69 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +694 -0
- package/dist/tools.js.map +1 -0
- package/package.json +36 -21
- package/src/config.js +0 -94
- package/src/http-fs.js +0 -178
- package/src/index.js +0 -442
- package/src/logger.js +0 -84
- package/src/methods/browse.js +0 -91
- package/src/methods/dialog.js +0 -84
- package/src/methods/fs.js +0 -674
- package/src/methods/git.js +0 -391
- package/src/methods/project.js +0 -57
- package/src/methods/scaffold.js +0 -131
- package/src/methods/skill.js +0 -472
- package/src/methods/system.js +0 -82
- package/src/methods/terminal.js +0 -234
- package/src/origin.js +0 -38
- package/src/pairing.js +0 -168
- package/src/rpc.js +0 -62
- package/src/sandbox.js +0 -178
package/README.md
CHANGED
|
@@ -1,91 +1,163 @@
|
|
|
1
1
|
# ysagc-agent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The **local execution agent** for ysagc. It runs on a user's own computer, opens a
|
|
4
|
+
WebSocket to the platform backend, receives tool instructions, executes them
|
|
5
|
+
**safely inside an authorization root**, and reports results back.
|
|
4
6
|
|
|
5
|
-
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
- 终端:node-pty(Windows: PowerShell / macOS·Linux: 默认 shell),输入输出**不经过网站后端**
|
|
9
|
-
- **免配对码**(v0.2.0):浏览器打开网站「工作台」自动识别并连接本机代理,无需输入配对码、无需安装 exe
|
|
10
|
-
- **目录树浏览 + 技能链接安装**(v0.3.0):新增 `fs.browse`(网页内逐级选文件夹)与 `skill.installFromUrl`(从链接下载安装技能)
|
|
7
|
+
`ysagc-agent` is deliberately **state-agnostic**: it never stores balances, never
|
|
8
|
+
makes billing decisions, and never holds platform secrets. It is a dumb, safe,
|
|
9
|
+
well-scoped executor — all policy lives on the platform.
|
|
11
10
|
|
|
12
|
-
##
|
|
11
|
+
## Highlights
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
- **Authorization root** — every file operation is forced inside one directory tree.
|
|
14
|
+
- **Danger-command guard** — destructive shell commands are detected and blocked.
|
|
15
|
+
- **Sensitive-path guard** — credential/system paths are blocked regardless of mode.
|
|
16
|
+
- **Secret masking** — secrets are redacted from logs and tool results.
|
|
17
|
+
- **Idempotency** — repeated `tool_call`s with the same key return the cached result
|
|
18
|
+
and never double-execute or double-write.
|
|
19
|
+
- **Heartbeat & auto-reconnect** — exponential backoff with a cap.
|
|
20
|
+
- **Cancel support** — in-flight commands can be aborted by the platform.
|
|
21
|
+
- **Strict TypeScript** — compiled with `tsc` to CommonJS, zero `any` leaks.
|
|
22
|
+
- **Cross-platform** — bash, PowerShell and cmd command detection.
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
# 方式一:免安装,直接跑(推荐,首次会下载依赖包)
|
|
18
|
-
npx ysagc-agent
|
|
24
|
+
## Requirements
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
npm i -g ysagc-agent
|
|
22
|
-
ysagc-agent
|
|
23
|
-
```
|
|
26
|
+
- Node.js **>= 18**
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
## Quick start
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
### Install globally and run
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
3. 在聊天中把话题「绑定工作区」后,AI 就能在对应文件夹里读文件、改代码、跑命令了。
|
|
32
|
+
```bash
|
|
33
|
+
npm install -g ysagc-agent
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
ysagc-agent --server ws://platform.example.com/agent \
|
|
36
|
+
--token <your-device-token> \
|
|
37
|
+
--root ~/my-projects
|
|
38
|
+
```
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
Once connected the agent sends a `hello` frame, waits for `welcome`, then answers
|
|
41
|
+
`ping`/`tool_call`/`cancel` frames.
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
### Or run it from this checkout
|
|
38
44
|
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"originWhitelist": [], // 允许直连的浏览器 Origin;留空=自动信任站点与 localhost
|
|
45
|
-
"trashEnabled": true, // 删除进回收站
|
|
46
|
-
"trashRetentionDays": 7,
|
|
47
|
-
"enableTerminal": true, // 终端开关
|
|
48
|
-
"terminalMaxSessions": 3,
|
|
49
|
-
"terminalIdleTimeoutMin": 30,
|
|
50
|
-
"terminalPermission": "ask", // ask=每次询问 / allow=始终允许 / deny=拒绝
|
|
51
|
-
"backendUrl": "https://chat.ysagc.top",
|
|
52
|
-
"logLevel": "info"
|
|
53
|
-
}
|
|
45
|
+
```bash
|
|
46
|
+
npm install
|
|
47
|
+
npm run build # tsc -> dist/
|
|
48
|
+
node dist/cli.js --selftest # run the smoke test
|
|
49
|
+
node dist/cli.js --server ws://... --token ... --root ~/my-projects
|
|
54
50
|
```
|
|
55
51
|
|
|
56
|
-
##
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
Settings come from defaults, then environment variables, then CLI flags
|
|
55
|
+
(CLI wins). `--token` is **never logged**.
|
|
56
|
+
|
|
57
|
+
| CLI flag | Environment | Default | Description |
|
|
58
|
+
| --------------------- | ------------------ | ----------------- | ---------------------------------------------------- |
|
|
59
|
+
| `--server <url>` | `WS_URL` | _(required)_ | Platform WebSocket URL for the agent channel |
|
|
60
|
+
| `--token <token>` | `YSAGC_TOKEN` | _(required)_ | Device/agent auth token |
|
|
61
|
+
| `--device-id <id>` | `DEVICE_ID` | host+pid | Stable device identifier |
|
|
62
|
+
| `--root <dir>` | `WORKSPACE_ROOT` | cwd | Authorization root (all file ops stay inside it) |
|
|
63
|
+
| `--mode <mode>` | `PERMISSION_MODE` | `smart` | Permission mode (see below) |
|
|
64
|
+
| `--web` | `YSAGC_WEB` | off | Enable the local web_search (stub) tool |
|
|
65
|
+
| `--timeout <ms>` | `YSAGC_TIMEOUT` | `120000` | Command timeout in milliseconds |
|
|
66
|
+
| `--max-bytes <n>` | `YSAGC_MAX_BYTES` | `64000` | Per-stream output cap before truncation |
|
|
67
|
+
| `--log-level <level>` | `YSAGC_LOG_LEVEL` | `info` | `silent\|error\|warn\|info\|debug` |
|
|
68
|
+
| `--selftest` | — | — | Run the local smoke test and exit |
|
|
69
|
+
| `-V, --version` | — | — | Print version |
|
|
70
|
+
| `-h, --help` | — | — | Print usage |
|
|
71
|
+
|
|
72
|
+
### Permission modes
|
|
73
|
+
|
|
74
|
+
| Mode | Shell behaviour |
|
|
75
|
+
| ---------- | ------------------------------------------------------------------------- |
|
|
76
|
+
| `supervise`| Every `run_command`/`git` is **denied** (requires human approval) |
|
|
77
|
+
| `smart` | Safe commands are allowed; dangerous ones are blocked (default) |
|
|
78
|
+
| `auto` | All non-dangerous commands are allowed |
|
|
79
|
+
|
|
80
|
+
Dangerous commands and sensitive paths are blocked **in every mode**.
|
|
81
|
+
|
|
82
|
+
## Tools
|
|
83
|
+
|
|
84
|
+
| Tool | Args | Returns |
|
|
85
|
+
| ------------- | ------------------------------------ | --------------------------------------- |
|
|
86
|
+
| `list_dir` | `path`, `depth` | entries (`name`, `type`, `size`, `mtime`) |
|
|
87
|
+
| `read_file` | `path`, `maxBytes` | text or hex, truncated, size info |
|
|
88
|
+
| `write_file` | `path`, `content`, `mode?` | `path`, `bytesWritten` |
|
|
89
|
+
| `edit_file` | `path`, `oldText`, `newText` | `path`, `replacements` |
|
|
90
|
+
| `run_command` | `cmd`, `timeout?`, `cwd?` | `exitCode`, `stdout`, `stderr`, flags |
|
|
91
|
+
| `web_search` | `query` | labelled **stub** result (real search is platform-side) |
|
|
92
|
+
| `git` | `args` (array) or `command` (string) | git output, `exitCode`, flags |
|
|
93
|
+
| `generate` | `template`, `name` | file list it created |
|
|
94
|
+
|
|
95
|
+
Every tool canonicalizes its path, asserts it is inside the authorization root,
|
|
96
|
+
rejects outside/sensitive paths, and never leaks platform internals or keys.
|
|
97
|
+
|
|
98
|
+
## Security model
|
|
99
|
+
|
|
100
|
+
1. **Authorization root** — `canonicalize()` resolves `..`, symlinks, the
|
|
101
|
+
`\\?\` prefix, trailing dots/spaces and Windows reserved names, then
|
|
102
|
+
`isWithinRoot()` strictly checks the result is under the root. Writes equal
|
|
103
|
+
to the root are rejected; `..` and symlink escapes are rejected too.
|
|
104
|
+
2. **Danger-command detection** — `isDangerCommand()` flags `rm -rf`, `sudo`,
|
|
105
|
+
`format`, `del /f`, `shutdown`, `reboot`, `git reset --hard`,
|
|
106
|
+
`git clean -fdx`, `find ... -delete`, `Remove-Item -Recurse -Force`,
|
|
107
|
+
`diskpart`, `reg delete`, `chmod -R 777 /`, `mkfs`, `dd of=/dev/...`,
|
|
108
|
+
redirects to block devices, fork bombs and more. Cross-platform
|
|
109
|
+
(bash / PowerShell / cmd).
|
|
110
|
+
3. **Sensitive-path detection** — `isSensitivePath()` blocks system and
|
|
111
|
+
credential paths (`/etc/passwd`, `C:\Windows\System32`, `~/.ssh`, `.env`
|
|
112
|
+
with keys, `id_rsa`, `.npmrc` with `_authToken`, and so on) regardless of mode.
|
|
113
|
+
4. **Secret masking** — `maskSecrets()` redacts provider keys, bearer tokens,
|
|
114
|
+
JWTs, private keys and `key=value` secrets from logs and tool output.
|
|
115
|
+
5. **Idempotency** — results are cached by a hash of `(tool, args, idempotencyKey)`;
|
|
116
|
+
replayed jobs return the cached result without re-executing.
|
|
117
|
+
6. **Environment sanitization** — child processes never inherit the agent's own
|
|
118
|
+
token or credential variables.
|
|
119
|
+
|
|
120
|
+
## Self-test
|
|
57
121
|
|
|
58
|
-
|
|
122
|
+
```bash
|
|
123
|
+
node dist/cli.js --selftest
|
|
124
|
+
```
|
|
59
125
|
|
|
60
|
-
|
|
126
|
+
Runs 27 checks over path safety, danger-command detection, sensitive-path
|
|
127
|
+
detection, secret masking and the tool registry, printing `PASS`/`FAIL` lines
|
|
128
|
+
and exiting `0`/`1`.
|
|
61
129
|
|
|
62
|
-
|
|
130
|
+
## Protocol
|
|
63
131
|
|
|
64
|
-
|
|
132
|
+
JSON text frames over a WebSocket.
|
|
65
133
|
|
|
66
|
-
**
|
|
134
|
+
**Client → server**
|
|
67
135
|
|
|
68
|
-
|
|
136
|
+
```jsonc
|
|
137
|
+
{ "type": "hello", "token": "...", "deviceId": "...", "version": "0.4.0", "platform": "node" }
|
|
138
|
+
{ "type": "pong", "t": 42 } // reply to a server ping
|
|
139
|
+
{ "type": "tool_result", "jobId": "j1", "ok": true, "result": { }, "durationMs": 12 }
|
|
140
|
+
{ "type": "status", "state": "online" | "busy" | "error", "sessionId": "..." }
|
|
141
|
+
```
|
|
69
142
|
|
|
70
|
-
|
|
143
|
+
**Server → client**
|
|
71
144
|
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
145
|
+
```jsonc
|
|
146
|
+
{ "type": "welcome", "sessionId": "..." }
|
|
147
|
+
{ "type": "ping", "t": 42 }
|
|
148
|
+
{ "type": "tool_call", "jobId": "j1", "idempotencyKey": "k1", "tool": "write_file", "args": { } }
|
|
149
|
+
{ "type": "cancel", "jobId": "j1" }
|
|
77
150
|
```
|
|
78
151
|
|
|
79
|
-
|
|
152
|
+
## Development
|
|
80
153
|
|
|
81
154
|
```bash
|
|
82
|
-
|
|
83
|
-
#
|
|
84
|
-
|
|
155
|
+
npm install
|
|
156
|
+
npm run build # tsc -> dist/
|
|
157
|
+
npm run test # node dist/cli.js --selftest
|
|
158
|
+
npm start # node dist/cli.js
|
|
85
159
|
```
|
|
86
160
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
## 隐私
|
|
161
|
+
## License
|
|
90
162
|
|
|
91
|
-
|
|
163
|
+
MIT
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ClientState } from './protocol';
|
|
2
|
+
import { type AgentConfig } from './config';
|
|
3
|
+
/** Kept in sync with package.json. */
|
|
4
|
+
export declare const AGENT_VERSION = "0.5.0";
|
|
5
|
+
export interface AgentHandle {
|
|
6
|
+
stop(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentEvents {
|
|
9
|
+
/** Called when the agent transitions connectivity state. */
|
|
10
|
+
onState?: (state: ClientState) => void;
|
|
11
|
+
}
|
|
12
|
+
/** Start the local agent. Throws {@link ConfigError} for missing required
|
|
13
|
+
* config (no server/token/device-id) with a friendly message. */
|
|
14
|
+
export declare function startAgent(config: AgentConfig, events?: AgentEvents): AgentHandle;
|
|
15
|
+
/** Convenience wrapper that loads config from env/CLI and starts the agent. */
|
|
16
|
+
export declare function startAgentFromEnv(overrides?: Partial<AgentConfig>): AgentHandle;
|
|
17
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAgE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAI1G,sCAAsC;AACtC,eAAO,MAAM,aAAa,UAAU,CAAC;AAQrC,MAAM,WAAW,WAAW;IAC1B,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AA8TD;iEACiE;AACjE,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAGjF;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAG/E"}
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AGENT_VERSION = void 0;
|
|
7
|
+
exports.startAgent = startAgent;
|
|
8
|
+
exports.startAgentFromEnv = startAgentFromEnv;
|
|
9
|
+
const ws_1 = __importDefault(require("ws"));
|
|
10
|
+
const protocol_1 = require("./protocol");
|
|
11
|
+
const tools_1 = require("./tools");
|
|
12
|
+
const config_1 = require("./config");
|
|
13
|
+
const tokens_1 = require("./tokens");
|
|
14
|
+
/** Kept in sync with package.json. */
|
|
15
|
+
exports.AGENT_VERSION = '0.5.0';
|
|
16
|
+
const MAX_IDEMPOTENCY_ENTRIES = 512;
|
|
17
|
+
const RECONNECT_BASE_MS = 1000;
|
|
18
|
+
const RECONNECT_CAP_MS = 60000;
|
|
19
|
+
const HEARTBEAT_MS = 30000;
|
|
20
|
+
const READY_OPEN = 1; // ws.WebSocket.OPEN
|
|
21
|
+
class Agent {
|
|
22
|
+
constructor(config, events) {
|
|
23
|
+
this.ws = null;
|
|
24
|
+
this.sessionId = '';
|
|
25
|
+
this.state = 'error';
|
|
26
|
+
this.stopped = false;
|
|
27
|
+
this.intentionalClose = false;
|
|
28
|
+
this.reconnectAttempt = 0;
|
|
29
|
+
this.jobs = new Map();
|
|
30
|
+
this.idempotencyCache = new Map();
|
|
31
|
+
this.config = config;
|
|
32
|
+
this.events = events;
|
|
33
|
+
this.log = (0, config_1.loggerFromConfig)(config);
|
|
34
|
+
this.registry = (0, tools_1.createToolRegistry)({
|
|
35
|
+
root: config.root,
|
|
36
|
+
mode: config.mode,
|
|
37
|
+
permissionPreset: config.permissionPreset,
|
|
38
|
+
webEnabled: config.web,
|
|
39
|
+
timeoutMs: config.timeoutMs,
|
|
40
|
+
maxBytes: config.maxBytes,
|
|
41
|
+
logger: this.log.child('tools'),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
start() {
|
|
45
|
+
(0, config_1.validateConfig)(this.config);
|
|
46
|
+
this.log.info('starting agent', (0, config_1.describeConfig)(this.config));
|
|
47
|
+
this.connect();
|
|
48
|
+
this.startHeartbeat();
|
|
49
|
+
return { stop: () => this.stop() };
|
|
50
|
+
}
|
|
51
|
+
connect() {
|
|
52
|
+
if (this.stopped)
|
|
53
|
+
return;
|
|
54
|
+
if (this.ws) {
|
|
55
|
+
this.log.debug('already connected, ignoring connect()');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.log.info('connecting', { url: this.config.server });
|
|
59
|
+
const ws = new ws_1.default(this.config.server, { handshakeTimeout: 15000, perMessageDeflate: false });
|
|
60
|
+
this.ws = ws;
|
|
61
|
+
ws.on('open', () => {
|
|
62
|
+
this.log.info('socket open; sending hello');
|
|
63
|
+
this.sendHello();
|
|
64
|
+
});
|
|
65
|
+
ws.on('message', (data) => {
|
|
66
|
+
this.handleMessage(data);
|
|
67
|
+
});
|
|
68
|
+
ws.on('pong', () => {
|
|
69
|
+
this.log.debug('pong received');
|
|
70
|
+
});
|
|
71
|
+
ws.on('unexpected-response', (_req, res) => {
|
|
72
|
+
this.log.warn('unexpected ws response', { status: res.statusCode });
|
|
73
|
+
});
|
|
74
|
+
ws.on('error', (err) => {
|
|
75
|
+
this.log.error('ws error', { error: err.message });
|
|
76
|
+
});
|
|
77
|
+
ws.on('close', (code, reason) => {
|
|
78
|
+
this.ws = null;
|
|
79
|
+
this.setStatus('error');
|
|
80
|
+
const reasonText = reason.toString();
|
|
81
|
+
this.log.warn('socket closed', { code, reason: reasonText });
|
|
82
|
+
// A disconnect/close should stop any in-flight jobs so a stalled command
|
|
83
|
+
// does not keep running against a backend that is no longer listening.
|
|
84
|
+
this.abortAllJobs();
|
|
85
|
+
if (this.intentionalClose || this.stopped)
|
|
86
|
+
return;
|
|
87
|
+
this.scheduleReconnect();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
sendHello() {
|
|
91
|
+
const { token, deviceId, platform } = this.config;
|
|
92
|
+
this.send({
|
|
93
|
+
type: 'hello',
|
|
94
|
+
token,
|
|
95
|
+
deviceId,
|
|
96
|
+
version: exports.AGENT_VERSION,
|
|
97
|
+
platform,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
send(msg) {
|
|
101
|
+
if (this.ws && this.ws.readyState === READY_OPEN) {
|
|
102
|
+
this.ws.send((0, protocol_1.encodeMessage)(msg));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.log.debug('dropping outbound message (socket not open)', { type: msg.type });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
handleMessage(data) {
|
|
109
|
+
const text = rawToString(data);
|
|
110
|
+
const msg = (0, protocol_1.decodeMessage)(text);
|
|
111
|
+
if (!msg) {
|
|
112
|
+
this.log.warn('ignoring malformed frame');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
switch (msg.type) {
|
|
116
|
+
case 'welcome':
|
|
117
|
+
this.onWelcome(msg);
|
|
118
|
+
break;
|
|
119
|
+
case 'ping':
|
|
120
|
+
this.onPing(msg);
|
|
121
|
+
break;
|
|
122
|
+
case 'tool_call':
|
|
123
|
+
this.onToolCall(msg);
|
|
124
|
+
break;
|
|
125
|
+
case 'cancel':
|
|
126
|
+
this.onCancel(msg);
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
this.log.warn('unhandled message type', { type: msg.type });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
onWelcome(msg) {
|
|
133
|
+
if (!(0, protocol_1.isWelcome)(msg))
|
|
134
|
+
return;
|
|
135
|
+
this.sessionId = msg.sessionId;
|
|
136
|
+
// A successful handshake resets the backoff ramp.
|
|
137
|
+
this.reconnectAttempt = 0;
|
|
138
|
+
this.setStatus('online');
|
|
139
|
+
this.log.info('welcomed', { sessionId: this.sessionId });
|
|
140
|
+
}
|
|
141
|
+
onPing(msg) {
|
|
142
|
+
if (!(0, protocol_1.isPing)(msg))
|
|
143
|
+
return;
|
|
144
|
+
this.send({ type: 'pong', t: msg.t });
|
|
145
|
+
this.log.debug('replied to ping');
|
|
146
|
+
}
|
|
147
|
+
async onToolCall(msg) {
|
|
148
|
+
if (!(0, protocol_1.isToolCall)(msg))
|
|
149
|
+
return;
|
|
150
|
+
const { jobId, tool, args, idempotencyKey } = msg;
|
|
151
|
+
const key = (0, protocol_1.computeIdempotencyKey)(tool, args ?? {}, idempotencyKey);
|
|
152
|
+
if (this.idempotencyCache.has(key)) {
|
|
153
|
+
const cached = this.idempotencyCache.get(key);
|
|
154
|
+
this.log.info('serving cached result', { jobId, tool });
|
|
155
|
+
this.sendResult({ ...cached, cached: true, durationMs: cached.durationMs }, jobId);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.setStatus('busy');
|
|
159
|
+
const controller = new AbortController();
|
|
160
|
+
this.jobs.set(jobId, controller);
|
|
161
|
+
this.log.info('running tool', { jobId, tool });
|
|
162
|
+
try {
|
|
163
|
+
const result = await this.registry.dispatch(tool, args ?? {}, controller.signal);
|
|
164
|
+
if (controller.signal.aborted) {
|
|
165
|
+
// The platform sent a cancel for this job; report it explicitly.
|
|
166
|
+
this.sendResult({ ok: false, error: 'Job cancelled by platform', durationMs: result.durationMs }, jobId);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.cacheResult(key, result);
|
|
170
|
+
this.sendResult(result, jobId);
|
|
171
|
+
// Token meter: report an approximate request/response count per turn.
|
|
172
|
+
this.sendUsage(jobId, args ?? {}, result.result ?? result.error);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
this.jobs.delete(jobId);
|
|
176
|
+
if (this.jobs.size === 0)
|
|
177
|
+
this.setStatus('online');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Emit a usage message estimating request/response tokens for this turn.
|
|
181
|
+
* When the platform supplies exact usage it wins; otherwise we estimate. */
|
|
182
|
+
sendUsage(jobId, input, output) {
|
|
183
|
+
const usage = (0, tokens_1.computeUsage)(input, output);
|
|
184
|
+
// No LLM usage available locally; estimate tokens from the payload.
|
|
185
|
+
const message = {
|
|
186
|
+
type: 'usage',
|
|
187
|
+
jobId,
|
|
188
|
+
...(this.sessionId ? { sessionId: this.sessionId } : {}),
|
|
189
|
+
inputTokens: usage.inputTokens,
|
|
190
|
+
outputTokens: usage.outputTokens,
|
|
191
|
+
totalTokens: usage.totalTokens,
|
|
192
|
+
source: 'estimate',
|
|
193
|
+
ts: Date.now(),
|
|
194
|
+
};
|
|
195
|
+
this.send(message);
|
|
196
|
+
this.log.debug('usage reported', {
|
|
197
|
+
jobId,
|
|
198
|
+
inputTokens: usage.inputTokens,
|
|
199
|
+
outputTokens: usage.outputTokens,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
onCancel(msg) {
|
|
203
|
+
if (!(0, protocol_1.isCancel)(msg))
|
|
204
|
+
return;
|
|
205
|
+
const controller = this.jobs.get(msg.jobId);
|
|
206
|
+
if (controller) {
|
|
207
|
+
controller.abort();
|
|
208
|
+
this.log.info('cancelled job', { jobId: msg.jobId });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.log.warn('cancel for unknown/job already finished', { jobId: msg.jobId });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/** Stop every in-flight job (used on disconnect / shutdown). */
|
|
215
|
+
abortAllJobs() {
|
|
216
|
+
if (this.jobs.size === 0)
|
|
217
|
+
return;
|
|
218
|
+
this.log.debug('aborting in-flight jobs', { count: this.jobs.size });
|
|
219
|
+
for (const controller of this.jobs.values())
|
|
220
|
+
controller.abort();
|
|
221
|
+
}
|
|
222
|
+
sendResult(result, jobId) {
|
|
223
|
+
const message = {
|
|
224
|
+
type: 'tool_result',
|
|
225
|
+
jobId,
|
|
226
|
+
ok: result.ok,
|
|
227
|
+
durationMs: result.durationMs,
|
|
228
|
+
...(result.result !== undefined ? { result: result.result } : {}),
|
|
229
|
+
...(result.error !== undefined ? { error: result.error } : {}),
|
|
230
|
+
...(result.cached ? { cached: true } : {}),
|
|
231
|
+
...(result.needsApproval ? { needsApproval: true } : {}),
|
|
232
|
+
};
|
|
233
|
+
this.send(message);
|
|
234
|
+
if (result.ok) {
|
|
235
|
+
this.log.info('sent result', { jobId, ok: true, durationMs: result.durationMs, cached: !!result.cached });
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
this.log.info('sent result', { jobId, ok: false, error: result.error, durationMs: result.durationMs });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
cacheResult(key, result) {
|
|
242
|
+
if (this.idempotencyCache.size >= MAX_IDEMPOTENCY_ENTRIES) {
|
|
243
|
+
const oldest = this.idempotencyCache.keys().next().value;
|
|
244
|
+
if (oldest !== undefined)
|
|
245
|
+
this.idempotencyCache.delete(oldest);
|
|
246
|
+
}
|
|
247
|
+
this.idempotencyCache.set(key, result);
|
|
248
|
+
}
|
|
249
|
+
setStatus(state) {
|
|
250
|
+
if (this.state === state)
|
|
251
|
+
return;
|
|
252
|
+
this.state = state;
|
|
253
|
+
this.send({ type: 'status', state, ...(this.sessionId ? { sessionId: this.sessionId } : {}), ts: Date.now() });
|
|
254
|
+
this.events?.onState?.(state);
|
|
255
|
+
this.log.info('status', { state });
|
|
256
|
+
}
|
|
257
|
+
startHeartbeat() {
|
|
258
|
+
if (this.heartbeatTimer)
|
|
259
|
+
return;
|
|
260
|
+
this.heartbeatTimer = setInterval(() => {
|
|
261
|
+
if (!this.stopped && this.state !== 'error' && this.ws) {
|
|
262
|
+
this.send({ type: 'status', state: this.state, ...(this.sessionId ? { sessionId: this.sessionId } : {}), ts: Date.now() });
|
|
263
|
+
}
|
|
264
|
+
}, HEARTBEAT_MS);
|
|
265
|
+
this.heartbeatTimer.unref?.();
|
|
266
|
+
}
|
|
267
|
+
scheduleReconnect() {
|
|
268
|
+
if (this.stopped)
|
|
269
|
+
return;
|
|
270
|
+
if (this.reconnectTimer)
|
|
271
|
+
return;
|
|
272
|
+
const delay = Math.min(RECONNECT_CAP_MS, RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempt));
|
|
273
|
+
this.reconnectAttempt += 1;
|
|
274
|
+
this.log.info('reconnecting', { delayMs: delay, attempt: this.reconnectAttempt });
|
|
275
|
+
this.reconnectTimer = setTimeout(() => {
|
|
276
|
+
this.reconnectTimer = undefined;
|
|
277
|
+
this.connect();
|
|
278
|
+
}, delay);
|
|
279
|
+
this.reconnectTimer.unref?.();
|
|
280
|
+
}
|
|
281
|
+
stop() {
|
|
282
|
+
this.log.info('stopping agent');
|
|
283
|
+
this.stopped = true;
|
|
284
|
+
this.intentionalClose = true;
|
|
285
|
+
if (this.reconnectTimer) {
|
|
286
|
+
clearTimeout(this.reconnectTimer);
|
|
287
|
+
this.reconnectTimer = undefined;
|
|
288
|
+
}
|
|
289
|
+
if (this.heartbeatTimer) {
|
|
290
|
+
clearInterval(this.heartbeatTimer);
|
|
291
|
+
this.heartbeatTimer = undefined;
|
|
292
|
+
}
|
|
293
|
+
for (const controller of this.jobs.values())
|
|
294
|
+
controller.abort();
|
|
295
|
+
this.jobs.clear();
|
|
296
|
+
if (this.ws) {
|
|
297
|
+
try {
|
|
298
|
+
this.ws.close(1000, 'agent stopping');
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
/* ignore */
|
|
302
|
+
}
|
|
303
|
+
this.ws = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/** Convert a ws RawData frame into a UTF-8 string. */
|
|
308
|
+
function rawToString(data) {
|
|
309
|
+
if (typeof data === 'string')
|
|
310
|
+
return data;
|
|
311
|
+
if (Array.isArray(data)) {
|
|
312
|
+
return Buffer.concat(data).toString('utf8');
|
|
313
|
+
}
|
|
314
|
+
if (data instanceof ArrayBuffer) {
|
|
315
|
+
return Buffer.from(data).toString('utf8');
|
|
316
|
+
}
|
|
317
|
+
// Buffer (or other Uint8Array)
|
|
318
|
+
return Buffer.from(data).toString('utf8');
|
|
319
|
+
}
|
|
320
|
+
/** Start the local agent. Throws {@link ConfigError} for missing required
|
|
321
|
+
* config (no server/token/device-id) with a friendly message. */
|
|
322
|
+
function startAgent(config, events) {
|
|
323
|
+
const agent = new Agent(config, events);
|
|
324
|
+
return agent.start();
|
|
325
|
+
}
|
|
326
|
+
/** Convenience wrapper that loads config from env/CLI and starts the agent. */
|
|
327
|
+
function startAgentFromEnv(overrides) {
|
|
328
|
+
const config = (0, config_1.loadConfig)(overrides);
|
|
329
|
+
return startAgent(config);
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface SelfTest {
|
|
3
|
+
name: string;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
details?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run a local smoke test of path safety, danger-command detection, sensitive
|
|
10
|
+
* path detection, secret masking and the tool registry. Returns structured
|
|
11
|
+
* PASS/FAIL results; the CLI prints them and picks the exit code.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runSelfTest(): Promise<SelfTest[]>;
|
|
14
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAaA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgGD;;;;GAIG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAkMvD"}
|