@ycodium-ai/agent-acp 0.2.2143 → 0.2.2488
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 +91 -396
- package/locales/en.json +19 -0
- package/locales/zh-CN.json +19 -0
- package/package.json +5 -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,10 @@ function tokenizeLaunchArgs(value) {
|
|
|
26628
26586
|
return tokens;
|
|
26629
26587
|
}
|
|
26630
26588
|
|
|
26631
|
-
// src/kimi.ts
|
|
26632
|
-
import * as NodeFS from "node:fs";
|
|
26633
|
-
import * as NodePath from "node:path";
|
|
26634
|
-
var KIMI_PROVIDER_ID = "kimiCode";
|
|
26635
|
-
var KIMI_HOME_ENV_VAR = "KIMI_CODE_HOME";
|
|
26636
|
-
var KIMI_USER_INPUT_TITLES = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
|
|
26637
|
-
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26638
|
-
function questionTextFromContent(content) {
|
|
26639
|
-
if (!Array.isArray(content)) return "";
|
|
26640
|
-
const parts = [];
|
|
26641
|
-
for (const entry of content) {
|
|
26642
|
-
if (!isRecord7(entry) || entry["type"] !== "content") continue;
|
|
26643
|
-
const inner = entry["content"];
|
|
26644
|
-
if (!isRecord7(inner) || inner["type"] !== "text") continue;
|
|
26645
|
-
const text = inner["text"];
|
|
26646
|
-
if (typeof text === "string") parts.push(text);
|
|
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
|
-
}
|
|
26722
|
-
}
|
|
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);
|
|
26750
|
-
}
|
|
26751
|
-
|
|
26752
|
-
// src/kimiModels.ts
|
|
26753
|
-
import {
|
|
26754
|
-
ExecutorSpawnRefusedError as ExecutorSpawnRefusedError2
|
|
26755
|
-
} from "@ycodium-ai/plugin-api/executor";
|
|
26756
|
-
|
|
26757
26589
|
// src/probeModels.ts
|
|
26758
|
-
import * as
|
|
26590
|
+
import * as NodeFS from "node:fs";
|
|
26759
26591
|
import * as NodeOS from "node:os";
|
|
26760
|
-
import * as
|
|
26592
|
+
import * as NodePath from "node:path";
|
|
26761
26593
|
import {
|
|
26762
26594
|
ExecutorSpawnRefusedError
|
|
26763
26595
|
} from "@ycodium-ai/plugin-api/executor";
|
|
@@ -26767,18 +26599,18 @@ var CLIENT_INFO = { name: "ycodium-agent-acp-probe", version: "0.2.0" };
|
|
|
26767
26599
|
var ACP_EFFORT_OPTION_ID = "reasoning";
|
|
26768
26600
|
function acpProbeSessionCwd(instanceId) {
|
|
26769
26601
|
const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
26770
|
-
return
|
|
26602
|
+
return NodePath.join(NodeOS.tmpdir(), `ycodium-acp-probe-${safe}`);
|
|
26771
26603
|
}
|
|
26772
|
-
function
|
|
26604
|
+
function isRecord7(value) {
|
|
26773
26605
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26774
26606
|
}
|
|
26775
26607
|
function asString3(value) {
|
|
26776
26608
|
return typeof value === "string" ? value : void 0;
|
|
26777
26609
|
}
|
|
26778
26610
|
function findAcpProbeSessionId(listed, probeCwd) {
|
|
26779
|
-
if (!
|
|
26611
|
+
if (!isRecord7(listed) || !Array.isArray(listed["sessions"])) return void 0;
|
|
26780
26612
|
for (const entry of listed["sessions"]) {
|
|
26781
|
-
if (!
|
|
26613
|
+
if (!isRecord7(entry)) continue;
|
|
26782
26614
|
if (asString3(entry["cwd"]) !== probeCwd) continue;
|
|
26783
26615
|
const sessionId = asString3(entry["sessionId"]);
|
|
26784
26616
|
if (sessionId !== void 0) return sessionId;
|
|
@@ -26795,7 +26627,7 @@ async function probeSessionSetup(handshake, probeCwd) {
|
|
|
26795
26627
|
return handshake.request("session/new", { cwd: probeCwd, mcpServers: [] });
|
|
26796
26628
|
}
|
|
26797
26629
|
function acpProbeModels(setup) {
|
|
26798
|
-
if (!
|
|
26630
|
+
if (!isRecord7(setup)) return void 0;
|
|
26799
26631
|
const rawOptions = setup["configOptions"];
|
|
26800
26632
|
const choices = acpModelChoicesFromConfigOptions(rawOptions) ?? acpModelChoicesFromSessionModels(setup["models"]);
|
|
26801
26633
|
if (choices === void 0 || choices.length === 0) return void 0;
|
|
@@ -26830,7 +26662,7 @@ async function probeAcpModelsViaSession(input2) {
|
|
|
26830
26662
|
const { recipe, host, env } = input2;
|
|
26831
26663
|
const probeCwd = acpProbeSessionCwd(host.instanceId);
|
|
26832
26664
|
try {
|
|
26833
|
-
|
|
26665
|
+
NodeFS.mkdirSync(probeCwd, { recursive: true });
|
|
26834
26666
|
} catch (error62) {
|
|
26835
26667
|
return { kind: "failed", detail: probeFailureDetail(error62), version: null };
|
|
26836
26668
|
}
|
|
@@ -26882,113 +26714,6 @@ async function probeAcpModelsViaSession(input2) {
|
|
|
26882
26714
|
}
|
|
26883
26715
|
}
|
|
26884
26716
|
|
|
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
26717
|
// src/runtimeModeApproval.ts
|
|
26993
26718
|
function acpRuntimeModeAutoApproves(runtimeMode, toolKind) {
|
|
26994
26719
|
switch (runtimeMode) {
|
|
@@ -27046,7 +26771,7 @@ var EventBus = class {
|
|
|
27046
26771
|
function expandHomePath(value) {
|
|
27047
26772
|
if (value === "~") return NodeOS2.homedir();
|
|
27048
26773
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
27049
|
-
return
|
|
26774
|
+
return NodePath2.join(NodeOS2.homedir(), value.slice(2));
|
|
27050
26775
|
}
|
|
27051
26776
|
return value;
|
|
27052
26777
|
}
|
|
@@ -27057,15 +26782,13 @@ function modelIdFromSelection(selection) {
|
|
|
27057
26782
|
const model = selection["model"];
|
|
27058
26783
|
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
27059
26784
|
}
|
|
27060
|
-
function buildSpawnEnv(recipe, configuredHomePath
|
|
26785
|
+
function buildSpawnEnv(recipe, configuredHomePath) {
|
|
27061
26786
|
const homePath = configuredHomePath.trim();
|
|
27062
26787
|
const homeEnvVar = recipe.homeEnvVar.trim();
|
|
27063
26788
|
const homeInjection = homePath.length > 0 && homeEnvVar.length > 0 ? { [homeEnvVar]: expandHomePath(homePath) } : {};
|
|
27064
26789
|
return mergeLaunchEnv({
|
|
27065
|
-
brainSlots: brainSlotEnvKeys(ACP_CARD),
|
|
27066
26790
|
accountHome: homeInjection,
|
|
27067
|
-
instanceTable: recipe.environment
|
|
27068
|
-
launch: launchEnv
|
|
26791
|
+
instanceTable: recipe.environment
|
|
27069
26792
|
});
|
|
27070
26793
|
}
|
|
27071
26794
|
function nowIso() {
|
|
@@ -27073,31 +26796,9 @@ function nowIso() {
|
|
|
27073
26796
|
}
|
|
27074
26797
|
function acpContinuationKey(recipe) {
|
|
27075
26798
|
const homePath = recipe.homePath.trim();
|
|
27076
|
-
const resolvedHomePath = homePath.length > 0 ?
|
|
26799
|
+
const resolvedHomePath = homePath.length > 0 ? NodePath2.resolve(expandHomePath(homePath)) : "";
|
|
27077
26800
|
return `acp:home:${recipe.binaryPath.trim()}\0${resolvedHomePath}`;
|
|
27078
26801
|
}
|
|
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
26802
|
async function stopBooked(booked) {
|
|
27102
26803
|
await booked.executor.dispose().catch(() => void 0);
|
|
27103
26804
|
await booked.handle.kill("SIGTERM").catch(() => void 0);
|
|
@@ -27125,7 +26826,7 @@ var createAcpInstance = (config2, host) => {
|
|
|
27125
26826
|
};
|
|
27126
26827
|
}
|
|
27127
26828
|
const env = buildSpawnEnv(recipe, recipe.homePath);
|
|
27128
|
-
const outcome =
|
|
26829
|
+
const outcome = await probeAcpModelsViaSession({ recipe, host, env });
|
|
27129
26830
|
switch (outcome.kind) {
|
|
27130
26831
|
case "not-started":
|
|
27131
26832
|
return {
|
|
@@ -27178,11 +26879,7 @@ var createAcpInstance = (config2, host) => {
|
|
|
27178
26879
|
await stopBooked(existing);
|
|
27179
26880
|
threads.delete(input2.threadId);
|
|
27180
26881
|
}
|
|
27181
|
-
const env = buildSpawnEnv(
|
|
27182
|
-
recipe,
|
|
27183
|
-
input2.launch.homePath?.trim() || recipe.homePath,
|
|
27184
|
-
input2.launch.processEnv
|
|
27185
|
-
);
|
|
26882
|
+
const env = buildSpawnEnv(recipe, recipe.homePath);
|
|
27186
26883
|
const handle = await host.process.spawn({
|
|
27187
26884
|
program: recipe.binaryPath,
|
|
27188
26885
|
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
@@ -27192,12 +26889,11 @@ var createAcpInstance = (config2, host) => {
|
|
|
27192
26889
|
});
|
|
27193
26890
|
const { readable, writable } = nodeStreamsFromHandle2(handle);
|
|
27194
26891
|
const resume = input2.discardResumeCursor === true ? void 0 : parseAcpResumeCursor(input2.resumeCursor, RESUME_SCHEMA_VERSION);
|
|
27195
|
-
const requestedModelId =
|
|
26892
|
+
const requestedModelId = modelIdFromSelection(input2.modelSelection);
|
|
27196
26893
|
const requestedEffort = modelSelectionStringOption(
|
|
27197
26894
|
input2.modelSelection,
|
|
27198
26895
|
ACP_EFFORT_OPTION_ID
|
|
27199
26896
|
);
|
|
27200
|
-
const hooks = vendorHooksFor(recipe, input2.launch.homePath);
|
|
27201
26897
|
const autoApprove = input2.nativeModeId === void 0 ? (request) => acpRuntimeModeAutoApproves(
|
|
27202
26898
|
threads.get(input2.threadId)?.session.runtimeMode ?? input2.runtimeMode,
|
|
27203
26899
|
request.kind
|
|
@@ -27214,7 +26910,6 @@ var createAcpInstance = (config2, host) => {
|
|
|
27214
26910
|
log: host.log,
|
|
27215
26911
|
...requestedModelId === void 0 ? {} : { requestedModelId },
|
|
27216
26912
|
...input2.bindingGeneration === void 0 ? {} : { originBindingGeneration: input2.bindingGeneration },
|
|
27217
|
-
...hooks === void 0 ? {} : { hooks },
|
|
27218
26913
|
...autoApprove === void 0 ? {} : { autoApprove },
|
|
27219
26914
|
...resume === void 0 ? {} : { resumeSessionId: resume.sessionId }
|
|
27220
26915
|
});
|
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.2488",
|
|
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,9 +21,9 @@
|
|
|
20
21
|
"@types/node": "24.12.4",
|
|
21
22
|
"esbuild": "0.28.1",
|
|
22
23
|
"vite-plus": "0.2.2",
|
|
23
|
-
"
|
|
24
|
-
"ycodium-
|
|
25
|
-
"ycodium-
|
|
24
|
+
"ycodium-acp-executor": "0.2.2488",
|
|
25
|
+
"@ycodium-ai/plugin-api": "0.2.2488",
|
|
26
|
+
"ycodium-executor-testing": "0.0.0"
|
|
26
27
|
},
|
|
27
28
|
"ycodium": {
|
|
28
29
|
"plugin": "./dist/index.js",
|