@yitom/agy-acp-map 0.1.4 → 0.1.6
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 +52 -1
- package/dist/agy-acp-win-x64.exe +4 -0
- package/dist/agy-headless.exe +0 -0
- package/dist/bin.js +123 -42
- package/dist/index.d.ts +1 -0
- package/dist/index.js +94 -42
- package/dist/lib/debug-log.d.ts +2 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -300,7 +300,7 @@ Engineering feasibility ≠ legal permission. 即便只用官方 CLI I/O,仍
|
|
|
300
300
|
|
|
301
301
|
## ACP V1 vs V2 Draft Specifications / 协议版本说明
|
|
302
302
|
|
|
303
|
-
- **ACP V1 (Stable)**: Production-grade implementation fully conforming to canonical ACP v1 JSON-RPC specifications.
|
|
303
|
+
- **ACP V1 (Stable)**: Production-grade implementation fully conforming to canonical ACP v1 JSON-RPC specifications. `initialize` returns a minimal Zed-verified shape (`protocolVersion`, `agentInfo`, `agentCapabilities`, `authMethods: []`; models arrive via `session/new` `configOptions`). Includes deterministic keyset cursor pagination on `session/list`, atomic session deletion, and strict session/resume semantics (`sessionId` + `cwd` required, cwd matching, omitted `additionalDirectories` reset to empty).
|
|
304
304
|
- **ACP V2 (Draft)**: Experimental v2 draft support built on `@agentclientprotocol/sdk@1.4.0` (`@agentclientprotocol/sdk/experimental/v2`). Conforms to the SDK's schema where `session/prompt` acknowledges prompt acceptance with an immediate `{}` (empty object) response, and subsequent progress is streamed via `session/update` notifications (`state_update: running -> chunks -> state_update: idle`).
|
|
305
305
|
- **Prompt Validation**: All content blocks (`text`, `resource`, `resource_link`, `image`, `audio`) are validated synchronously before sending ACK, preventing background silent failures.
|
|
306
306
|
|
|
@@ -311,6 +311,57 @@ Engineering feasibility ≠ legal permission. 即便只用官方 CLI I/O,仍
|
|
|
311
311
|
- **Zed / Editor Configuration**: When configuring the bridge in Zed on Windows, point directly to `bun` or `node` with `dist/bin.js` (or a windowless shim) rather than a `.cmd` or `.bat` wrapper. Batch scripts cause `cmd.exe` to flash a console window on launch before passing control to Node/Bun.
|
|
312
312
|
- **If a custom Zed server still flashes**: use the native wrapper as the custom command itself, for example `command: "<repo>\\dist\\agy-headless.exe"` with args `["<path-to-bun-or-node>", "<repo>\\src\\sdk-server.ts"]` (or `dist\\bin.js`). You can also set `AGY_HEADLESS_LAUNCHER` to an absolute wrapper path. Packaging the bridge on npm improves distribution, but npm packaging alone does not change Windows process creation flags.
|
|
313
313
|
|
|
314
|
+
## Zed via npm (global install) / Zed 全局安装用法
|
|
315
|
+
|
|
316
|
+
No Bun / TypeScript needed at runtime — the published package ships compiled
|
|
317
|
+
`dist/` artifacts (`bin.js` for Node, `agy-headless.exe`, plus the optional
|
|
318
|
+
single-file `agy-acp-win-x64.exe`). A **global** install is recommended so Zed
|
|
319
|
+
gets a stable absolute path (repo moves would break a local path):
|
|
320
|
+
|
|
321
|
+
```powershell
|
|
322
|
+
npm install -g @yitom/agy-acp-map
|
|
323
|
+
npm root -g # e.g. C:\Users\<you>\AppData\Roaming\npm\node_modules
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Recommended Zed `agent_servers` entry (zero console flash: GUI shim starts
|
|
327
|
+
plain `node`, only `node` is required on the machine):
|
|
328
|
+
|
|
329
|
+
```jsonc
|
|
330
|
+
"agy-acp-map-local": {
|
|
331
|
+
"type": "custom",
|
|
332
|
+
"command": "C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\@yitom\\agy-acp-map\\dist\\agy-headless.exe",
|
|
333
|
+
"args": ["node", "C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\@yitom\\agy-acp-map\\dist\\bin.js"],
|
|
334
|
+
"env": {}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Fallback without the shim (works, but `node.exe` flashes one console frame on
|
|
339
|
+
launch because Zed spawns agents without `CREATE_NO_WINDOW`):
|
|
340
|
+
|
|
341
|
+
```jsonc
|
|
342
|
+
"agy-acp-map-local": {
|
|
343
|
+
"type": "custom",
|
|
344
|
+
"command": "node",
|
|
345
|
+
"args": ["C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\@yitom\\agy-acp-map\\dist\\bin.js"],
|
|
346
|
+
"env": {}
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Do NOT point Zed at the `agy-acp` / `agy-acp.cmd` global bin wrappers (extra
|
|
351
|
+
`cmd.exe` flash), at `src/*.ts` sources (needs Bun, dev only), or at
|
|
352
|
+
`bun`/`node` without an absolute `dist` path. `initialize` intentionally
|
|
353
|
+
returns a minimal response (`protocolVersion`, `agentInfo`,
|
|
354
|
+
`agentCapabilities`, `authMethods: []`); models arrive via `session/new`
|
|
355
|
+
`configOptions`, so the Zed model picker keeps working.
|
|
356
|
+
|
|
357
|
+
Troubleshooting: the bridge hides nothing from disk — append-only file log at
|
|
358
|
+
`%TEMP%\agy-acp.log` (override with `AGY_ACP_LOG`; ~1MB rotation). If Zed says
|
|
359
|
+
`Server exited with status exit code: 0` right after launch, check the tail of
|
|
360
|
+
that file: `START` with no following `V1 initialize called` means Zed never
|
|
361
|
+
sent bytes (spawn/config issue); `V1 initialize called` followed by
|
|
362
|
+
`stdin END` means Zed rejected the handshake (capture the exchange and compare
|
|
363
|
+
against a known-good agent such as `opencode acp`).
|
|
364
|
+
|
|
314
365
|
## Bun + TypeScript / Windows
|
|
315
366
|
|
|
316
367
|
- Runtime is **Bun** (not Node). Entry: `bun src/server.ts` (or `bun run start`).
|
|
Binary file
|
package/dist/bin.js
CHANGED
|
@@ -9302,8 +9302,8 @@ var legacyClientNotificationMethods = new Set([
|
|
|
9302
9302
|
|
|
9303
9303
|
// src/core/session-core.ts
|
|
9304
9304
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9305
|
-
import * as
|
|
9306
|
-
import
|
|
9305
|
+
import * as fs9 from "node:fs";
|
|
9306
|
+
import path10 from "node:path";
|
|
9307
9307
|
// node_modules/@agentclientprotocol/sdk/dist/acp.js
|
|
9308
9308
|
function emptyObjectResponse2(response) {
|
|
9309
9309
|
return response ?? {};
|
|
@@ -11747,8 +11747,10 @@ function isAgyExecutable(bin) {
|
|
|
11747
11747
|
}
|
|
11748
11748
|
function findHeadlessLauncher() {
|
|
11749
11749
|
const moduleDir = import.meta.dir ?? path5.dirname(process.argv[1] ?? "");
|
|
11750
|
+
const execDir = path5.dirname(process.execPath ?? "");
|
|
11750
11751
|
const candidates = [
|
|
11751
11752
|
process.env.AGY_HEADLESS_LAUNCHER,
|
|
11753
|
+
execDir ? path5.join(execDir, "agy-headless.exe") : undefined,
|
|
11752
11754
|
path5.resolve(moduleDir, "..", "..", "dist", "agy-headless.exe"),
|
|
11753
11755
|
path5.resolve(moduleDir, "agy-headless.exe"),
|
|
11754
11756
|
path5.resolve(process.cwd(), "dist", "agy-headless.exe")
|
|
@@ -12486,7 +12488,7 @@ class SessionHistoryStore {
|
|
|
12486
12488
|
var AGENT_INFO = {
|
|
12487
12489
|
name: "agy-acp",
|
|
12488
12490
|
title: "agy ACP (stream-json)",
|
|
12489
|
-
version: "0.1.
|
|
12491
|
+
version: "0.1.6"
|
|
12490
12492
|
};
|
|
12491
12493
|
var BRIDGE_CAPABILITIES = {
|
|
12492
12494
|
prompt: true,
|
|
@@ -12552,6 +12554,46 @@ class AsyncSerialQueue {
|
|
|
12552
12554
|
}
|
|
12553
12555
|
}
|
|
12554
12556
|
|
|
12557
|
+
// src/lib/debug-log.ts
|
|
12558
|
+
import fs8 from "node:fs";
|
|
12559
|
+
import os4 from "node:os";
|
|
12560
|
+
import path9 from "node:path";
|
|
12561
|
+
function resolveLogPath() {
|
|
12562
|
+
const override = process.env.AGY_ACP_LOG;
|
|
12563
|
+
if (override && override !== "undefined" && override !== "null")
|
|
12564
|
+
return override;
|
|
12565
|
+
return path9.join(os4.tmpdir(), "agy-acp.log");
|
|
12566
|
+
}
|
|
12567
|
+
var logPath = null;
|
|
12568
|
+
try {
|
|
12569
|
+
logPath = resolveLogPath();
|
|
12570
|
+
} catch {
|
|
12571
|
+
logPath = null;
|
|
12572
|
+
}
|
|
12573
|
+
function writeLine(line) {
|
|
12574
|
+
if (!logPath)
|
|
12575
|
+
return;
|
|
12576
|
+
try {
|
|
12577
|
+
let truncate = false;
|
|
12578
|
+
try {
|
|
12579
|
+
const st = fs8.statSync(logPath);
|
|
12580
|
+
if (st.size > 1024 * 1024)
|
|
12581
|
+
truncate = true;
|
|
12582
|
+
} catch {}
|
|
12583
|
+
fs8.appendFileSync(logPath, line + `
|
|
12584
|
+
`, "utf8");
|
|
12585
|
+
if (truncate) {
|
|
12586
|
+
try {
|
|
12587
|
+
const text = fs8.readFileSync(logPath, "utf8");
|
|
12588
|
+
fs8.writeFileSync(logPath, text.slice(-512 * 1024), "utf8");
|
|
12589
|
+
} catch {}
|
|
12590
|
+
}
|
|
12591
|
+
} catch {}
|
|
12592
|
+
}
|
|
12593
|
+
function debugLog(msg) {
|
|
12594
|
+
writeLine(`${new Date().toISOString()} pid=${process.pid} ${msg}`);
|
|
12595
|
+
}
|
|
12596
|
+
|
|
12555
12597
|
// src/core/session-core.ts
|
|
12556
12598
|
class AgySessionCore {
|
|
12557
12599
|
sessions = new Map;
|
|
@@ -12610,8 +12652,8 @@ class AgySessionCore {
|
|
|
12610
12652
|
const rawBin = process.env.AGY_BIN;
|
|
12611
12653
|
let bin = rawBin && rawBin !== "undefined" && rawBin !== "null" ? rawBin : "agy";
|
|
12612
12654
|
if (bin === "agy" || bin === "agy.exe") {
|
|
12613
|
-
const geminiBin =
|
|
12614
|
-
if (
|
|
12655
|
+
const geminiBin = path10.join(process.env.USERPROFILE || process.env.HOME || "", ".gemini", "bin", process.platform === "win32" ? "agy.exe" : "agy");
|
|
12656
|
+
if (fs9.existsSync(geminiBin)) {
|
|
12615
12657
|
bin = geminiBin;
|
|
12616
12658
|
}
|
|
12617
12659
|
}
|
|
@@ -12746,10 +12788,11 @@ class AgySessionCore {
|
|
|
12746
12788
|
}
|
|
12747
12789
|
async createSession(params, protocolVersion = 1) {
|
|
12748
12790
|
const cwd = params?.cwd;
|
|
12749
|
-
|
|
12791
|
+
debugLog(`createSession v${protocolVersion} cwd=${cwd}`);
|
|
12792
|
+
if (!cwd || typeof cwd !== "string" || !path10.isAbsolute(cwd)) {
|
|
12750
12793
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12751
12794
|
}
|
|
12752
|
-
if (!
|
|
12795
|
+
if (!fs9.existsSync(cwd) || !fs9.statSync(cwd).isDirectory()) {
|
|
12753
12796
|
throw new RequestError(-32602, `cwd does not exist or is not a directory: ${cwd}`);
|
|
12754
12797
|
}
|
|
12755
12798
|
if (params?.additionalDirectories !== undefined) {
|
|
@@ -12757,7 +12800,7 @@ class AgySessionCore {
|
|
|
12757
12800
|
throw new RequestError(-32602, "additionalDirectories must be an array");
|
|
12758
12801
|
}
|
|
12759
12802
|
for (const d of params.additionalDirectories) {
|
|
12760
|
-
if (typeof d !== "string" || !
|
|
12803
|
+
if (typeof d !== "string" || !path10.isAbsolute(d)) {
|
|
12761
12804
|
throw new RequestError(-32602, `additionalDirectory must be an absolute path: ${d}`);
|
|
12762
12805
|
}
|
|
12763
12806
|
}
|
|
@@ -12824,10 +12867,10 @@ class AgySessionCore {
|
|
|
12824
12867
|
if (!cwd || typeof cwd !== "string") {
|
|
12825
12868
|
throw new RequestError(-32602, "cwd is required for session/resume");
|
|
12826
12869
|
}
|
|
12827
|
-
if (!
|
|
12870
|
+
if (!path10.isAbsolute(cwd)) {
|
|
12828
12871
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12829
12872
|
}
|
|
12830
|
-
if (!
|
|
12873
|
+
if (!fs9.existsSync(cwd) || !fs9.statSync(cwd).isDirectory()) {
|
|
12831
12874
|
throw new RequestError(-32602, `cwd does not exist or is not a directory: ${cwd}`);
|
|
12832
12875
|
}
|
|
12833
12876
|
if (params?.replayFrom !== undefined && params?.replayFrom !== null) {
|
|
@@ -12849,7 +12892,7 @@ class AgySessionCore {
|
|
|
12849
12892
|
throw new RequestError(-32602, "additionalDirectories must be an array");
|
|
12850
12893
|
}
|
|
12851
12894
|
for (const d of params.additionalDirectories) {
|
|
12852
|
-
if (typeof d !== "string" || !
|
|
12895
|
+
if (typeof d !== "string" || !path10.isAbsolute(d)) {
|
|
12853
12896
|
throw new RequestError(-32602, `additionalDirectory must be an absolute path: ${d}`);
|
|
12854
12897
|
}
|
|
12855
12898
|
}
|
|
@@ -12865,7 +12908,7 @@ class AgySessionCore {
|
|
|
12865
12908
|
if (recordedVersion !== protocolVersion) {
|
|
12866
12909
|
throw new RequestError(-32602, `Session ${sessionId} was created with ACP v${recordedVersion} and cannot be resumed with v${protocolVersion}`);
|
|
12867
12910
|
}
|
|
12868
|
-
if (record.cwd &&
|
|
12911
|
+
if (record.cwd && path10.resolve(record.cwd) !== path10.resolve(cwd)) {
|
|
12869
12912
|
throw new RequestError(-32602, `cwd does not match session cwd: expected ${record.cwd}, got ${cwd}`);
|
|
12870
12913
|
}
|
|
12871
12914
|
const richRoots = richRootsFromSession({
|
|
@@ -12909,7 +12952,7 @@ class AgySessionCore {
|
|
|
12909
12952
|
if (session.protocolVersion !== protocolVersion) {
|
|
12910
12953
|
throw new RequestError(-32602, `Session ${sessionId} was created with ACP v${session.protocolVersion} and cannot be resumed with v${protocolVersion}`);
|
|
12911
12954
|
}
|
|
12912
|
-
if (
|
|
12955
|
+
if (path10.resolve(session.cwd) !== path10.resolve(cwd)) {
|
|
12913
12956
|
throw new RequestError(-32602, `cwd does not match session cwd: expected ${session.cwd}, got ${cwd}`);
|
|
12914
12957
|
}
|
|
12915
12958
|
session.additionalDirectories = additionalDirectories;
|
|
@@ -12977,7 +13020,7 @@ class AgySessionCore {
|
|
|
12977
13020
|
async listSessions(params) {
|
|
12978
13021
|
const filterCwd = params?.cwd;
|
|
12979
13022
|
if (filterCwd !== undefined && filterCwd !== null) {
|
|
12980
|
-
if (typeof filterCwd !== "string" || !
|
|
13023
|
+
if (typeof filterCwd !== "string" || !path10.isAbsolute(filterCwd)) {
|
|
12981
13024
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12982
13025
|
}
|
|
12983
13026
|
}
|
|
@@ -13204,8 +13247,8 @@ class AgySessionCore {
|
|
|
13204
13247
|
if (process.env.AGY_ACP_KEEP_STAGING !== "1" && session.stagedFiles.length) {
|
|
13205
13248
|
for (const f of session.stagedFiles) {
|
|
13206
13249
|
try {
|
|
13207
|
-
if (
|
|
13208
|
-
|
|
13250
|
+
if (fs9.existsSync(f))
|
|
13251
|
+
fs9.unlinkSync(f);
|
|
13209
13252
|
} catch {}
|
|
13210
13253
|
}
|
|
13211
13254
|
session.stagedFiles = [];
|
|
@@ -13330,18 +13373,6 @@ class AgySessionCore {
|
|
|
13330
13373
|
}
|
|
13331
13374
|
}
|
|
13332
13375
|
|
|
13333
|
-
// src/v1/types.ts
|
|
13334
|
-
var V1_AGENT_CAPABILITIES = {
|
|
13335
|
-
loadSession: true,
|
|
13336
|
-
sessionCapabilities: {
|
|
13337
|
-
list: {},
|
|
13338
|
-
resume: {},
|
|
13339
|
-
close: {},
|
|
13340
|
-
delete: {},
|
|
13341
|
-
additionalDirectories: {}
|
|
13342
|
-
}
|
|
13343
|
-
};
|
|
13344
|
-
|
|
13345
13376
|
// src/v1/config.ts
|
|
13346
13377
|
function buildV1ConfigOptions(discovery, session) {
|
|
13347
13378
|
const models = catalogChoices(discovery.availableModels, session?.model);
|
|
@@ -13379,22 +13410,16 @@ class AgyAcpV1Service {
|
|
|
13379
13410
|
this.core = core;
|
|
13380
13411
|
}
|
|
13381
13412
|
async initialize() {
|
|
13382
|
-
|
|
13383
|
-
|
|
13413
|
+
debugLog("V1 initialize called");
|
|
13414
|
+
debugLog("V1 initialize called (minimal response)");
|
|
13384
13415
|
return {
|
|
13385
13416
|
protocolVersion: 1,
|
|
13386
|
-
agentInfo: AGENT_INFO,
|
|
13387
|
-
agentCapabilities:
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
availableAgents: discovery.availableAgents,
|
|
13393
|
-
configOptions
|
|
13394
|
-
},
|
|
13395
|
-
availableModels: discovery.availableModels,
|
|
13396
|
-
availableAgents: discovery.availableAgents
|
|
13397
|
-
}
|
|
13417
|
+
agentInfo: { name: AGENT_INFO.name, version: AGENT_INFO.version },
|
|
13418
|
+
agentCapabilities: {
|
|
13419
|
+
loadSession: true,
|
|
13420
|
+
sessionCapabilities: { close: {}, list: {}, resume: {} }
|
|
13421
|
+
},
|
|
13422
|
+
authMethods: []
|
|
13398
13423
|
};
|
|
13399
13424
|
}
|
|
13400
13425
|
async newSession(params) {
|
|
@@ -17752,11 +17777,67 @@ class AgyAcpService {
|
|
|
17752
17777
|
}
|
|
17753
17778
|
}
|
|
17754
17779
|
|
|
17780
|
+
// src/lib/debug-log.ts
|
|
17781
|
+
import fs10 from "node:fs";
|
|
17782
|
+
import os5 from "node:os";
|
|
17783
|
+
import path11 from "node:path";
|
|
17784
|
+
function resolveLogPath2() {
|
|
17785
|
+
const override = process.env.AGY_ACP_LOG;
|
|
17786
|
+
if (override && override !== "undefined" && override !== "null")
|
|
17787
|
+
return override;
|
|
17788
|
+
return path11.join(os5.tmpdir(), "agy-acp.log");
|
|
17789
|
+
}
|
|
17790
|
+
var logPath2 = null;
|
|
17791
|
+
try {
|
|
17792
|
+
logPath2 = resolveLogPath2();
|
|
17793
|
+
} catch {
|
|
17794
|
+
logPath2 = null;
|
|
17795
|
+
}
|
|
17796
|
+
function writeLine2(line) {
|
|
17797
|
+
if (!logPath2)
|
|
17798
|
+
return;
|
|
17799
|
+
try {
|
|
17800
|
+
let truncate = false;
|
|
17801
|
+
try {
|
|
17802
|
+
const st = fs10.statSync(logPath2);
|
|
17803
|
+
if (st.size > 1024 * 1024)
|
|
17804
|
+
truncate = true;
|
|
17805
|
+
} catch {}
|
|
17806
|
+
fs10.appendFileSync(logPath2, line + `
|
|
17807
|
+
`, "utf8");
|
|
17808
|
+
if (truncate) {
|
|
17809
|
+
try {
|
|
17810
|
+
const text = fs10.readFileSync(logPath2, "utf8");
|
|
17811
|
+
fs10.writeFileSync(logPath2, text.slice(-512 * 1024), "utf8");
|
|
17812
|
+
} catch {}
|
|
17813
|
+
}
|
|
17814
|
+
} catch {}
|
|
17815
|
+
}
|
|
17816
|
+
function debugLog2(msg) {
|
|
17817
|
+
writeLine2(`${new Date().toISOString()} pid=${process.pid} ${msg}`);
|
|
17818
|
+
}
|
|
17819
|
+
function installFileLogging() {
|
|
17820
|
+
try {
|
|
17821
|
+
process.on("uncaughtException", (err) => {
|
|
17822
|
+
debugLog2(`FATAL uncaughtException: ${err?.stack || err}`);
|
|
17823
|
+
});
|
|
17824
|
+
process.on("unhandledRejection", (reason) => {
|
|
17825
|
+
debugLog2(`FATAL unhandledRejection: ${reason instanceof Error ? reason.stack : reason}`);
|
|
17826
|
+
});
|
|
17827
|
+
process.stdin.on("end", () => debugLog2("stdin END (parent closed pipe)"));
|
|
17828
|
+
process.stdin.on("close", () => debugLog2("stdin CLOSE"));
|
|
17829
|
+
} catch {}
|
|
17830
|
+
return logPath2;
|
|
17831
|
+
}
|
|
17832
|
+
|
|
17755
17833
|
// src/sdk-server.ts
|
|
17756
17834
|
hideConsoleWindow();
|
|
17835
|
+
var logPath3 = installFileLogging();
|
|
17836
|
+
debugLog2(`START argv=${JSON.stringify(process.argv.slice(1))} cwd=${process.cwd()} bun=${process.versions?.bun || "no"} node=${process.version} log=${logPath3}`);
|
|
17757
17837
|
var service = new AgyAcpService;
|
|
17758
17838
|
var app = createDualAcpApp(service);
|
|
17759
17839
|
var stream = ndJsonStream2(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
|
|
17760
17840
|
process.stderr.write(`[agy-acp-sdk] Starting official @agentclientprotocol/sdk stdio server...
|
|
17761
17841
|
`);
|
|
17762
17842
|
await app.connect(stream);
|
|
17843
|
+
debugLog2("CONNECT-SETUP-DONE (stream established; exit 0 only happens after stdin END/CLOSE)");
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,8 +17,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
17
17
|
|
|
18
18
|
// src/core/session-core.ts
|
|
19
19
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
20
|
-
import * as
|
|
21
|
-
import
|
|
20
|
+
import * as fs9 from "node:fs";
|
|
21
|
+
import path10 from "node:path";
|
|
22
22
|
|
|
23
23
|
// node_modules/@agentclientprotocol/sdk/dist/schema/index.js
|
|
24
24
|
var AGENT_METHODS = {
|
|
@@ -11457,8 +11457,10 @@ function isAgyExecutable(bin) {
|
|
|
11457
11457
|
}
|
|
11458
11458
|
function findHeadlessLauncher() {
|
|
11459
11459
|
const moduleDir = import.meta.dir ?? path5.dirname(process.argv[1] ?? "");
|
|
11460
|
+
const execDir = path5.dirname(process.execPath ?? "");
|
|
11460
11461
|
const candidates = [
|
|
11461
11462
|
process.env.AGY_HEADLESS_LAUNCHER,
|
|
11463
|
+
execDir ? path5.join(execDir, "agy-headless.exe") : undefined,
|
|
11462
11464
|
path5.resolve(moduleDir, "..", "..", "dist", "agy-headless.exe"),
|
|
11463
11465
|
path5.resolve(moduleDir, "agy-headless.exe"),
|
|
11464
11466
|
path5.resolve(process.cwd(), "dist", "agy-headless.exe")
|
|
@@ -12273,7 +12275,7 @@ class SessionHistoryStore {
|
|
|
12273
12275
|
var AGENT_INFO = {
|
|
12274
12276
|
name: "agy-acp",
|
|
12275
12277
|
title: "agy ACP (stream-json)",
|
|
12276
|
-
version: "0.1.
|
|
12278
|
+
version: "0.1.6"
|
|
12277
12279
|
};
|
|
12278
12280
|
var BRIDGE_CAPABILITIES = {
|
|
12279
12281
|
prompt: true,
|
|
@@ -12339,6 +12341,59 @@ class AsyncSerialQueue {
|
|
|
12339
12341
|
}
|
|
12340
12342
|
}
|
|
12341
12343
|
|
|
12344
|
+
// src/lib/debug-log.ts
|
|
12345
|
+
import fs8 from "node:fs";
|
|
12346
|
+
import os4 from "node:os";
|
|
12347
|
+
import path9 from "node:path";
|
|
12348
|
+
function resolveLogPath() {
|
|
12349
|
+
const override = process.env.AGY_ACP_LOG;
|
|
12350
|
+
if (override && override !== "undefined" && override !== "null")
|
|
12351
|
+
return override;
|
|
12352
|
+
return path9.join(os4.tmpdir(), "agy-acp.log");
|
|
12353
|
+
}
|
|
12354
|
+
var logPath = null;
|
|
12355
|
+
try {
|
|
12356
|
+
logPath = resolveLogPath();
|
|
12357
|
+
} catch {
|
|
12358
|
+
logPath = null;
|
|
12359
|
+
}
|
|
12360
|
+
function writeLine(line) {
|
|
12361
|
+
if (!logPath)
|
|
12362
|
+
return;
|
|
12363
|
+
try {
|
|
12364
|
+
let truncate = false;
|
|
12365
|
+
try {
|
|
12366
|
+
const st = fs8.statSync(logPath);
|
|
12367
|
+
if (st.size > 1024 * 1024)
|
|
12368
|
+
truncate = true;
|
|
12369
|
+
} catch {}
|
|
12370
|
+
fs8.appendFileSync(logPath, line + `
|
|
12371
|
+
`, "utf8");
|
|
12372
|
+
if (truncate) {
|
|
12373
|
+
try {
|
|
12374
|
+
const text = fs8.readFileSync(logPath, "utf8");
|
|
12375
|
+
fs8.writeFileSync(logPath, text.slice(-512 * 1024), "utf8");
|
|
12376
|
+
} catch {}
|
|
12377
|
+
}
|
|
12378
|
+
} catch {}
|
|
12379
|
+
}
|
|
12380
|
+
function debugLog(msg) {
|
|
12381
|
+
writeLine(`${new Date().toISOString()} pid=${process.pid} ${msg}`);
|
|
12382
|
+
}
|
|
12383
|
+
function installFileLogging() {
|
|
12384
|
+
try {
|
|
12385
|
+
process.on("uncaughtException", (err) => {
|
|
12386
|
+
debugLog(`FATAL uncaughtException: ${err?.stack || err}`);
|
|
12387
|
+
});
|
|
12388
|
+
process.on("unhandledRejection", (reason) => {
|
|
12389
|
+
debugLog(`FATAL unhandledRejection: ${reason instanceof Error ? reason.stack : reason}`);
|
|
12390
|
+
});
|
|
12391
|
+
process.stdin.on("end", () => debugLog("stdin END (parent closed pipe)"));
|
|
12392
|
+
process.stdin.on("close", () => debugLog("stdin CLOSE"));
|
|
12393
|
+
} catch {}
|
|
12394
|
+
return logPath;
|
|
12395
|
+
}
|
|
12396
|
+
|
|
12342
12397
|
// src/core/session-core.ts
|
|
12343
12398
|
class AgySessionCore {
|
|
12344
12399
|
sessions = new Map;
|
|
@@ -12397,8 +12452,8 @@ class AgySessionCore {
|
|
|
12397
12452
|
const rawBin = process.env.AGY_BIN;
|
|
12398
12453
|
let bin = rawBin && rawBin !== "undefined" && rawBin !== "null" ? rawBin : "agy";
|
|
12399
12454
|
if (bin === "agy" || bin === "agy.exe") {
|
|
12400
|
-
const geminiBin =
|
|
12401
|
-
if (
|
|
12455
|
+
const geminiBin = path10.join(process.env.USERPROFILE || process.env.HOME || "", ".gemini", "bin", process.platform === "win32" ? "agy.exe" : "agy");
|
|
12456
|
+
if (fs9.existsSync(geminiBin)) {
|
|
12402
12457
|
bin = geminiBin;
|
|
12403
12458
|
}
|
|
12404
12459
|
}
|
|
@@ -12533,10 +12588,11 @@ class AgySessionCore {
|
|
|
12533
12588
|
}
|
|
12534
12589
|
async createSession(params, protocolVersion = 1) {
|
|
12535
12590
|
const cwd = params?.cwd;
|
|
12536
|
-
|
|
12591
|
+
debugLog(`createSession v${protocolVersion} cwd=${cwd}`);
|
|
12592
|
+
if (!cwd || typeof cwd !== "string" || !path10.isAbsolute(cwd)) {
|
|
12537
12593
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12538
12594
|
}
|
|
12539
|
-
if (!
|
|
12595
|
+
if (!fs9.existsSync(cwd) || !fs9.statSync(cwd).isDirectory()) {
|
|
12540
12596
|
throw new RequestError(-32602, `cwd does not exist or is not a directory: ${cwd}`);
|
|
12541
12597
|
}
|
|
12542
12598
|
if (params?.additionalDirectories !== undefined) {
|
|
@@ -12544,7 +12600,7 @@ class AgySessionCore {
|
|
|
12544
12600
|
throw new RequestError(-32602, "additionalDirectories must be an array");
|
|
12545
12601
|
}
|
|
12546
12602
|
for (const d of params.additionalDirectories) {
|
|
12547
|
-
if (typeof d !== "string" || !
|
|
12603
|
+
if (typeof d !== "string" || !path10.isAbsolute(d)) {
|
|
12548
12604
|
throw new RequestError(-32602, `additionalDirectory must be an absolute path: ${d}`);
|
|
12549
12605
|
}
|
|
12550
12606
|
}
|
|
@@ -12611,10 +12667,10 @@ class AgySessionCore {
|
|
|
12611
12667
|
if (!cwd || typeof cwd !== "string") {
|
|
12612
12668
|
throw new RequestError(-32602, "cwd is required for session/resume");
|
|
12613
12669
|
}
|
|
12614
|
-
if (!
|
|
12670
|
+
if (!path10.isAbsolute(cwd)) {
|
|
12615
12671
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12616
12672
|
}
|
|
12617
|
-
if (!
|
|
12673
|
+
if (!fs9.existsSync(cwd) || !fs9.statSync(cwd).isDirectory()) {
|
|
12618
12674
|
throw new RequestError(-32602, `cwd does not exist or is not a directory: ${cwd}`);
|
|
12619
12675
|
}
|
|
12620
12676
|
if (params?.replayFrom !== undefined && params?.replayFrom !== null) {
|
|
@@ -12636,7 +12692,7 @@ class AgySessionCore {
|
|
|
12636
12692
|
throw new RequestError(-32602, "additionalDirectories must be an array");
|
|
12637
12693
|
}
|
|
12638
12694
|
for (const d of params.additionalDirectories) {
|
|
12639
|
-
if (typeof d !== "string" || !
|
|
12695
|
+
if (typeof d !== "string" || !path10.isAbsolute(d)) {
|
|
12640
12696
|
throw new RequestError(-32602, `additionalDirectory must be an absolute path: ${d}`);
|
|
12641
12697
|
}
|
|
12642
12698
|
}
|
|
@@ -12652,7 +12708,7 @@ class AgySessionCore {
|
|
|
12652
12708
|
if (recordedVersion !== protocolVersion) {
|
|
12653
12709
|
throw new RequestError(-32602, `Session ${sessionId} was created with ACP v${recordedVersion} and cannot be resumed with v${protocolVersion}`);
|
|
12654
12710
|
}
|
|
12655
|
-
if (record.cwd &&
|
|
12711
|
+
if (record.cwd && path10.resolve(record.cwd) !== path10.resolve(cwd)) {
|
|
12656
12712
|
throw new RequestError(-32602, `cwd does not match session cwd: expected ${record.cwd}, got ${cwd}`);
|
|
12657
12713
|
}
|
|
12658
12714
|
const richRoots = richRootsFromSession({
|
|
@@ -12696,7 +12752,7 @@ class AgySessionCore {
|
|
|
12696
12752
|
if (session.protocolVersion !== protocolVersion) {
|
|
12697
12753
|
throw new RequestError(-32602, `Session ${sessionId} was created with ACP v${session.protocolVersion} and cannot be resumed with v${protocolVersion}`);
|
|
12698
12754
|
}
|
|
12699
|
-
if (
|
|
12755
|
+
if (path10.resolve(session.cwd) !== path10.resolve(cwd)) {
|
|
12700
12756
|
throw new RequestError(-32602, `cwd does not match session cwd: expected ${session.cwd}, got ${cwd}`);
|
|
12701
12757
|
}
|
|
12702
12758
|
session.additionalDirectories = additionalDirectories;
|
|
@@ -12764,7 +12820,7 @@ class AgySessionCore {
|
|
|
12764
12820
|
async listSessions(params) {
|
|
12765
12821
|
const filterCwd = params?.cwd;
|
|
12766
12822
|
if (filterCwd !== undefined && filterCwd !== null) {
|
|
12767
|
-
if (typeof filterCwd !== "string" || !
|
|
12823
|
+
if (typeof filterCwd !== "string" || !path10.isAbsolute(filterCwd)) {
|
|
12768
12824
|
throw new RequestError(-32602, "cwd must be an absolute path");
|
|
12769
12825
|
}
|
|
12770
12826
|
}
|
|
@@ -12991,8 +13047,8 @@ class AgySessionCore {
|
|
|
12991
13047
|
if (process.env.AGY_ACP_KEEP_STAGING !== "1" && session.stagedFiles.length) {
|
|
12992
13048
|
for (const f of session.stagedFiles) {
|
|
12993
13049
|
try {
|
|
12994
|
-
if (
|
|
12995
|
-
|
|
13050
|
+
if (fs9.existsSync(f))
|
|
13051
|
+
fs9.unlinkSync(f);
|
|
12996
13052
|
} catch {}
|
|
12997
13053
|
}
|
|
12998
13054
|
session.stagedFiles = [];
|
|
@@ -13117,18 +13173,6 @@ class AgySessionCore {
|
|
|
13117
13173
|
}
|
|
13118
13174
|
}
|
|
13119
13175
|
|
|
13120
|
-
// src/v1/types.ts
|
|
13121
|
-
var V1_AGENT_CAPABILITIES = {
|
|
13122
|
-
loadSession: true,
|
|
13123
|
-
sessionCapabilities: {
|
|
13124
|
-
list: {},
|
|
13125
|
-
resume: {},
|
|
13126
|
-
close: {},
|
|
13127
|
-
delete: {},
|
|
13128
|
-
additionalDirectories: {}
|
|
13129
|
-
}
|
|
13130
|
-
};
|
|
13131
|
-
|
|
13132
13176
|
// src/v1/config.ts
|
|
13133
13177
|
function buildV1ConfigOptions(discovery, session) {
|
|
13134
13178
|
const models = catalogChoices(discovery.availableModels, session?.model);
|
|
@@ -13166,22 +13210,16 @@ class AgyAcpV1Service {
|
|
|
13166
13210
|
this.core = core;
|
|
13167
13211
|
}
|
|
13168
13212
|
async initialize() {
|
|
13169
|
-
|
|
13170
|
-
|
|
13213
|
+
debugLog("V1 initialize called");
|
|
13214
|
+
debugLog("V1 initialize called (minimal response)");
|
|
13171
13215
|
return {
|
|
13172
13216
|
protocolVersion: 1,
|
|
13173
|
-
agentInfo: AGENT_INFO,
|
|
13174
|
-
agentCapabilities:
|
|
13175
|
-
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
13179
|
-
availableAgents: discovery.availableAgents,
|
|
13180
|
-
configOptions
|
|
13181
|
-
},
|
|
13182
|
-
availableModels: discovery.availableModels,
|
|
13183
|
-
availableAgents: discovery.availableAgents
|
|
13184
|
-
}
|
|
13217
|
+
agentInfo: { name: AGENT_INFO.name, version: AGENT_INFO.version },
|
|
13218
|
+
agentCapabilities: {
|
|
13219
|
+
loadSession: true,
|
|
13220
|
+
sessionCapabilities: { close: {}, list: {}, resume: {} }
|
|
13221
|
+
},
|
|
13222
|
+
authMethods: []
|
|
13185
13223
|
};
|
|
13186
13224
|
}
|
|
13187
13225
|
async newSession(params) {
|
|
@@ -17555,6 +17593,18 @@ __export(exports_v1, {
|
|
|
17555
17593
|
buildV1ConfigOptions: () => buildV1ConfigOptions,
|
|
17556
17594
|
createAcpV1App: () => createAcpV1App
|
|
17557
17595
|
});
|
|
17596
|
+
|
|
17597
|
+
// src/v1/types.ts
|
|
17598
|
+
var V1_AGENT_CAPABILITIES = {
|
|
17599
|
+
loadSession: true,
|
|
17600
|
+
sessionCapabilities: {
|
|
17601
|
+
list: {},
|
|
17602
|
+
resume: {},
|
|
17603
|
+
close: {},
|
|
17604
|
+
delete: {},
|
|
17605
|
+
additionalDirectories: {}
|
|
17606
|
+
}
|
|
17607
|
+
};
|
|
17558
17608
|
// src/v2/index.ts
|
|
17559
17609
|
var exports_v2 = {};
|
|
17560
17610
|
__export(exports_v2, {
|
|
@@ -17620,6 +17670,7 @@ export {
|
|
|
17620
17670
|
createAcpV2App,
|
|
17621
17671
|
createDualAcpApp,
|
|
17622
17672
|
createMapperState,
|
|
17673
|
+
debugLog,
|
|
17623
17674
|
decodeFsPath,
|
|
17624
17675
|
deleteOnCloseEnabled,
|
|
17625
17676
|
discoverAgyCatalog,
|
|
@@ -17633,6 +17684,7 @@ export {
|
|
|
17633
17684
|
getCachedDiscovery,
|
|
17634
17685
|
guessToolKind,
|
|
17635
17686
|
hideConsoleWindow,
|
|
17687
|
+
installFileLogging,
|
|
17636
17688
|
isPathAllowed,
|
|
17637
17689
|
killAgyChild,
|
|
17638
17690
|
mapAgyEvent,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yitom/agy-acp-map",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"build": "bun run build:js && bun run build:types && bun run build:headless",
|
|
29
29
|
"build:headless": "bun scripts/build-headless.ts",
|
|
30
30
|
"build:js": "bun build src/sdk-server.ts --target node --outfile dist/bin.js && bun build src/index.ts --target node --outfile dist/index.js",
|
|
31
|
+
"build:exe": "bun build src/sdk-server.ts --compile --target=bun-windows-x64 --outfile dist/agy-acp-win-x64.exe",
|
|
31
32
|
"build:types": "bunx tsc -p tsconfig.build.json",
|
|
32
33
|
"release:patch": "bun scripts/release.ts",
|
|
33
34
|
"release:publish": "bun scripts/release.ts --publish",
|