@ycodium-ai/agent-acp 0.2.2167 → 0.2.2510
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 +4 -17
- package/dist/index.js +114 -394
- package/locales/en.json +19 -0
- package/locales/zh-CN.json +19 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
# @ycodium-ai/agent-acp
|
|
2
2
|
|
|
3
3
|
Generic ACP executor plugin. The user supplies the CLI (`binaryPath` + `launchArgs`); this package
|
|
4
|
-
spawns it over stdio and runs `ycodium-acp-executor`
|
|
4
|
+
spawns it over stdio and runs the shared `ycodium-acp-executor` state machine.
|
|
5
5
|
|
|
6
6
|
- `driverKind` is `acp`, matching the existing generic ACP envelope (`driver: "acp"` plus
|
|
7
7
|
`config.binaryPath` / `config.launchArgs`). Disk format is unchanged.
|
|
8
8
|
- `createInstance` reads that envelope (or a bare settings object) and `startSession` spawns via
|
|
9
9
|
lease-scoped `host.process.spawn`.
|
|
10
10
|
- Manifest permission is `{ kind: "executor" }`.
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
`session/request_permission` and must stay structured user input, and its context usage is read
|
|
14
|
-
from the CLI's own session log. The instance is recognised by `config.providerId === "kimiCode"`
|
|
15
|
-
or `homeEnvVar === "KIMI_CODE_HOME"` — both are prefilled by the provider table and hidden from
|
|
16
|
-
the form, so they beat the user-editable program path.
|
|
17
|
-
|
|
18
|
-
One card, six grid cells: the five ACP vendor rows in the provider table
|
|
19
|
-
(`kimiCode` / `githubCopilot` / `geminiCli` / `qwenCode` / `hermesAgent`) plus the user-filled
|
|
20
|
-
"Other agent (ACP)" all create `driver: "acp"` instances and are served by this package.
|
|
11
|
+
- There are no vendor presets. A CLI that needs its own behaviour (sign-in, model listing, session
|
|
12
|
+
logs) gets its own executor plugin built on the same shared ACP machinery, as `agent-kimi` does.
|
|
21
13
|
|
|
22
14
|
Shipped pre-installed as `core.agent-acp`; the host's built-in `acp` driver was deleted on
|
|
23
|
-
2026-09-18
|
|
24
|
-
|
|
25
|
-
Golden replay (`src/replay.test.ts`) runs the real bytes recorded from `kimi acp` 2.0.1 through
|
|
26
|
-
`test/wireReplayPeer.mjs`. Re-record with
|
|
27
|
-
`apps/server/scripts/record-acp-session.ts`; provenance and what is **not** capturable on this
|
|
28
|
-
machine are in `docs/internals/provider-recordings.md`.
|
|
15
|
+
2026-09-18.
|
|
29
16
|
|
|
30
17
|
Develop with `vp run --filter @ycodium-ai/agent-acp typecheck`, `build`, and `test`.
|
|
31
18
|
|
package/dist/index.js
CHANGED
|
@@ -9,12 +9,8 @@ import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
|
9
9
|
|
|
10
10
|
// src/acpInstance.ts
|
|
11
11
|
import * as NodeOS2 from "node:os";
|
|
12
|
-
import * as
|
|
13
|
-
import {
|
|
14
|
-
mergeLaunchEnv,
|
|
15
|
-
modelSelectionStringOption,
|
|
16
|
-
brainSlotEnvKeys
|
|
17
|
-
} from "@ycodium-ai/plugin-api/executor";
|
|
12
|
+
import * as NodePath2 from "node:path";
|
|
13
|
+
import { mergeLaunchEnv, modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
|
|
18
14
|
import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
|
|
19
15
|
|
|
20
16
|
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
@@ -23405,10 +23401,44 @@ var legacyClientNotificationMethods = /* @__PURE__ */ new Set([
|
|
|
23405
23401
|
CLIENT_METHODS.elicitation_complete
|
|
23406
23402
|
]);
|
|
23407
23403
|
|
|
23408
|
-
// ../../packages/ycodium-acp-
|
|
23404
|
+
// ../../packages/ycodium-acp-executor/src/connection.ts
|
|
23409
23405
|
import * as NodeStream from "node:stream";
|
|
23410
23406
|
|
|
23411
|
-
// ../../packages/ycodium-acp-
|
|
23407
|
+
// ../../packages/ycodium-acp-executor/src/errors.ts
|
|
23408
|
+
var AcpExecutorError = class extends Error {
|
|
23409
|
+
code;
|
|
23410
|
+
constructor(code, message) {
|
|
23411
|
+
super(message);
|
|
23412
|
+
this.name = "AcpExecutorError";
|
|
23413
|
+
this.code = code;
|
|
23414
|
+
}
|
|
23415
|
+
};
|
|
23416
|
+
var AcpExecutorDisposedError = class extends AcpExecutorError {
|
|
23417
|
+
constructor(message = "ACP executor has been disposed") {
|
|
23418
|
+
super("disposed", message);
|
|
23419
|
+
this.name = "AcpExecutorDisposedError";
|
|
23420
|
+
}
|
|
23421
|
+
};
|
|
23422
|
+
var AcpExecutorNotStartedError = class extends AcpExecutorError {
|
|
23423
|
+
constructor(message = "ACP session has not been started") {
|
|
23424
|
+
super("not-started", message);
|
|
23425
|
+
this.name = "AcpExecutorNotStartedError";
|
|
23426
|
+
}
|
|
23427
|
+
};
|
|
23428
|
+
var AcpExecutorCancelTimeoutError = class extends AcpExecutorError {
|
|
23429
|
+
constructor(message = "Timed out waiting for session/prompt to finish after cancellation") {
|
|
23430
|
+
super("cancel-timeout", message);
|
|
23431
|
+
this.name = "AcpExecutorCancelTimeoutError";
|
|
23432
|
+
}
|
|
23433
|
+
};
|
|
23434
|
+
var AcpExecutorRequestError = class extends AcpExecutorError {
|
|
23435
|
+
method;
|
|
23436
|
+
constructor(method, message) {
|
|
23437
|
+
super("request-failed", message);
|
|
23438
|
+
this.name = "AcpExecutorRequestError";
|
|
23439
|
+
this.method = method;
|
|
23440
|
+
}
|
|
23441
|
+
};
|
|
23412
23442
|
var AcpConnectionClosedError = class extends Error {
|
|
23413
23443
|
constructor(message = "ACP connection closed") {
|
|
23414
23444
|
super(message);
|
|
@@ -23416,7 +23446,7 @@ var AcpConnectionClosedError = class extends Error {
|
|
|
23416
23446
|
}
|
|
23417
23447
|
};
|
|
23418
23448
|
|
|
23419
|
-
// ../../packages/ycodium-acp-
|
|
23449
|
+
// ../../packages/ycodium-acp-executor/src/jsonrpc.ts
|
|
23420
23450
|
function isRecord2(value) {
|
|
23421
23451
|
return typeof value === "object" && value !== null;
|
|
23422
23452
|
}
|
|
@@ -23454,7 +23484,7 @@ function readJsonRpcError(value) {
|
|
|
23454
23484
|
};
|
|
23455
23485
|
}
|
|
23456
23486
|
|
|
23457
|
-
// ../../packages/ycodium-acp-
|
|
23487
|
+
// ../../packages/ycodium-acp-executor/src/line-buffer.ts
|
|
23458
23488
|
var newline2 = 10;
|
|
23459
23489
|
var LineBuffer2 = class {
|
|
23460
23490
|
#pending = [];
|
|
@@ -23498,7 +23528,7 @@ var LineBuffer2 = class {
|
|
|
23498
23528
|
}
|
|
23499
23529
|
};
|
|
23500
23530
|
|
|
23501
|
-
// ../../packages/ycodium-acp-
|
|
23531
|
+
// ../../packages/ycodium-acp-executor/src/session-update.ts
|
|
23502
23532
|
var KNOWN_SESSION_UPDATES = /* @__PURE__ */ new Set([
|
|
23503
23533
|
"user_message_chunk",
|
|
23504
23534
|
"agent_message_chunk",
|
|
@@ -23543,7 +23573,7 @@ function decodeSessionUpdate(payload) {
|
|
|
23543
23573
|
return { status: "raw", params: payload };
|
|
23544
23574
|
}
|
|
23545
23575
|
|
|
23546
|
-
// ../../packages/ycodium-acp-
|
|
23576
|
+
// ../../packages/ycodium-acp-executor/src/connection.ts
|
|
23547
23577
|
var textDecoder = new TextDecoder();
|
|
23548
23578
|
var textEncoder = new TextEncoder();
|
|
23549
23579
|
function asBytes(chunk) {
|
|
@@ -24068,42 +24098,6 @@ var UnboundedEventStream = class {
|
|
|
24068
24098
|
}
|
|
24069
24099
|
};
|
|
24070
24100
|
|
|
24071
|
-
// ../../packages/ycodium-acp-executor/src/errors.ts
|
|
24072
|
-
var AcpExecutorError = class extends Error {
|
|
24073
|
-
code;
|
|
24074
|
-
constructor(code, message) {
|
|
24075
|
-
super(message);
|
|
24076
|
-
this.name = "AcpExecutorError";
|
|
24077
|
-
this.code = code;
|
|
24078
|
-
}
|
|
24079
|
-
};
|
|
24080
|
-
var AcpExecutorDisposedError = class extends AcpExecutorError {
|
|
24081
|
-
constructor(message = "ACP executor has been disposed") {
|
|
24082
|
-
super("disposed", message);
|
|
24083
|
-
this.name = "AcpExecutorDisposedError";
|
|
24084
|
-
}
|
|
24085
|
-
};
|
|
24086
|
-
var AcpExecutorNotStartedError = class extends AcpExecutorError {
|
|
24087
|
-
constructor(message = "ACP session has not been started") {
|
|
24088
|
-
super("not-started", message);
|
|
24089
|
-
this.name = "AcpExecutorNotStartedError";
|
|
24090
|
-
}
|
|
24091
|
-
};
|
|
24092
|
-
var AcpExecutorCancelTimeoutError = class extends AcpExecutorError {
|
|
24093
|
-
constructor(message = "Timed out waiting for session/prompt to finish after cancellation") {
|
|
24094
|
-
super("cancel-timeout", message);
|
|
24095
|
-
this.name = "AcpExecutorCancelTimeoutError";
|
|
24096
|
-
}
|
|
24097
|
-
};
|
|
24098
|
-
var AcpExecutorRequestError = class extends AcpExecutorError {
|
|
24099
|
-
method;
|
|
24100
|
-
constructor(method, message) {
|
|
24101
|
-
super("request-failed", message);
|
|
24102
|
-
this.name = "AcpExecutorRequestError";
|
|
24103
|
-
this.method = method;
|
|
24104
|
-
}
|
|
24105
|
-
};
|
|
24106
|
-
|
|
24107
24101
|
// ../../packages/ycodium-acp-executor/src/events.ts
|
|
24108
24102
|
function canonicalRequestTypeFromAcpKind(kind) {
|
|
24109
24103
|
switch (kind) {
|
|
@@ -26399,57 +26393,7 @@ function acpAgentVersion(initializeResult) {
|
|
|
26399
26393
|
const agentInfo = initializeResult["agentInfo"];
|
|
26400
26394
|
return isRecord5(agentInfo) ? asTrimmedString(agentInfo["version"]) ?? null : null;
|
|
26401
26395
|
}
|
|
26402
|
-
var CLI_VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
|
|
26403
|
-
function parseCliVersion(output2) {
|
|
26404
|
-
return CLI_VERSION_PATTERN.exec(output2)?.[1] ?? null;
|
|
26405
|
-
}
|
|
26406
|
-
async function collectCappedText(stream, maxBytes) {
|
|
26407
|
-
const decoder = new TextDecoder();
|
|
26408
|
-
let text = "";
|
|
26409
|
-
let total = 0;
|
|
26410
|
-
for await (const chunk of stream) {
|
|
26411
|
-
total += chunk.byteLength;
|
|
26412
|
-
if (total <= maxBytes) text += decoder.decode(chunk, { stream: true });
|
|
26413
|
-
}
|
|
26414
|
-
return { text: text + decoder.decode(), overflowed: total > maxBytes };
|
|
26415
|
-
}
|
|
26416
|
-
async function collectProbeProcess(child, input2) {
|
|
26417
|
-
try {
|
|
26418
|
-
await child.closeStdin().catch(() => void 0);
|
|
26419
|
-
const [stdout, stderr, exitCode] = await withProbeTimeout(
|
|
26420
|
-
Promise.all([
|
|
26421
|
-
collectCappedText(child.stdout, input2.maxOutputBytes),
|
|
26422
|
-
collectCappedText(child.stderr, input2.maxOutputBytes),
|
|
26423
|
-
child.exited
|
|
26424
|
-
]),
|
|
26425
|
-
input2.timeoutMs,
|
|
26426
|
-
input2.what
|
|
26427
|
-
);
|
|
26428
|
-
return { stdout: stdout.overflowed ? void 0 : stdout.text, stderr: stderr.text, exitCode };
|
|
26429
|
-
} finally {
|
|
26430
|
-
await child.kill("SIGTERM").catch(() => void 0);
|
|
26431
|
-
}
|
|
26432
|
-
}
|
|
26433
26396
|
var MAX_VERSION_OUTPUT_BYTES = 64 * 1024;
|
|
26434
|
-
async function probeCliVersion(input2) {
|
|
26435
|
-
let child;
|
|
26436
|
-
try {
|
|
26437
|
-
child = await input2.spawn();
|
|
26438
|
-
} catch {
|
|
26439
|
-
return null;
|
|
26440
|
-
}
|
|
26441
|
-
try {
|
|
26442
|
-
const run = await collectProbeProcess(child, {
|
|
26443
|
-
timeoutMs: input2.timeoutMs,
|
|
26444
|
-
maxOutputBytes: MAX_VERSION_OUTPUT_BYTES,
|
|
26445
|
-
what: "--version"
|
|
26446
|
-
});
|
|
26447
|
-
if (run.exitCode !== 0) return null;
|
|
26448
|
-
return parseCliVersion(run.stdout ?? "") ?? parseCliVersion(run.stderr);
|
|
26449
|
-
} catch {
|
|
26450
|
-
return null;
|
|
26451
|
-
}
|
|
26452
|
-
}
|
|
26453
26397
|
|
|
26454
26398
|
// src/card.ts
|
|
26455
26399
|
var ACP_DRIVER_KIND = "acp";
|
|
@@ -26473,9 +26417,6 @@ var ACP_CARD = {
|
|
|
26473
26417
|
defaultTextGenerationModel: "",
|
|
26474
26418
|
customModelIdExample: "",
|
|
26475
26419
|
modelSlugAliases: null,
|
|
26476
|
-
modelsDevProviderIds: [],
|
|
26477
|
-
modelsDevSlugPrefixed: false,
|
|
26478
|
-
modelSlugPrefix: "",
|
|
26479
26420
|
mcpTransports: ["stdio", "http", "sse"],
|
|
26480
26421
|
pluginManaged: true,
|
|
26481
26422
|
verifiedSkills: false,
|
|
@@ -26500,15 +26441,38 @@ var ACP_CARD = {
|
|
|
26500
26441
|
},
|
|
26501
26442
|
credentialSources: [],
|
|
26502
26443
|
diagnostics: [],
|
|
26444
|
+
// 设置表单照这份画:带 x-ycodium-form 的属性才进表单(enabled、customModels 等另有入口,不在此列),
|
|
26445
|
+
// 顺序看 x-ycodium-form-order;文案键在本插件 locales/<locale>.json 里解析,宿主不兜底。
|
|
26503
26446
|
configSchema: {
|
|
26504
26447
|
type: "object",
|
|
26448
|
+
"x-ycodium-form-order": ["binaryPath", "launchArgs", "homePath"],
|
|
26505
26449
|
properties: {
|
|
26506
|
-
binaryPath: {
|
|
26507
|
-
|
|
26508
|
-
|
|
26450
|
+
binaryPath: {
|
|
26451
|
+
type: "string",
|
|
26452
|
+
"x-ycodium-form": {
|
|
26453
|
+
titleKey: "form.binaryPath.title",
|
|
26454
|
+
descriptionKey: "form.binaryPath.description",
|
|
26455
|
+
placeholderKey: "form.binaryPath.placeholder",
|
|
26456
|
+
control: "executable-path"
|
|
26457
|
+
}
|
|
26458
|
+
},
|
|
26459
|
+
launchArgs: {
|
|
26460
|
+
type: "string",
|
|
26461
|
+
"x-ycodium-form": {
|
|
26462
|
+
titleKey: "form.launchArgs.title",
|
|
26463
|
+
descriptionKey: "form.launchArgs.description",
|
|
26464
|
+
placeholderKey: "form.launchArgs.placeholder"
|
|
26465
|
+
}
|
|
26466
|
+
},
|
|
26467
|
+
homePath: {
|
|
26468
|
+
type: "string",
|
|
26469
|
+
"x-ycodium-form": {
|
|
26470
|
+
titleKey: "form.homePath.title",
|
|
26471
|
+
descriptionKey: "form.homePath.description",
|
|
26472
|
+
placeholderKey: "form.homePath.placeholder"
|
|
26473
|
+
}
|
|
26474
|
+
},
|
|
26509
26475
|
homeEnvVar: { type: "string" },
|
|
26510
|
-
providerId: { type: "string" },
|
|
26511
|
-
packageName: { type: "string" },
|
|
26512
26476
|
enabled: { type: "boolean" },
|
|
26513
26477
|
customModels: { type: "array" },
|
|
26514
26478
|
driver: { type: "string" },
|
|
@@ -26519,14 +26483,10 @@ var ACP_CARD = {
|
|
|
26519
26483
|
},
|
|
26520
26484
|
modelConnectivity: {
|
|
26521
26485
|
dialects: ["anthropic-messages", "openai-responses", "openai-chat-completions"],
|
|
26522
|
-
// **通用 ACP
|
|
26523
|
-
//
|
|
26524
|
-
//
|
|
26525
|
-
//
|
|
26526
|
-
//
|
|
26527
|
-
// 原来这里写着 `true` 却一栏开关都不给——名片对外宣称能接,实际绑定时报一个含糊
|
|
26528
|
-
// 的 `driver-unknown`,而提案 0025 的进度表据此把 kimi 记成「通」。哪家要接,就为
|
|
26529
|
-
// 那一家单出一张名片(`resolveByLocator` 按启动命令认家),别回来改这一张。
|
|
26486
|
+
// **通用 ACP 这张名片说不出怎么接外部地址,而且说不出是对的。** ACP 协议本身没有
|
|
26487
|
+
// 端点概念,地址与钥匙全靠各家 CLI 自己的环境变量,各家各不相同。用户按那家 CLI
|
|
26488
|
+
// 自己的文档在实例上设变量。哪家要写清楚,就为那一家单出一个插件(像 `agent-kimi`),
|
|
26489
|
+
// 别回来改这一张。
|
|
26530
26490
|
acceptsExternalEndpoints: false
|
|
26531
26491
|
}
|
|
26532
26492
|
};
|
|
@@ -26560,8 +26520,7 @@ function parseAcpInstanceConfig(config2) {
|
|
|
26560
26520
|
homePath: "",
|
|
26561
26521
|
homeEnvVar: "",
|
|
26562
26522
|
environment: {},
|
|
26563
|
-
envelopeDriver: void 0
|
|
26564
|
-
providerId: ""
|
|
26523
|
+
envelopeDriver: void 0
|
|
26565
26524
|
};
|
|
26566
26525
|
}
|
|
26567
26526
|
const nested = isRecord6(config2["config"]) ? config2["config"] : void 0;
|
|
@@ -26572,8 +26531,7 @@ function parseAcpInstanceConfig(config2) {
|
|
|
26572
26531
|
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config2["homePath"]),
|
|
26573
26532
|
homeEnvVar: readTrimmed(settings["homeEnvVar"]) || readTrimmed(config2["homeEnvVar"]),
|
|
26574
26533
|
environment: readEnvironment(config2["environment"]),
|
|
26575
|
-
envelopeDriver: readTrimmed(config2["driver"]) || void 0
|
|
26576
|
-
providerId: readTrimmed(settings["providerId"]) || readTrimmed(config2["providerId"])
|
|
26534
|
+
envelopeDriver: readTrimmed(config2["driver"]) || void 0
|
|
26577
26535
|
};
|
|
26578
26536
|
}
|
|
26579
26537
|
function tokenizeLaunchArgs(value) {
|
|
@@ -26628,136 +26586,30 @@ function tokenizeLaunchArgs(value) {
|
|
|
26628
26586
|
return tokens;
|
|
26629
26587
|
}
|
|
26630
26588
|
|
|
26631
|
-
// src/
|
|
26632
|
-
|
|
26633
|
-
|
|
26634
|
-
|
|
26635
|
-
|
|
26636
|
-
|
|
26637
|
-
|
|
26638
|
-
|
|
26639
|
-
|
|
26640
|
-
|
|
26641
|
-
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
|
|
26645
|
-
|
|
26646
|
-
|
|
26647
|
-
}
|
|
26648
|
-
return parts.join("\n\n").trim();
|
|
26649
|
-
}
|
|
26650
|
-
function kimiPermissionUserInput(request) {
|
|
26651
|
-
const title = request.toolCall.title;
|
|
26652
|
-
if (typeof title !== "string" || !KIMI_USER_INPUT_TITLES.has(title)) return void 0;
|
|
26653
|
-
const ids = new Set(request.options.map((option) => option.optionId));
|
|
26654
|
-
if (request.options.length === 0 || ids.size !== request.options.length) {
|
|
26655
|
-
throw new Error("Kimi interaction must provide distinct response options.");
|
|
26656
|
-
}
|
|
26657
|
-
const question = questionTextFromContent(request.toolCall.content);
|
|
26658
|
-
if (question.length === 0) {
|
|
26659
|
-
throw new Error("Kimi interaction is missing a question or plan.");
|
|
26660
|
-
}
|
|
26661
|
-
return {
|
|
26662
|
-
id: request.toolCall.toolCallId,
|
|
26663
|
-
header: title,
|
|
26664
|
-
question,
|
|
26665
|
-
kind: title === "ExitPlanMode" ? "plan" : "question",
|
|
26666
|
-
allowFreeform: false,
|
|
26667
|
-
multiSelect: false,
|
|
26668
|
-
options: request.options.map((option) => ({
|
|
26669
|
-
id: option.optionId,
|
|
26670
|
-
label: option.name,
|
|
26671
|
-
description: ""
|
|
26672
|
-
}))
|
|
26673
|
-
};
|
|
26674
|
-
}
|
|
26675
|
-
var WIRE_LOG_SEGMENTS = ["agents", "main", "wire.jsonl"];
|
|
26676
|
-
var SESSIONS_DIR = "sessions";
|
|
26677
|
-
var TAIL_SCAN_BYTES = 256 * 1024;
|
|
26678
|
-
var positiveInt = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
26679
|
-
function parseKimiContextWindow(contents) {
|
|
26680
|
-
let usedTokens;
|
|
26681
|
-
let maxTokens;
|
|
26682
|
-
for (const line of contents.split("\n")) {
|
|
26683
|
-
const trimmed = line.trim();
|
|
26684
|
-
if (trimmed.length === 0) continue;
|
|
26685
|
-
let record2;
|
|
26686
|
-
try {
|
|
26687
|
-
record2 = JSON.parse(trimmed);
|
|
26688
|
-
} catch {
|
|
26689
|
-
continue;
|
|
26690
|
-
}
|
|
26691
|
-
if (!isRecord7(record2)) continue;
|
|
26692
|
-
const type = record2["type"];
|
|
26693
|
-
if (type === "token_counting.turn_recorded" || type === "token_counting.measured") {
|
|
26694
|
-
usedTokens = positiveInt(record2["tokens"]) ?? usedTokens;
|
|
26695
|
-
continue;
|
|
26696
|
-
}
|
|
26697
|
-
if (type === "llm.request") {
|
|
26698
|
-
maxTokens = positiveInt(record2["maxTokens"]) ?? maxTokens;
|
|
26699
|
-
}
|
|
26700
|
-
}
|
|
26701
|
-
if (usedTokens === void 0) return void 0;
|
|
26702
|
-
return maxTokens === void 0 ? { usedTokens } : { usedTokens, maxTokens };
|
|
26703
|
-
}
|
|
26704
|
-
function readTail(filePath) {
|
|
26705
|
-
let handle;
|
|
26706
|
-
try {
|
|
26707
|
-
const size = NodeFS.statSync(filePath).size;
|
|
26708
|
-
if (!Number.isFinite(size) || size <= 0) return void 0;
|
|
26709
|
-
const length = size > TAIL_SCAN_BYTES ? TAIL_SCAN_BYTES : size;
|
|
26710
|
-
const buffer = Buffer.alloc(length);
|
|
26711
|
-
handle = NodeFS.openSync(filePath, "r");
|
|
26712
|
-
NodeFS.readSync(handle, buffer, 0, length, size - length);
|
|
26713
|
-
return buffer.toString("utf8");
|
|
26714
|
-
} catch {
|
|
26715
|
-
return void 0;
|
|
26716
|
-
} finally {
|
|
26717
|
-
if (handle !== void 0) {
|
|
26718
|
-
try {
|
|
26719
|
-
NodeFS.closeSync(handle);
|
|
26720
|
-
} catch {
|
|
26721
|
-
}
|
|
26589
|
+
// src/mcpServers.ts
|
|
26590
|
+
function toAcpMcpServers(entries) {
|
|
26591
|
+
return (entries ?? []).map(
|
|
26592
|
+
(entry) => entry.transport.type === "stdio" ? {
|
|
26593
|
+
name: entry.name,
|
|
26594
|
+
command: entry.transport.command,
|
|
26595
|
+
args: [...entry.transport.args ?? []],
|
|
26596
|
+
env: Object.entries(entry.transport.env ?? {}).map(([name, value]) => ({ name, value }))
|
|
26597
|
+
} : {
|
|
26598
|
+
type: entry.transport.type,
|
|
26599
|
+
name: entry.name,
|
|
26600
|
+
url: entry.transport.url,
|
|
26601
|
+
headers: Object.entries(entry.transport.headers ?? {}).map(([name, value]) => ({
|
|
26602
|
+
name,
|
|
26603
|
+
value
|
|
26604
|
+
}))
|
|
26722
26605
|
}
|
|
26723
|
-
|
|
26724
|
-
}
|
|
26725
|
-
function findKimiSessionWireLog(input2) {
|
|
26726
|
-
const sessionsRoot = NodePath.join(input2.homePath, SESSIONS_DIR);
|
|
26727
|
-
let workspaces;
|
|
26728
|
-
try {
|
|
26729
|
-
workspaces = NodeFS.readdirSync(sessionsRoot);
|
|
26730
|
-
} catch {
|
|
26731
|
-
return void 0;
|
|
26732
|
-
}
|
|
26733
|
-
for (const workspace of workspaces) {
|
|
26734
|
-
const candidate = NodePath.join(
|
|
26735
|
-
sessionsRoot,
|
|
26736
|
-
workspace,
|
|
26737
|
-
input2.acpSessionId,
|
|
26738
|
-
...WIRE_LOG_SEGMENTS
|
|
26739
|
-
);
|
|
26740
|
-
if (NodeFS.existsSync(candidate)) return candidate;
|
|
26741
|
-
}
|
|
26742
|
-
return void 0;
|
|
26743
|
-
}
|
|
26744
|
-
function readKimiContextWindow(input2) {
|
|
26745
|
-
if (input2.homePath.trim().length === 0) return void 0;
|
|
26746
|
-
const wireLog = findKimiSessionWireLog(input2);
|
|
26747
|
-
if (wireLog === void 0) return void 0;
|
|
26748
|
-
const contents = readTail(wireLog);
|
|
26749
|
-
return contents === void 0 ? void 0 : parseKimiContextWindow(contents);
|
|
26606
|
+
);
|
|
26750
26607
|
}
|
|
26751
26608
|
|
|
26752
|
-
// src/kimiModels.ts
|
|
26753
|
-
import {
|
|
26754
|
-
ExecutorSpawnRefusedError as ExecutorSpawnRefusedError2
|
|
26755
|
-
} from "@ycodium-ai/plugin-api/executor";
|
|
26756
|
-
|
|
26757
26609
|
// src/probeModels.ts
|
|
26758
|
-
import * as
|
|
26610
|
+
import * as NodeFS from "node:fs";
|
|
26759
26611
|
import * as NodeOS from "node:os";
|
|
26760
|
-
import * as
|
|
26612
|
+
import * as NodePath from "node:path";
|
|
26761
26613
|
import {
|
|
26762
26614
|
ExecutorSpawnRefusedError
|
|
26763
26615
|
} from "@ycodium-ai/plugin-api/executor";
|
|
@@ -26767,18 +26619,18 @@ var CLIENT_INFO = { name: "ycodium-agent-acp-probe", version: "0.2.0" };
|
|
|
26767
26619
|
var ACP_EFFORT_OPTION_ID = "reasoning";
|
|
26768
26620
|
function acpProbeSessionCwd(instanceId) {
|
|
26769
26621
|
const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
26770
|
-
return
|
|
26622
|
+
return NodePath.join(NodeOS.tmpdir(), `ycodium-acp-probe-${safe}`);
|
|
26771
26623
|
}
|
|
26772
|
-
function
|
|
26624
|
+
function isRecord7(value) {
|
|
26773
26625
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26774
26626
|
}
|
|
26775
26627
|
function asString3(value) {
|
|
26776
26628
|
return typeof value === "string" ? value : void 0;
|
|
26777
26629
|
}
|
|
26778
26630
|
function findAcpProbeSessionId(listed, probeCwd) {
|
|
26779
|
-
if (!
|
|
26631
|
+
if (!isRecord7(listed) || !Array.isArray(listed["sessions"])) return void 0;
|
|
26780
26632
|
for (const entry of listed["sessions"]) {
|
|
26781
|
-
if (!
|
|
26633
|
+
if (!isRecord7(entry)) continue;
|
|
26782
26634
|
if (asString3(entry["cwd"]) !== probeCwd) continue;
|
|
26783
26635
|
const sessionId = asString3(entry["sessionId"]);
|
|
26784
26636
|
if (sessionId !== void 0) return sessionId;
|
|
@@ -26795,7 +26647,7 @@ async function probeSessionSetup(handshake, probeCwd) {
|
|
|
26795
26647
|
return handshake.request("session/new", { cwd: probeCwd, mcpServers: [] });
|
|
26796
26648
|
}
|
|
26797
26649
|
function acpProbeModels(setup) {
|
|
26798
|
-
if (!
|
|
26650
|
+
if (!isRecord7(setup)) return void 0;
|
|
26799
26651
|
const rawOptions = setup["configOptions"];
|
|
26800
26652
|
const choices = acpModelChoicesFromConfigOptions(rawOptions) ?? acpModelChoicesFromSessionModels(setup["models"]);
|
|
26801
26653
|
if (choices === void 0 || choices.length === 0) return void 0;
|
|
@@ -26830,7 +26682,7 @@ async function probeAcpModelsViaSession(input2) {
|
|
|
26830
26682
|
const { recipe, host, env } = input2;
|
|
26831
26683
|
const probeCwd = acpProbeSessionCwd(host.instanceId);
|
|
26832
26684
|
try {
|
|
26833
|
-
|
|
26685
|
+
NodeFS.mkdirSync(probeCwd, { recursive: true });
|
|
26834
26686
|
} catch (error62) {
|
|
26835
26687
|
return { kind: "failed", detail: probeFailureDetail(error62), version: null };
|
|
26836
26688
|
}
|
|
@@ -26882,113 +26734,6 @@ async function probeAcpModelsViaSession(input2) {
|
|
|
26882
26734
|
}
|
|
26883
26735
|
}
|
|
26884
26736
|
|
|
26885
|
-
// src/kimiModels.ts
|
|
26886
|
-
var PROBE_TIMEOUT_MS = 15e3;
|
|
26887
|
-
var MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
26888
|
-
var KIMI_MODEL_LIST_ARGS = ["provider", "list", "--json"];
|
|
26889
|
-
function isRecord9(value) {
|
|
26890
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26891
|
-
}
|
|
26892
|
-
function asString4(value) {
|
|
26893
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
26894
|
-
}
|
|
26895
|
-
function positiveInt2(value) {
|
|
26896
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
26897
|
-
}
|
|
26898
|
-
function kimiProbeModels(stdout) {
|
|
26899
|
-
let parsed;
|
|
26900
|
-
try {
|
|
26901
|
-
parsed = JSON.parse(stdout);
|
|
26902
|
-
} catch {
|
|
26903
|
-
return void 0;
|
|
26904
|
-
}
|
|
26905
|
-
if (!isRecord9(parsed)) return void 0;
|
|
26906
|
-
const models = parsed["models"];
|
|
26907
|
-
if (!isRecord9(models)) return void 0;
|
|
26908
|
-
const out = [];
|
|
26909
|
-
for (const [slug, entry] of Object.entries(models)) {
|
|
26910
|
-
const trimmed = slug.trim();
|
|
26911
|
-
if (trimmed.length === 0 || !isRecord9(entry)) continue;
|
|
26912
|
-
const name = asString4(entry["displayName"]);
|
|
26913
|
-
const contextWindow = positiveInt2(entry["maxContextSize"]);
|
|
26914
|
-
out.push({
|
|
26915
|
-
slug: trimmed,
|
|
26916
|
-
...name === void 0 ? {} : { name },
|
|
26917
|
-
...contextWindow === void 0 ? {} : { contextWindow }
|
|
26918
|
-
});
|
|
26919
|
-
}
|
|
26920
|
-
return out;
|
|
26921
|
-
}
|
|
26922
|
-
async function probeKimiModels(input2) {
|
|
26923
|
-
const { recipe, host, env } = input2;
|
|
26924
|
-
let handle;
|
|
26925
|
-
try {
|
|
26926
|
-
handle = await host.process.spawn({
|
|
26927
|
-
program: recipe.binaryPath,
|
|
26928
|
-
// 实例信封里的启动参数(Kimi 那行预填 `acp`)在这一栏用不上:读配置要换成
|
|
26929
|
-
// `provider list --json`,留着 `acp` 就等于让它起 ACP 服务然后什么都不问。
|
|
26930
|
-
args: KIMI_MODEL_LIST_ARGS,
|
|
26931
|
-
cwd: process.cwd(),
|
|
26932
|
-
owner: { bindingId: host.bindingId },
|
|
26933
|
-
...Object.keys(env).length > 0 ? { env } : {}
|
|
26934
|
-
});
|
|
26935
|
-
} catch (error62) {
|
|
26936
|
-
if (error62 instanceof ExecutorSpawnRefusedError2) throw error62;
|
|
26937
|
-
return { kind: "not-started", detail: probeFailureDetail(error62) };
|
|
26938
|
-
}
|
|
26939
|
-
try {
|
|
26940
|
-
const run = await collectProbeProcess(handle, {
|
|
26941
|
-
timeoutMs: input2.timeoutMs ?? PROBE_TIMEOUT_MS,
|
|
26942
|
-
// 这份 JSON 实测 1.7KB;封顶是防 CLI 抽风刷日志把内存吃掉。
|
|
26943
|
-
maxOutputBytes: MAX_OUTPUT_BYTES,
|
|
26944
|
-
what: "kimi provider list"
|
|
26945
|
-
});
|
|
26946
|
-
if (run.exitCode !== 0) {
|
|
26947
|
-
const stderr = run.stderr.trim();
|
|
26948
|
-
return {
|
|
26949
|
-
kind: "failed",
|
|
26950
|
-
detail: stderr.length > 0 ? stderr : run.exitCode === null ? "kimi provider list was killed by a signal" : `kimi provider list exited with code ${run.exitCode}`
|
|
26951
|
-
};
|
|
26952
|
-
}
|
|
26953
|
-
return {
|
|
26954
|
-
kind: "answered",
|
|
26955
|
-
models: run.stdout === void 0 ? void 0 : kimiProbeModels(run.stdout)
|
|
26956
|
-
};
|
|
26957
|
-
} catch (error62) {
|
|
26958
|
-
return { kind: "failed", detail: probeFailureDetail(error62) };
|
|
26959
|
-
}
|
|
26960
|
-
}
|
|
26961
|
-
async function probeKimiVersion(input2) {
|
|
26962
|
-
const { recipe, host, env } = input2;
|
|
26963
|
-
return probeCliVersion({
|
|
26964
|
-
spawn: () => host.process.spawn({
|
|
26965
|
-
program: recipe.binaryPath,
|
|
26966
|
-
args: ["--version"],
|
|
26967
|
-
cwd: process.cwd(),
|
|
26968
|
-
owner: { bindingId: host.bindingId },
|
|
26969
|
-
...Object.keys(env).length > 0 ? { env } : {}
|
|
26970
|
-
}),
|
|
26971
|
-
timeoutMs: PROBE_TIMEOUT_MS
|
|
26972
|
-
});
|
|
26973
|
-
}
|
|
26974
|
-
async function probeKimi(input2) {
|
|
26975
|
-
const [listed, version2] = await Promise.all([probeKimiModels(input2), probeKimiVersion(input2)]);
|
|
26976
|
-
switch (listed.kind) {
|
|
26977
|
-
case "not-started":
|
|
26978
|
-
return { kind: "not-started", detail: listed.detail };
|
|
26979
|
-
case "failed":
|
|
26980
|
-
return { kind: "failed", detail: listed.detail, version: version2 };
|
|
26981
|
-
case "answered":
|
|
26982
|
-
return {
|
|
26983
|
-
kind: "answered",
|
|
26984
|
-
version: version2,
|
|
26985
|
-
models: listed.models,
|
|
26986
|
-
nativeModes: [],
|
|
26987
|
-
currentNativeModeId: void 0
|
|
26988
|
-
};
|
|
26989
|
-
}
|
|
26990
|
-
}
|
|
26991
|
-
|
|
26992
26737
|
// src/runtimeModeApproval.ts
|
|
26993
26738
|
function acpRuntimeModeAutoApproves(runtimeMode, toolKind) {
|
|
26994
26739
|
switch (runtimeMode) {
|
|
@@ -27046,7 +26791,7 @@ var EventBus = class {
|
|
|
27046
26791
|
function expandHomePath(value) {
|
|
27047
26792
|
if (value === "~") return NodeOS2.homedir();
|
|
27048
26793
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
27049
|
-
return
|
|
26794
|
+
return NodePath2.join(NodeOS2.homedir(), value.slice(2));
|
|
27050
26795
|
}
|
|
27051
26796
|
return value;
|
|
27052
26797
|
}
|
|
@@ -27057,15 +26802,13 @@ function modelIdFromSelection(selection) {
|
|
|
27057
26802
|
const model = selection["model"];
|
|
27058
26803
|
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
27059
26804
|
}
|
|
27060
|
-
function buildSpawnEnv(recipe, configuredHomePath
|
|
26805
|
+
function buildSpawnEnv(recipe, configuredHomePath) {
|
|
27061
26806
|
const homePath = configuredHomePath.trim();
|
|
27062
26807
|
const homeEnvVar = recipe.homeEnvVar.trim();
|
|
27063
26808
|
const homeInjection = homePath.length > 0 && homeEnvVar.length > 0 ? { [homeEnvVar]: expandHomePath(homePath) } : {};
|
|
27064
26809
|
return mergeLaunchEnv({
|
|
27065
|
-
brainSlots: brainSlotEnvKeys(ACP_CARD),
|
|
27066
26810
|
accountHome: homeInjection,
|
|
27067
|
-
instanceTable: recipe.environment
|
|
27068
|
-
launch: launchEnv
|
|
26811
|
+
instanceTable: recipe.environment
|
|
27069
26812
|
});
|
|
27070
26813
|
}
|
|
27071
26814
|
function nowIso() {
|
|
@@ -27073,31 +26816,9 @@ function nowIso() {
|
|
|
27073
26816
|
}
|
|
27074
26817
|
function acpContinuationKey(recipe) {
|
|
27075
26818
|
const homePath = recipe.homePath.trim();
|
|
27076
|
-
const resolvedHomePath = homePath.length > 0 ?
|
|
26819
|
+
const resolvedHomePath = homePath.length > 0 ? NodePath2.resolve(expandHomePath(homePath)) : "";
|
|
27077
26820
|
return `acp:home:${recipe.binaryPath.trim()}\0${resolvedHomePath}`;
|
|
27078
26821
|
}
|
|
27079
|
-
function resolveHomePath(recipe, launchHomePath) {
|
|
27080
|
-
const envVar = recipe.homeEnvVar.trim();
|
|
27081
|
-
const fromEnvironment = envVar.length > 0 ? recipe.environment[envVar]?.trim() : void 0;
|
|
27082
|
-
if (fromEnvironment !== void 0 && fromEnvironment.length > 0) {
|
|
27083
|
-
return expandHomePath(fromEnvironment);
|
|
27084
|
-
}
|
|
27085
|
-
const configured = (launchHomePath?.trim() || recipe.homePath).trim();
|
|
27086
|
-
return configured.length > 0 ? expandHomePath(configured) : "";
|
|
27087
|
-
}
|
|
27088
|
-
function isKimiInstance(recipe) {
|
|
27089
|
-
return recipe.providerId === KIMI_PROVIDER_ID || recipe.homeEnvVar.trim() === KIMI_HOME_ENV_VAR;
|
|
27090
|
-
}
|
|
27091
|
-
function vendorHooksFor(recipe, launchHomePath) {
|
|
27092
|
-
if (!isKimiInstance(recipe)) return void 0;
|
|
27093
|
-
const homePath = resolveHomePath(recipe, launchHomePath);
|
|
27094
|
-
return {
|
|
27095
|
-
permissionUserInput: kimiPermissionUserInput,
|
|
27096
|
-
// ACP 的 `usage_update` 我们这边不消费,进度圈只能从各家自己写在磁盘上的
|
|
27097
|
-
// 记录里读。目前只有 Kimi 的格式核实过。
|
|
27098
|
-
readContextWindow: ({ sessionId }) => readKimiContextWindow({ homePath, acpSessionId: sessionId })
|
|
27099
|
-
};
|
|
27100
|
-
}
|
|
27101
26822
|
async function stopBooked(booked) {
|
|
27102
26823
|
await booked.executor.dispose().catch(() => void 0);
|
|
27103
26824
|
await booked.handle.kill("SIGTERM").catch(() => void 0);
|
|
@@ -27125,7 +26846,7 @@ var createAcpInstance = (config2, host) => {
|
|
|
27125
26846
|
};
|
|
27126
26847
|
}
|
|
27127
26848
|
const env = buildSpawnEnv(recipe, recipe.homePath);
|
|
27128
|
-
const outcome =
|
|
26849
|
+
const outcome = await probeAcpModelsViaSession({ recipe, host, env });
|
|
27129
26850
|
switch (outcome.kind) {
|
|
27130
26851
|
case "not-started":
|
|
27131
26852
|
return {
|
|
@@ -27165,6 +26886,8 @@ var createAcpInstance = (config2, host) => {
|
|
|
27165
26886
|
};
|
|
27166
26887
|
}
|
|
27167
26888
|
},
|
|
26889
|
+
// 暂不处理 input.readOnlyDirectories(有意为之):acp 经共享的 ycodium-acp-executor 起会话,
|
|
26890
|
+
// 还没用真机确认这家 CLI 对 cwd 之外的读怎么处理、要不要放行。确认之后再接这一栏。
|
|
27168
26891
|
startSession: async (input2, signal) => {
|
|
27169
26892
|
if (disposed) throw new Error("instance disposed");
|
|
27170
26893
|
if (signal?.aborted) throw new Error("aborted");
|
|
@@ -27178,11 +26901,7 @@ var createAcpInstance = (config2, host) => {
|
|
|
27178
26901
|
await stopBooked(existing);
|
|
27179
26902
|
threads.delete(input2.threadId);
|
|
27180
26903
|
}
|
|
27181
|
-
const env = buildSpawnEnv(
|
|
27182
|
-
recipe,
|
|
27183
|
-
input2.launch.homePath?.trim() || recipe.homePath,
|
|
27184
|
-
input2.launch.processEnv
|
|
27185
|
-
);
|
|
26904
|
+
const env = buildSpawnEnv(recipe, recipe.homePath);
|
|
27186
26905
|
const handle = await host.process.spawn({
|
|
27187
26906
|
program: recipe.binaryPath,
|
|
27188
26907
|
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
@@ -27192,12 +26911,11 @@ var createAcpInstance = (config2, host) => {
|
|
|
27192
26911
|
});
|
|
27193
26912
|
const { readable, writable } = nodeStreamsFromHandle2(handle);
|
|
27194
26913
|
const resume = input2.discardResumeCursor === true ? void 0 : parseAcpResumeCursor(input2.resumeCursor, RESUME_SCHEMA_VERSION);
|
|
27195
|
-
const requestedModelId =
|
|
26914
|
+
const requestedModelId = modelIdFromSelection(input2.modelSelection);
|
|
27196
26915
|
const requestedEffort = modelSelectionStringOption(
|
|
27197
26916
|
input2.modelSelection,
|
|
27198
26917
|
ACP_EFFORT_OPTION_ID
|
|
27199
26918
|
);
|
|
27200
|
-
const hooks = vendorHooksFor(recipe, input2.launch.homePath);
|
|
27201
26919
|
const autoApprove = input2.nativeModeId === void 0 ? (request) => acpRuntimeModeAutoApproves(
|
|
27202
26920
|
threads.get(input2.threadId)?.session.runtimeMode ?? input2.runtimeMode,
|
|
27203
26921
|
request.kind
|
|
@@ -27214,9 +26932,11 @@ var createAcpInstance = (config2, host) => {
|
|
|
27214
26932
|
log: host.log,
|
|
27215
26933
|
...requestedModelId === void 0 ? {} : { requestedModelId },
|
|
27216
26934
|
...input2.bindingGeneration === void 0 ? {} : { originBindingGeneration: input2.bindingGeneration },
|
|
27217
|
-
...hooks === void 0 ? {} : { hooks },
|
|
27218
26935
|
...autoApprove === void 0 ? {} : { autoApprove },
|
|
27219
|
-
...resume === void 0 ? {} : { resumeSessionId: resume.sessionId }
|
|
26936
|
+
...resume === void 0 ? {} : { resumeSessionId: resume.sessionId },
|
|
26937
|
+
// 内置编排那一条排第一,后面跟用户在插件中心配的;缺了 `mcpServers` 这一栏,
|
|
26938
|
+
// `mcp__ycodium__*` 整套工具在通用 ACP 会话里都不存在。
|
|
26939
|
+
...input2.mcpServers === void 0 || input2.mcpServers.length === 0 ? {} : { mcpServers: toAcpMcpServers(input2.mcpServers) }
|
|
27220
26940
|
});
|
|
27221
26941
|
const forwarding = (async () => {
|
|
27222
26942
|
for await (const event of executor.events) {
|
package/locales/en.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"form": {
|
|
3
|
+
"binaryPath": {
|
|
4
|
+
"title": "Program path",
|
|
5
|
+
"description": "The ACP program this provider launches.",
|
|
6
|
+
"placeholder": "e.g. my-agent"
|
|
7
|
+
},
|
|
8
|
+
"launchArgs": {
|
|
9
|
+
"title": "Launch arguments",
|
|
10
|
+
"description": "Arguments that put the CLI into ACP stdio mode.",
|
|
11
|
+
"placeholder": "e.g. acp or --acp"
|
|
12
|
+
},
|
|
13
|
+
"homePath": {
|
|
14
|
+
"title": "Account directory",
|
|
15
|
+
"description": "Where this account's login and history live. Leave empty to use the CLI's default.",
|
|
16
|
+
"placeholder": "e.g. ~/.my-agent-work"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"form": {
|
|
3
|
+
"binaryPath": {
|
|
4
|
+
"title": "程序路径",
|
|
5
|
+
"description": "此 provider 启动的 ACP 程序。",
|
|
6
|
+
"placeholder": "例如 my-agent"
|
|
7
|
+
},
|
|
8
|
+
"launchArgs": {
|
|
9
|
+
"title": "启动参数",
|
|
10
|
+
"description": "让命令行工具进入 ACP stdio 模式的参数。",
|
|
11
|
+
"placeholder": "例如 acp 或 --acp"
|
|
12
|
+
},
|
|
13
|
+
"homePath": {
|
|
14
|
+
"title": "账户目录",
|
|
15
|
+
"description": "此账户的登录信息与历史记录所在的目录。留空则使用该命令行工具的默认目录。",
|
|
16
|
+
"placeholder": "例如 ~/.my-agent-work"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-acp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2510",
|
|
4
4
|
"description": "Generic ACP executor: user-supplied CLI over Agent Client Protocol stdio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"assets",
|
|
13
|
+
"locales",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"type": "module",
|
|
@@ -20,10 +21,9 @@
|
|
|
20
21
|
"@types/node": "24.12.4",
|
|
21
22
|
"esbuild": "0.28.1",
|
|
22
23
|
"vite-plus": "0.2.2",
|
|
23
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
24
|
+
"@ycodium-ai/plugin-api": "0.2.2510",
|
|
24
25
|
"ycodium-executor-testing": "0.0.0",
|
|
25
|
-
"ycodium-acp-executor": "0.
|
|
26
|
-
"ycodium-acp-protocol": "0.0.0"
|
|
26
|
+
"ycodium-acp-executor": "0.2.2510"
|
|
27
27
|
},
|
|
28
28
|
"ycodium": {
|
|
29
29
|
"plugin": "./dist/index.js",
|