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.
Files changed (67) hide show
  1. package/README.md +132 -60
  2. package/dist/agent.d.ts +17 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +331 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/cli.d.ts +14 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +320 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/config.d.ts +58 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +152 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/executor.d.ts +48 -0
  15. package/dist/executor.d.ts.map +1 -0
  16. package/dist/executor.js +458 -0
  17. package/dist/executor.js.map +1 -0
  18. package/dist/index.d.ts +23 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +45 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/logger.d.ts +37 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +121 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/path-utils.d.ts +44 -0
  27. package/dist/path-utils.d.ts.map +1 -0
  28. package/dist/path-utils.js +206 -0
  29. package/dist/path-utils.js.map +1 -0
  30. package/dist/protocol.d.ts +92 -0
  31. package/dist/protocol.d.ts.map +1 -0
  32. package/dist/protocol.js +94 -0
  33. package/dist/protocol.js.map +1 -0
  34. package/dist/security.d.ts +32 -0
  35. package/dist/security.d.ts.map +1 -0
  36. package/dist/security.js +228 -0
  37. package/dist/security.js.map +1 -0
  38. package/dist/skills.d.ts +16 -0
  39. package/dist/skills.d.ts.map +1 -0
  40. package/dist/skills.js +105 -0
  41. package/dist/skills.js.map +1 -0
  42. package/dist/tokens.d.ts +26 -0
  43. package/dist/tokens.d.ts.map +1 -0
  44. package/dist/tokens.js +50 -0
  45. package/dist/tokens.js.map +1 -0
  46. package/dist/tools.d.ts +69 -0
  47. package/dist/tools.d.ts.map +1 -0
  48. package/dist/tools.js +694 -0
  49. package/dist/tools.js.map +1 -0
  50. package/package.json +36 -21
  51. package/src/config.js +0 -94
  52. package/src/http-fs.js +0 -178
  53. package/src/index.js +0 -442
  54. package/src/logger.js +0 -84
  55. package/src/methods/browse.js +0 -91
  56. package/src/methods/dialog.js +0 -84
  57. package/src/methods/fs.js +0 -674
  58. package/src/methods/git.js +0 -391
  59. package/src/methods/project.js +0 -57
  60. package/src/methods/scaffold.js +0 -131
  61. package/src/methods/skill.js +0 -472
  62. package/src/methods/system.js +0 -82
  63. package/src/methods/terminal.js +0 -234
  64. package/src/origin.js +0 -38
  65. package/src/pairing.js +0 -168
  66. package/src/rpc.js +0 -62
  67. package/src/sandbox.js +0 -178
package/README.md CHANGED
@@ -1,91 +1,163 @@
1
1
  # ysagc-agent
2
2
 
3
- 代码工作台本机代理:替浏览器在本机执行**文件 / Git / 终端**操作。只处理工作台发来的指令,不偷传数据、不常驻收集信息。
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
- - 仅监听 `127.0.0.1`(浏览器可信源),HTTPS 页面不拦截
6
- - 通信:JSON-RPC 2.0 over WebSocket(控制通道)+ 二进制帧(终端通道)
7
- - 路径沙箱:只能操作 allowlist(用户显式添加的项目根目录)内路径
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
- ## 安装(npm 方式,全球通用)
11
+ ## Highlights
13
12
 
14
- 要求 Node.js 20(Windows / macOS / Linux 均可)。
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
- ```bash
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
- 启动后终端会显示 `ysagc-agent 运行中: ws://127.0.0.1:37890`,保持该终端窗口开启即可(最小化没问题,不要关闭)。
28
+ ## Quick start
26
29
 
27
- ## 使用流程
30
+ ### Install globally and run
28
31
 
29
- 1. 打开终端执行 `npx ysagc-agent`(保持运行)。
30
- 2. 打开网站「工作台」,点击「新增工作区」→ 选择本机文件夹。
31
- 3. 在聊天中把话题「绑定工作区」后,AI 就能在对应文件夹里读文件、改代码、跑命令了。
32
+ ```bash
33
+ npm install -g ysagc-agent
32
34
 
33
- > 旧版(0.1.x)安装包渠道与配对码流程已不再需要;如需卸载:`npm rm -g ysagc-agent`。
35
+ ysagc-agent --server ws://platform.example.com/agent \
36
+ --token <your-device-token> \
37
+ --root ~/my-projects
38
+ ```
34
39
 
35
- ## 配置(agent.json)
40
+ Once connected the agent sends a `hello` frame, waits for `welcome`, then answers
41
+ `ping`/`tool_call`/`cancel` frames.
36
42
 
37
- 位置:`~/.ysagc-agent/agent.json`(Windows `C:\Users\<你>\.ysagc-agent`)。非法 JSON 会自动备份恢复。
43
+ ### Or run it from this checkout
38
44
 
39
- ```jsonc
40
- {
41
- "port": 37890, // 端口被占用自动 +1(最多 5 次)
42
- "allowedRoots": [], // 授权项目根目录(网站添加工作区时自动写入)
43
- "deviceTokenWhitelist": [], // 旧版配对令牌(sha256,兼容保留)
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
- **Q:端口被占用怎么办?** 自动尝试 37891–37894;也可 `ysagc-agent --port <端口>` 指定。
122
+ ```bash
123
+ node dist/cli.js --selftest
124
+ ```
59
125
 
60
- **Q:网页提示"未检测到本机代理"?** 确认 Agent 已在终端运行(能看到 `运行中: ws://127.0.0.1:37890`);首次 `npx` 会先下载依赖,稍等片刻。
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
- **Q:macOS 提示"无法打开"?** npm 方式无需处理;仅安装包渠道需要右键 → 打开。
130
+ ## Protocol
63
131
 
64
- **Q:日志在哪?** `~/.ysagc-agent/logs/agent.log`。日志**永不记录**密钥文件内容与 Git 凭证。
132
+ JSON text frames over a WebSocket.
65
133
 
66
- **Q:Agent 会读取我电脑上的所有文件吗?** 不会。Agent 只能访问你在网站显式添加的工作区目录(allowlist),越界操作一律拒绝并记录审计;终端除外(终端等同于你的命令行,可操作整台电脑——首次使用会在网页端弹安全确认)。
134
+ **Client server**
67
135
 
68
- **Q:其他网站能控制我的 Agent 吗?** 不能。Agent 只信任站点域名与 localhost 来源(Origin 白名单),其他网页发起的连接会被拒绝。
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
- ```bash
73
- npm ci
74
- npm start # 启动
75
- npm run smoke # 冒烟测试(WS 鉴权 / RPC / 终端全链路)
76
- node scripts/smoke.js <token> <port> # 自定义参数
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
- npx @yao-pkg/pkg . --target node22-win-x64 --output dist/ysagc-agent.exe
83
- # 三平台(Linux 环境可交叉产出):
84
- npx @yao-pkg/pkg . --target node22-win-x64,node22-macos-x64,node22-linux-x64 --output dist/ysagc-agent
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
- CI:`.gitlab-ci.yml`(build 产物 + tag 触发发布到 Package Registry / npm)。
88
-
89
- ## 隐私
161
+ ## License
90
162
 
91
- Agent 与网站后端的交互仅限:设备自动注册、版本握手、审计元数据。**项目文件内容、终端输入输出、Git 凭证一律不经过网站后端**。
163
+ MIT
@@ -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"}