@ycodium-ai/agent-acp 0.2.2106 → 0.2.2126
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 +17 -3
- package/dist/index.js +930 -110
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -8,8 +8,14 @@ var __export = (target, all) => {
|
|
|
8
8
|
import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
9
9
|
|
|
10
10
|
// src/acpInstance.ts
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
11
|
+
import * as NodeOS2 from "node:os";
|
|
12
|
+
import * as NodePath3 from "node:path";
|
|
13
|
+
import {
|
|
14
|
+
mergeLaunchEnv,
|
|
15
|
+
modelSelectionStringOption,
|
|
16
|
+
brainSlotEnvKeys
|
|
17
|
+
} from "@ycodium-ai/plugin-api/executor";
|
|
18
|
+
import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
|
|
13
19
|
|
|
14
20
|
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
15
21
|
import * as NodeCrypto from "node:crypto";
|
|
@@ -23879,6 +23885,12 @@ function acpApprovalOptions(request) {
|
|
|
23879
23885
|
}
|
|
23880
23886
|
return options;
|
|
23881
23887
|
}
|
|
23888
|
+
function selectAutoApprovedAcpPermissionOption(request) {
|
|
23889
|
+
if (new Set(request.options.map((option) => option.kind)).size !== request.options.length) {
|
|
23890
|
+
return void 0;
|
|
23891
|
+
}
|
|
23892
|
+
return selectAcpPermissionOptionId(request, "acceptForSession") ?? selectAcpPermissionOptionId(request, "accept");
|
|
23893
|
+
}
|
|
23882
23894
|
function parseAcpResumeCursor(raw, schemaVersion) {
|
|
23883
23895
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
23884
23896
|
const record2 = raw;
|
|
@@ -24272,6 +24284,233 @@ function makeAcpContentDeltaEvent(input2) {
|
|
|
24272
24284
|
};
|
|
24273
24285
|
}
|
|
24274
24286
|
|
|
24287
|
+
// ../../packages/ycodium-acp-executor/src/config-options.ts
|
|
24288
|
+
function isRecord3(value) {
|
|
24289
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24290
|
+
}
|
|
24291
|
+
function asString(value) {
|
|
24292
|
+
return typeof value === "string" ? value : void 0;
|
|
24293
|
+
}
|
|
24294
|
+
function normalizedField(option, key) {
|
|
24295
|
+
return asString(option[key])?.trim().toLowerCase() ?? "";
|
|
24296
|
+
}
|
|
24297
|
+
function looksLikeEffortOption(option) {
|
|
24298
|
+
const id = normalizedField(option, "id");
|
|
24299
|
+
const name = normalizedField(option, "name");
|
|
24300
|
+
return id === "effort" || id === "reasoning" || name === "effort" || name === "reasoning" || name.includes("effort") || name.includes("reasoning") || normalizedField(option, "category") === "thought_level";
|
|
24301
|
+
}
|
|
24302
|
+
function flattenChoices(rawOptions, currentValue) {
|
|
24303
|
+
if (!Array.isArray(rawOptions)) return [];
|
|
24304
|
+
const out = [];
|
|
24305
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24306
|
+
const push = (entry) => {
|
|
24307
|
+
if (!isRecord3(entry)) return;
|
|
24308
|
+
const value = asString(entry["value"]);
|
|
24309
|
+
if (value === void 0 || seen.has(value)) return;
|
|
24310
|
+
seen.add(value);
|
|
24311
|
+
const description = asString(entry["description"])?.trim();
|
|
24312
|
+
const name = asString(entry["name"])?.trim();
|
|
24313
|
+
out.push({
|
|
24314
|
+
value,
|
|
24315
|
+
...name ? { name } : {},
|
|
24316
|
+
label: name || value,
|
|
24317
|
+
...description ? { description } : {},
|
|
24318
|
+
...currentValue !== void 0 && currentValue === value ? { isDefault: true } : {}
|
|
24319
|
+
});
|
|
24320
|
+
};
|
|
24321
|
+
for (const entry of rawOptions) {
|
|
24322
|
+
if (isRecord3(entry) && Array.isArray(entry["options"])) {
|
|
24323
|
+
for (const nested of entry["options"]) push(nested);
|
|
24324
|
+
continue;
|
|
24325
|
+
}
|
|
24326
|
+
push(entry);
|
|
24327
|
+
}
|
|
24328
|
+
return out;
|
|
24329
|
+
}
|
|
24330
|
+
function findAcpEffortConfig(configOptions) {
|
|
24331
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24332
|
+
const candidates = configOptions.filter(isRecord3).filter((option) => normalizedField(option, "type") === "select").filter(looksLikeEffortOption);
|
|
24333
|
+
if (candidates.length === 0) return void 0;
|
|
24334
|
+
const picked = candidates.find((option) => normalizedField(option, "category") === "model_option") ?? candidates.find((option) => normalizedField(option, "id") === "effort") ?? candidates.find((option) => normalizedField(option, "category") === "thought_level") ?? candidates[0];
|
|
24335
|
+
if (picked === void 0) return void 0;
|
|
24336
|
+
const configId = asString(picked["id"])?.trim();
|
|
24337
|
+
if (!configId) return void 0;
|
|
24338
|
+
const choices = flattenChoices(picked["options"], asString(picked["currentValue"])?.trim());
|
|
24339
|
+
if (choices.length === 0) return void 0;
|
|
24340
|
+
return {
|
|
24341
|
+
configId,
|
|
24342
|
+
label: asString(picked["name"])?.trim() ?? "",
|
|
24343
|
+
choices
|
|
24344
|
+
};
|
|
24345
|
+
}
|
|
24346
|
+
function acpModelChoicesFromConfigOptions(configOptions) {
|
|
24347
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24348
|
+
const records = configOptions.filter(isRecord3);
|
|
24349
|
+
const modelOption = records.find((option) => normalizedField(option, "category") === "model");
|
|
24350
|
+
if (modelOption === void 0) return void 0;
|
|
24351
|
+
if (!asString(modelOption["id"])?.trim()) return void 0;
|
|
24352
|
+
return flattenChoices(modelOption["options"], asString(modelOption["currentValue"])?.trim());
|
|
24353
|
+
}
|
|
24354
|
+
function acpModelChoicesFromSessionModels(models) {
|
|
24355
|
+
if (!isRecord3(models) || !Array.isArray(models["availableModels"])) return void 0;
|
|
24356
|
+
const currentModelId = asString(models["currentModelId"])?.trim();
|
|
24357
|
+
const out = [];
|
|
24358
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24359
|
+
for (const entry of models["availableModels"]) {
|
|
24360
|
+
if (!isRecord3(entry)) continue;
|
|
24361
|
+
const value = asString(entry["modelId"])?.trim();
|
|
24362
|
+
if (!value || seen.has(value)) continue;
|
|
24363
|
+
seen.add(value);
|
|
24364
|
+
const name = asString(entry["name"])?.trim();
|
|
24365
|
+
const description = asString(entry["description"])?.trim();
|
|
24366
|
+
out.push({
|
|
24367
|
+
value,
|
|
24368
|
+
...name ? { name } : {},
|
|
24369
|
+
label: name || value,
|
|
24370
|
+
...description ? { description } : {},
|
|
24371
|
+
...currentModelId !== void 0 && currentModelId === value ? { isDefault: true } : {}
|
|
24372
|
+
});
|
|
24373
|
+
}
|
|
24374
|
+
return out;
|
|
24375
|
+
}
|
|
24376
|
+
|
|
24377
|
+
// ../../packages/ycodium-acp-executor/src/runtime-mode.ts
|
|
24378
|
+
function isRecord4(value) {
|
|
24379
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24380
|
+
}
|
|
24381
|
+
function asString2(value) {
|
|
24382
|
+
return typeof value === "string" ? value : void 0;
|
|
24383
|
+
}
|
|
24384
|
+
function acpAvailableModes(setup) {
|
|
24385
|
+
if (!isRecord4(setup)) return [];
|
|
24386
|
+
const out = [];
|
|
24387
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24388
|
+
const push = (entry) => {
|
|
24389
|
+
if (!isRecord4(entry)) return;
|
|
24390
|
+
const id = (asString2(entry["id"]) ?? asString2(entry["value"]))?.trim();
|
|
24391
|
+
if (!id || seen.has(id)) return;
|
|
24392
|
+
seen.add(id);
|
|
24393
|
+
const meta3 = entry["_meta"];
|
|
24394
|
+
const kind = isRecord4(meta3) ? asString2(meta3["kind"])?.trim().toLowerCase() : void 0;
|
|
24395
|
+
const name = asString2(entry["name"])?.trim();
|
|
24396
|
+
const description = asString2(entry["description"])?.trim();
|
|
24397
|
+
out.push({
|
|
24398
|
+
id,
|
|
24399
|
+
name: name || id,
|
|
24400
|
+
...description ? { description } : {},
|
|
24401
|
+
...kind ? { kind } : {}
|
|
24402
|
+
});
|
|
24403
|
+
};
|
|
24404
|
+
const modes = setup["modes"];
|
|
24405
|
+
if (isRecord4(modes) && Array.isArray(modes["availableModes"])) {
|
|
24406
|
+
for (const entry of modes["availableModes"]) push(entry);
|
|
24407
|
+
}
|
|
24408
|
+
const configOptions = setup["configOptions"];
|
|
24409
|
+
if (Array.isArray(configOptions)) {
|
|
24410
|
+
for (const option of configOptions) {
|
|
24411
|
+
if (!isRecord4(option)) continue;
|
|
24412
|
+
if (asString2(option["category"])?.trim().toLowerCase() !== "mode") continue;
|
|
24413
|
+
if (!Array.isArray(option["options"])) continue;
|
|
24414
|
+
for (const entry of option["options"]) push(entry);
|
|
24415
|
+
}
|
|
24416
|
+
}
|
|
24417
|
+
return out;
|
|
24418
|
+
}
|
|
24419
|
+
function acpModeConfigId(setup) {
|
|
24420
|
+
if (!isRecord4(setup)) return void 0;
|
|
24421
|
+
const configOptions = setup["configOptions"];
|
|
24422
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24423
|
+
for (const option of configOptions) {
|
|
24424
|
+
if (!isRecord4(option)) continue;
|
|
24425
|
+
if (asString2(option["category"])?.trim().toLowerCase() !== "mode") continue;
|
|
24426
|
+
const id = asString2(option["id"])?.trim();
|
|
24427
|
+
if (id) return id;
|
|
24428
|
+
}
|
|
24429
|
+
return void 0;
|
|
24430
|
+
}
|
|
24431
|
+
function acpCurrentModeId(setup) {
|
|
24432
|
+
if (!isRecord4(setup)) return void 0;
|
|
24433
|
+
const modes = setup["modes"];
|
|
24434
|
+
if (isRecord4(modes)) {
|
|
24435
|
+
const current = asString2(modes["currentModeId"])?.trim();
|
|
24436
|
+
if (current) return current;
|
|
24437
|
+
}
|
|
24438
|
+
const configOptions = setup["configOptions"];
|
|
24439
|
+
if (Array.isArray(configOptions)) {
|
|
24440
|
+
for (const option of configOptions) {
|
|
24441
|
+
if (!isRecord4(option)) continue;
|
|
24442
|
+
if (asString2(option["category"])?.trim().toLowerCase() !== "mode") continue;
|
|
24443
|
+
const current = asString2(option["currentValue"])?.trim();
|
|
24444
|
+
if (current) return current;
|
|
24445
|
+
}
|
|
24446
|
+
}
|
|
24447
|
+
return void 0;
|
|
24448
|
+
}
|
|
24449
|
+
|
|
24450
|
+
// ../../packages/ycodium-acp-executor/src/handshake.ts
|
|
24451
|
+
function acpInitializePayload(clientInfo, overrides) {
|
|
24452
|
+
return {
|
|
24453
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
24454
|
+
clientCapabilities: {
|
|
24455
|
+
fs: {
|
|
24456
|
+
readTextFile: false,
|
|
24457
|
+
writeTextFile: false,
|
|
24458
|
+
...overrides?.fs
|
|
24459
|
+
},
|
|
24460
|
+
terminal: overrides?.terminal ?? false
|
|
24461
|
+
},
|
|
24462
|
+
clientInfo
|
|
24463
|
+
};
|
|
24464
|
+
}
|
|
24465
|
+
|
|
24466
|
+
// ../../packages/ycodium-acp-executor/src/config-option-wiring.ts
|
|
24467
|
+
var VENDOR_CATEGORY_PREFIX = "_";
|
|
24468
|
+
var ACP_CONFIG_CATEGORY_HANDLING = {
|
|
24469
|
+
mode: {
|
|
24470
|
+
consumed: true,
|
|
24471
|
+
via: "runtime-mode.ts\uFF1AacpAvailableModes / acpCurrentModeId / acpModeConfigId"
|
|
24472
|
+
},
|
|
24473
|
+
model: {
|
|
24474
|
+
consumed: true,
|
|
24475
|
+
via: "runtime-model.ts:extractModelConfigId \u2192 executor.ts:applyRequestedModel"
|
|
24476
|
+
},
|
|
24477
|
+
thought_level: {
|
|
24478
|
+
consumed: true,
|
|
24479
|
+
via: "config-options.ts:findAcpEffortConfig \u2192 executor.ts:applyRequestedEffort"
|
|
24480
|
+
},
|
|
24481
|
+
model_option: {
|
|
24482
|
+
consumed: true,
|
|
24483
|
+
// 精确说法:它不是**识别器**,是**优先级**。`looksLikeEffortOption` 先筛出候选,
|
|
24484
|
+
// 标了 `model_option` 的在候选里排第一(厂商自己标的最准),排在 id 叫 `effort`
|
|
24485
|
+
// 的和标 `thought_level` 的前面。光有这个 category 而 id/name 不像力度档的,
|
|
24486
|
+
// 压根进不了候选。
|
|
24487
|
+
via: "config-options.ts:findAcpEffortConfig\uFF08\u5019\u9009\u91CC\u7684\u6700\u9AD8\u4F18\u5148\u7EA7\uFF0C\u538B\u8FC7 thought_level\uFF09"
|
|
24488
|
+
},
|
|
24489
|
+
model_config: {
|
|
24490
|
+
consumed: false,
|
|
24491
|
+
note: "\u53EA\u6709\u5BBF\u4E3B\u7684 CursorProvider \u6D88\u8D39\u8FC7\uFF08context / fast / thinking \u4E09\u4E2A\u5F00\u5173\uFF09\u3002Cursor 2026-09-20 \u5E9F\u5F03\u5220\u9664\uFF0C\u8FD9\u4E00\u7C7B\u73B0\u5728\u6CA1\u6709\u6D88\u8D39\u70B9\uFF1B\u6CA1\u89C1\u8FC7\u522B\u5BB6\u7684\u771F\u5B9E\u8F7D\u8377\uFF0C\u5148\u8BB0\u8D26\u4E0D\u731C\u5F62\u72B6\u3002"
|
|
24492
|
+
}
|
|
24493
|
+
};
|
|
24494
|
+
var KNOWN_CATEGORIES = new Set(Object.keys(ACP_CONFIG_CATEGORY_HANDLING));
|
|
24495
|
+
function unhandledConfigCategories(configOptions) {
|
|
24496
|
+
if (!configOptions) return [];
|
|
24497
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24498
|
+
const out = [];
|
|
24499
|
+
for (const option of configOptions) {
|
|
24500
|
+
const category = option.category?.trim();
|
|
24501
|
+
if (!category) continue;
|
|
24502
|
+
if (KNOWN_CATEGORIES.has(category)) continue;
|
|
24503
|
+
if (seen.has(category)) continue;
|
|
24504
|
+
seen.add(category);
|
|
24505
|
+
out.push({
|
|
24506
|
+
category,
|
|
24507
|
+
optionId: option.id.trim(),
|
|
24508
|
+
vendorExtension: category.startsWith(VENDOR_CATEGORY_PREFIX)
|
|
24509
|
+
});
|
|
24510
|
+
}
|
|
24511
|
+
return out;
|
|
24512
|
+
}
|
|
24513
|
+
|
|
24275
24514
|
// ../../packages/ycodium-acp-executor/src/mutex.ts
|
|
24276
24515
|
var Mutex = class {
|
|
24277
24516
|
locked = false;
|
|
@@ -24314,7 +24553,7 @@ var Mutex = class {
|
|
|
24314
24553
|
};
|
|
24315
24554
|
|
|
24316
24555
|
// ../../packages/ycodium-acp-executor/src/util.ts
|
|
24317
|
-
function
|
|
24556
|
+
function isRecord5(value) {
|
|
24318
24557
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24319
24558
|
}
|
|
24320
24559
|
function asTrimmedString(value) {
|
|
@@ -24360,11 +24599,11 @@ function extractCommandFromTitle(title) {
|
|
|
24360
24599
|
return backtickMatch?.[1]?.trim() || void 0;
|
|
24361
24600
|
}
|
|
24362
24601
|
function extractToolCommand(data, title) {
|
|
24363
|
-
const item =
|
|
24364
|
-
const itemInput = item &&
|
|
24365
|
-
const itemResult = item &&
|
|
24366
|
-
const rawInput =
|
|
24367
|
-
const dataInput =
|
|
24602
|
+
const item = isRecord5(data?.["item"]) ? data["item"] : void 0;
|
|
24603
|
+
const itemInput = item && isRecord5(item["input"]) ? item["input"] : void 0;
|
|
24604
|
+
const itemResult = item && isRecord5(item["result"]) ? item["result"] : void 0;
|
|
24605
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24606
|
+
const dataInput = isRecord5(data?.["input"]) ? data["input"] : void 0;
|
|
24368
24607
|
const candidates = [
|
|
24369
24608
|
normalizeCommandValue(item?.["command"]),
|
|
24370
24609
|
normalizeCommandValue(itemInput?.["command"]),
|
|
@@ -24409,7 +24648,7 @@ function collectPaths(value, paths, seen, depth) {
|
|
|
24409
24648
|
}
|
|
24410
24649
|
return;
|
|
24411
24650
|
}
|
|
24412
|
-
if (!
|
|
24651
|
+
if (!isRecord5(value)) {
|
|
24413
24652
|
return;
|
|
24414
24653
|
}
|
|
24415
24654
|
for (const key of ["path", "filePath", "relativePath", "filename", "newPath", "oldPath"]) {
|
|
@@ -24472,7 +24711,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24472
24711
|
const title = asTrimmedString(input2.title);
|
|
24473
24712
|
const detail = stripTrailingExitCode(asTrimmedString(input2.detail));
|
|
24474
24713
|
const fallbackSummary = asTrimmedString(input2.fallbackSummary) ?? "Tool";
|
|
24475
|
-
const data =
|
|
24714
|
+
const data = isRecord5(input2.data) ? input2.data : void 0;
|
|
24476
24715
|
const command = extractToolCommand(data, title);
|
|
24477
24716
|
const primaryPath = extractPrimaryPath(data);
|
|
24478
24717
|
const action = classifyToolAction({
|
|
@@ -24504,7 +24743,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24504
24743
|
};
|
|
24505
24744
|
}
|
|
24506
24745
|
if (action === "search") {
|
|
24507
|
-
const rawInput =
|
|
24746
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24508
24747
|
const query = asTrimmedString(rawInput?.["query"]) ?? asTrimmedString(rawInput?.["pattern"]) ?? asTrimmedString(rawInput?.["searchTerm"]);
|
|
24509
24748
|
return {
|
|
24510
24749
|
summary: "Searched files",
|
|
@@ -24543,6 +24782,46 @@ function findSessionConfigOption(configOptions, configId) {
|
|
|
24543
24782
|
}
|
|
24544
24783
|
return configOptions.find((option) => option.id.trim() === normalizedConfigId);
|
|
24545
24784
|
}
|
|
24785
|
+
function collectSessionConfigOptionValues(configOption) {
|
|
24786
|
+
if (configOption.type !== "select" || !configOption.options) {
|
|
24787
|
+
return [];
|
|
24788
|
+
}
|
|
24789
|
+
return configOption.options.flatMap(
|
|
24790
|
+
(entry) => "value" in entry ? [entry.value] : entry.options.map((option) => option.value)
|
|
24791
|
+
);
|
|
24792
|
+
}
|
|
24793
|
+
function collectSessionModelIds(models) {
|
|
24794
|
+
if (!isRecord5(models) || !Array.isArray(models["availableModels"])) {
|
|
24795
|
+
return [];
|
|
24796
|
+
}
|
|
24797
|
+
return models["availableModels"].flatMap(
|
|
24798
|
+
(model) => isRecord5(model) && typeof model["modelId"] === "string" ? [model["modelId"]] : []
|
|
24799
|
+
);
|
|
24800
|
+
}
|
|
24801
|
+
function catalogModelLastSegment(value) {
|
|
24802
|
+
if (value.startsWith("[")) {
|
|
24803
|
+
let parsed;
|
|
24804
|
+
try {
|
|
24805
|
+
parsed = JSON.parse(value);
|
|
24806
|
+
} catch {
|
|
24807
|
+
return void 0;
|
|
24808
|
+
}
|
|
24809
|
+
if (!Array.isArray(parsed) || parsed.length < 2) return void 0;
|
|
24810
|
+
const last = parsed[parsed.length - 1];
|
|
24811
|
+
return typeof last === "string" ? last : void 0;
|
|
24812
|
+
}
|
|
24813
|
+
const separator = value.indexOf("/");
|
|
24814
|
+
return separator > 0 && separator < value.length - 1 ? value.slice(separator + 1) : void 0;
|
|
24815
|
+
}
|
|
24816
|
+
function matchAdvertisedModelValue(requestedModelId, advertisedValues) {
|
|
24817
|
+
const wanted = requestedModelId.trim();
|
|
24818
|
+
if (!wanted) return void 0;
|
|
24819
|
+
if (advertisedValues.includes(wanted)) return wanted;
|
|
24820
|
+
const byLastSegment = advertisedValues.filter(
|
|
24821
|
+
(value) => catalogModelLastSegment(value) === wanted
|
|
24822
|
+
);
|
|
24823
|
+
return byLastSegment.length === 1 ? byLastSegment[0] : void 0;
|
|
24824
|
+
}
|
|
24546
24825
|
function parseSessionModeState(sessionResponse) {
|
|
24547
24826
|
const modes = sessionResponse.modes;
|
|
24548
24827
|
if (!modes) return void 0;
|
|
@@ -24581,7 +24860,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24581
24860
|
}
|
|
24582
24861
|
const commands = [];
|
|
24583
24862
|
for (const command of availableCommands) {
|
|
24584
|
-
if (!
|
|
24863
|
+
if (!isRecord5(command)) {
|
|
24585
24864
|
continue;
|
|
24586
24865
|
}
|
|
24587
24866
|
const name = typeof command["name"] === "string" ? command["name"].trim() : "";
|
|
@@ -24589,7 +24868,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24589
24868
|
continue;
|
|
24590
24869
|
}
|
|
24591
24870
|
const description = typeof command["description"] === "string" ? command["description"].trim() || void 0 : void 0;
|
|
24592
|
-
const input2 =
|
|
24871
|
+
const input2 = isRecord5(command["input"]) ? command["input"] : void 0;
|
|
24593
24872
|
const inputHint = typeof input2?.["hint"] === "string" ? input2["hint"].trim() || void 0 : void 0;
|
|
24594
24873
|
commands.push({
|
|
24595
24874
|
name,
|
|
@@ -24651,7 +24930,7 @@ function extractCommandFromTitle2(title) {
|
|
|
24651
24930
|
return match?.[1]?.trim() || void 0;
|
|
24652
24931
|
}
|
|
24653
24932
|
function extractToolCallCommand(rawInput, title) {
|
|
24654
|
-
if (
|
|
24933
|
+
if (isRecord5(rawInput)) {
|
|
24655
24934
|
const directCommand = normalizeCommandValue2(rawInput["command"]);
|
|
24656
24935
|
if (directCommand) {
|
|
24657
24936
|
return directCommand;
|
|
@@ -24678,7 +24957,7 @@ function boundToolCallOutputText(text) {
|
|
|
24678
24957
|
}
|
|
24679
24958
|
var RAW_OUTPUT_TEXT_FIELDS = ["content", "stdout", "stderr", "output"];
|
|
24680
24959
|
function boundToolCallRawOutput(rawOutput) {
|
|
24681
|
-
if (!
|
|
24960
|
+
if (!isRecord5(rawOutput)) {
|
|
24682
24961
|
return rawOutput;
|
|
24683
24962
|
}
|
|
24684
24963
|
let changed = false;
|
|
@@ -24908,7 +25187,7 @@ function parseSessionUpdateEvent(params) {
|
|
|
24908
25187
|
const entries = Array.isArray(upd["entries"]) ? upd["entries"] : [];
|
|
24909
25188
|
const plan = entries.map((entry, index) => ({
|
|
24910
25189
|
step: readAcpText(entry, "content") ?? `Step ${index + 1}`,
|
|
24911
|
-
status: normalizePlanStepStatus(
|
|
25190
|
+
status: normalizePlanStepStatus(isRecord5(entry) ? entry["status"] : void 0)
|
|
24912
25191
|
}));
|
|
24913
25192
|
if (plan.length > 0) {
|
|
24914
25193
|
events.push({
|
|
@@ -24947,7 +25226,7 @@ function parseSessionUpdateEvent(params) {
|
|
|
24947
25226
|
}
|
|
24948
25227
|
case "agent_message_chunk":
|
|
24949
25228
|
case "agent_thought_chunk": {
|
|
24950
|
-
const content =
|
|
25229
|
+
const content = isRecord5(upd["content"]) ? upd["content"] : void 0;
|
|
24951
25230
|
const contentType = content?.["type"];
|
|
24952
25231
|
const streamKind = kind === "agent_thought_chunk" ? "reasoning_text" : "assistant_text";
|
|
24953
25232
|
if (contentType === "text") {
|
|
@@ -25014,16 +25293,18 @@ function normalizeModelId(value) {
|
|
|
25014
25293
|
return value?.trim() || void 0;
|
|
25015
25294
|
}
|
|
25016
25295
|
function modelSelectionStateFromSetup(setup) {
|
|
25017
|
-
const sessionModels =
|
|
25296
|
+
const sessionModels = isRecord5(setup.models) ? setup.models : void 0;
|
|
25018
25297
|
const modelConfigId = extractModelConfigId(setup);
|
|
25019
25298
|
const strategy = sessionModels === void 0 && modelConfigId !== void 0 ? "config-option" : "session/set_model";
|
|
25020
|
-
const
|
|
25299
|
+
const modelConfigOption = modelConfigId === void 0 ? void 0 : findSessionConfigOption(setup.configOptions, modelConfigId);
|
|
25300
|
+
const configModel = modelConfigOption?.currentValue;
|
|
25021
25301
|
const currentModelId = strategy === "config-option" ? typeof configModel === "string" ? normalizeModelId(configModel) : void 0 : typeof sessionModels?.["currentModelId"] === "string" ? normalizeModelId(sessionModels["currentModelId"]) : void 0;
|
|
25022
25302
|
return {
|
|
25023
25303
|
strategy,
|
|
25024
25304
|
sessionModelsAdvertised: sessionModels !== void 0,
|
|
25025
25305
|
modelConfigId,
|
|
25026
|
-
currentModelId
|
|
25306
|
+
currentModelId,
|
|
25307
|
+
advertisedModelValues: strategy === "config-option" ? modelConfigOption === void 0 ? [] : collectSessionConfigOptionValues(modelConfigOption) : collectSessionModelIds(sessionModels)
|
|
25027
25308
|
};
|
|
25028
25309
|
}
|
|
25029
25310
|
function createAcpExecutor(options) {
|
|
@@ -25042,8 +25323,10 @@ function createAcpExecutor(options) {
|
|
|
25042
25323
|
strategy: "session/set_model",
|
|
25043
25324
|
sessionModelsAdvertised: false,
|
|
25044
25325
|
modelConfigId: void 0,
|
|
25045
|
-
currentModelId: void 0
|
|
25326
|
+
currentModelId: void 0,
|
|
25327
|
+
advertisedModelValues: []
|
|
25046
25328
|
};
|
|
25329
|
+
let lastUnmatchedModelId;
|
|
25047
25330
|
let initializeResult;
|
|
25048
25331
|
let startResult;
|
|
25049
25332
|
let startInFlight;
|
|
@@ -25368,6 +25651,12 @@ function createAcpExecutor(options) {
|
|
|
25368
25651
|
const userInputOutcome = await handlePermissionAsUserInput(params);
|
|
25369
25652
|
if (userInputOutcome !== void 0) return userInputOutcome;
|
|
25370
25653
|
const permissionRequest = parsePermissionRequest(params);
|
|
25654
|
+
if (options.autoApprove?.(permissionRequest) === true) {
|
|
25655
|
+
const optionId = selectAutoApprovedAcpPermissionOption(params);
|
|
25656
|
+
if (optionId !== void 0) {
|
|
25657
|
+
return { outcome: { outcome: "selected", optionId } };
|
|
25658
|
+
}
|
|
25659
|
+
}
|
|
25371
25660
|
const requestId = randomId();
|
|
25372
25661
|
const outcome = await new Promise((resolve) => {
|
|
25373
25662
|
const pending = {
|
|
@@ -25455,36 +25744,70 @@ function createAcpExecutor(options) {
|
|
|
25455
25744
|
if (requestedModelId === void 0 || requestedModelId === input2.state.currentModelId || input2.state.strategy === "session/set_model" && !input2.state.sessionModelsAdvertised || input2.state.strategy === "config-option" && input2.state.modelConfigId === void 0) {
|
|
25456
25745
|
return input2.state;
|
|
25457
25746
|
}
|
|
25747
|
+
const value = matchAdvertisedModelValue(requestedModelId, input2.state.advertisedModelValues);
|
|
25748
|
+
if (value === void 0) {
|
|
25749
|
+
if (requestedModelId !== lastUnmatchedModelId) {
|
|
25750
|
+
lastUnmatchedModelId = requestedModelId;
|
|
25751
|
+
options.log?.info("requested model is not in the agent catalog; keeping its own model", {
|
|
25752
|
+
requestedModelId,
|
|
25753
|
+
currentModelId: input2.state.currentModelId,
|
|
25754
|
+
advertisedModelValues: input2.state.advertisedModelValues
|
|
25755
|
+
});
|
|
25756
|
+
}
|
|
25757
|
+
return input2.state;
|
|
25758
|
+
}
|
|
25759
|
+
if (value === input2.state.currentModelId) {
|
|
25760
|
+
return input2.state;
|
|
25761
|
+
}
|
|
25458
25762
|
if (input2.state.strategy === "config-option") {
|
|
25459
25763
|
await connection.request("session/set_config_option", {
|
|
25460
25764
|
sessionId: input2.acpSessionId,
|
|
25461
25765
|
configId: input2.state.modelConfigId,
|
|
25462
|
-
value
|
|
25766
|
+
value
|
|
25463
25767
|
});
|
|
25464
25768
|
} else {
|
|
25465
25769
|
await connection.request("session/set_model", {
|
|
25466
25770
|
sessionId: input2.acpSessionId,
|
|
25467
|
-
modelId:
|
|
25771
|
+
modelId: value
|
|
25468
25772
|
});
|
|
25469
25773
|
}
|
|
25470
25774
|
if (!isLive(input2.expectedGeneration)) {
|
|
25471
25775
|
throw new AcpExecutorDisposedError();
|
|
25472
25776
|
}
|
|
25473
|
-
return { ...input2.state, currentModelId:
|
|
25777
|
+
return { ...input2.state, currentModelId: value };
|
|
25778
|
+
};
|
|
25779
|
+
const applyRequestedEffort = async (input2) => {
|
|
25780
|
+
const requested = input2.requestedEffort?.trim();
|
|
25781
|
+
if (!requested) return;
|
|
25782
|
+
const configOptions = typeof input2.setup === "object" && input2.setup !== null ? input2.setup.configOptions : void 0;
|
|
25783
|
+
const effort = findAcpEffortConfig(configOptions);
|
|
25784
|
+
if (effort === void 0) return;
|
|
25785
|
+
const matched = effort.choices.find((choice) => choice.value === requested);
|
|
25786
|
+
if (matched === void 0) {
|
|
25787
|
+
options.log?.info("requested effort is not in the agent catalog; keeping its own", {
|
|
25788
|
+
requestedEffort: requested,
|
|
25789
|
+
advertised: effort.choices.map((choice) => choice.value)
|
|
25790
|
+
});
|
|
25791
|
+
return;
|
|
25792
|
+
}
|
|
25793
|
+
if (matched.isDefault === true) return;
|
|
25794
|
+
if (!isLive(input2.expectedGeneration)) return;
|
|
25795
|
+
try {
|
|
25796
|
+
await connection.request("session/set_config_option", {
|
|
25797
|
+
sessionId: input2.acpSessionId,
|
|
25798
|
+
configId: effort.configId,
|
|
25799
|
+
value: requested
|
|
25800
|
+
});
|
|
25801
|
+
} catch (error62) {
|
|
25802
|
+
options.log?.info("setting the effort level failed; the session keeps its own", {
|
|
25803
|
+
requestedEffort: requested,
|
|
25804
|
+
configId: effort.configId,
|
|
25805
|
+
error: error62 instanceof Error ? error62.message : String(error62)
|
|
25806
|
+
});
|
|
25807
|
+
}
|
|
25474
25808
|
};
|
|
25475
25809
|
const startOnce = async (expectedGeneration) => {
|
|
25476
|
-
const initializePayload =
|
|
25477
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
25478
|
-
clientCapabilities: {
|
|
25479
|
-
fs: {
|
|
25480
|
-
readTextFile: false,
|
|
25481
|
-
writeTextFile: false,
|
|
25482
|
-
...options.clientCapabilities?.fs
|
|
25483
|
-
},
|
|
25484
|
-
terminal: options.clientCapabilities?.terminal ?? false
|
|
25485
|
-
},
|
|
25486
|
-
clientInfo: options.clientInfo
|
|
25487
|
-
};
|
|
25810
|
+
const initializePayload = acpInitializePayload(options.clientInfo, options.clientCapabilities);
|
|
25488
25811
|
const initialized = await connection.request(
|
|
25489
25812
|
"initialize",
|
|
25490
25813
|
initializePayload
|
|
@@ -25528,12 +25851,27 @@ function createAcpExecutor(options) {
|
|
|
25528
25851
|
nextSessionId = created.sessionId;
|
|
25529
25852
|
setup = created;
|
|
25530
25853
|
}
|
|
25854
|
+
const unhandledCategories = unhandledConfigCategories(
|
|
25855
|
+
setup.configOptions
|
|
25856
|
+
);
|
|
25857
|
+
if (unhandledCategories.length > 0) {
|
|
25858
|
+
options.log?.info("acp session reported config option categories we do not handle", {
|
|
25859
|
+
sessionId: nextSessionId,
|
|
25860
|
+
categories: unhandledCategories
|
|
25861
|
+
});
|
|
25862
|
+
}
|
|
25531
25863
|
const nextModelSelectionState = await applyRequestedModel({
|
|
25532
25864
|
state: modelSelectionStateFromSetup(setup),
|
|
25533
25865
|
acpSessionId: nextSessionId,
|
|
25534
25866
|
requestedModelId: options.requestedModelId,
|
|
25535
25867
|
expectedGeneration
|
|
25536
25868
|
});
|
|
25869
|
+
await applyRequestedEffort({
|
|
25870
|
+
setup,
|
|
25871
|
+
acpSessionId: nextSessionId,
|
|
25872
|
+
requestedEffort: options.requestedEffort,
|
|
25873
|
+
expectedGeneration
|
|
25874
|
+
});
|
|
25537
25875
|
if (options.beforeApplyResult) {
|
|
25538
25876
|
await options.beforeApplyResult();
|
|
25539
25877
|
}
|
|
@@ -25898,6 +26236,26 @@ function createAcpExecutor(options) {
|
|
|
25898
26236
|
};
|
|
25899
26237
|
apply();
|
|
25900
26238
|
};
|
|
26239
|
+
const setNativeMode = async (modeId) => {
|
|
26240
|
+
failIfDisposed();
|
|
26241
|
+
const started = startResult;
|
|
26242
|
+
if (started === void 0) {
|
|
26243
|
+
throw new AcpExecutorRequestError("session/set_mode", "session has not started yet");
|
|
26244
|
+
}
|
|
26245
|
+
const configId = acpModeConfigId(started.sessionSetupResult);
|
|
26246
|
+
if (configId !== void 0) {
|
|
26247
|
+
await connection.request("session/set_config_option", {
|
|
26248
|
+
sessionId: started.sessionId,
|
|
26249
|
+
configId,
|
|
26250
|
+
value: modeId
|
|
26251
|
+
});
|
|
26252
|
+
return;
|
|
26253
|
+
}
|
|
26254
|
+
await connection.request("session/set_mode", {
|
|
26255
|
+
sessionId: started.sessionId,
|
|
26256
|
+
modeId
|
|
26257
|
+
});
|
|
26258
|
+
};
|
|
25901
26259
|
const respondToUserInput = async (requestId, answers) => {
|
|
25902
26260
|
failIfDisposed();
|
|
25903
26261
|
const pending = pendingUserInputs.get(requestId);
|
|
@@ -25914,7 +26272,7 @@ function createAcpExecutor(options) {
|
|
|
25914
26272
|
pendingUserInputs.delete(requestId);
|
|
25915
26273
|
pending.resolve({
|
|
25916
26274
|
kind: "answered",
|
|
25917
|
-
answers:
|
|
26275
|
+
answers: isRecord5(answers) ? answers : {}
|
|
25918
26276
|
});
|
|
25919
26277
|
};
|
|
25920
26278
|
const dispose = async () => {
|
|
@@ -25964,10 +26322,53 @@ function createAcpExecutor(options) {
|
|
|
25964
26322
|
cancel,
|
|
25965
26323
|
respondToRequest,
|
|
25966
26324
|
respondToUserInput,
|
|
26325
|
+
setNativeMode,
|
|
25967
26326
|
dispose
|
|
25968
26327
|
};
|
|
25969
26328
|
}
|
|
25970
26329
|
|
|
26330
|
+
// ../../packages/ycodium-acp-executor/src/probe.ts
|
|
26331
|
+
function withProbeTimeout(promise2, timeoutMs, method) {
|
|
26332
|
+
return new Promise((resolve, reject) => {
|
|
26333
|
+
const timer = setTimeout(() => {
|
|
26334
|
+
reject(new Error(`ACP probe request '${method}' timed out after ${timeoutMs}ms`));
|
|
26335
|
+
}, timeoutMs);
|
|
26336
|
+
timer.unref?.();
|
|
26337
|
+
promise2.then(
|
|
26338
|
+
(value) => {
|
|
26339
|
+
clearTimeout(timer);
|
|
26340
|
+
resolve(value);
|
|
26341
|
+
},
|
|
26342
|
+
(error62) => {
|
|
26343
|
+
clearTimeout(timer);
|
|
26344
|
+
reject(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
26345
|
+
}
|
|
26346
|
+
);
|
|
26347
|
+
});
|
|
26348
|
+
}
|
|
26349
|
+
async function openAcpProbeHandshake(input2) {
|
|
26350
|
+
const connection = createAcpConnection({
|
|
26351
|
+
readable: input2.readable,
|
|
26352
|
+
writable: input2.writable,
|
|
26353
|
+
onNotification: () => void 0
|
|
26354
|
+
});
|
|
26355
|
+
try {
|
|
26356
|
+
const initializeResult = await withProbeTimeout(
|
|
26357
|
+
connection.request("initialize", acpInitializePayload(input2.clientInfo)),
|
|
26358
|
+
input2.requestTimeoutMs,
|
|
26359
|
+
"initialize"
|
|
26360
|
+
);
|
|
26361
|
+
return {
|
|
26362
|
+
initializeResult,
|
|
26363
|
+
request: (method, params) => withProbeTimeout(connection.request(method, params), input2.requestTimeoutMs, method),
|
|
26364
|
+
close: () => connection.close()
|
|
26365
|
+
};
|
|
26366
|
+
} catch (error62) {
|
|
26367
|
+
await connection.close().catch(() => void 0);
|
|
26368
|
+
throw error62;
|
|
26369
|
+
}
|
|
26370
|
+
}
|
|
26371
|
+
|
|
25971
26372
|
// src/card.ts
|
|
25972
26373
|
var ACP_DRIVER_KIND = "acp";
|
|
25973
26374
|
var ACP_CARD = {
|
|
@@ -25999,7 +26400,21 @@ var ACP_CARD = {
|
|
|
25999
26400
|
everydayHarness: false,
|
|
26000
26401
|
capabilities: {
|
|
26001
26402
|
sessionModelSwitch: "unsupported",
|
|
26002
|
-
|
|
26403
|
+
// **这一位仍是空头支票,切档走的是下面那位。** `setRuntimeMode` 在这里只改自己的
|
|
26404
|
+
// 会话记录,从不发 RPC——宿主四档发不到 CLI 上。它没删是因为编排还在读它(哪些手
|
|
26405
|
+
// 要重开会话),但用户真正切得动的是 `nativeModeSwitch` 那条:这只手自报几档、
|
|
26406
|
+
// 界面画几档、选哪档发哪档,不经四档翻译(各家语义本来就对不齐:grok 的
|
|
26407
|
+
// `acceptEdits` 实测等同 `default`,照样问)。
|
|
26408
|
+
runtimeModeSwitch: "in-session",
|
|
26409
|
+
// 能中途切自报的那几档。`setNativeMode` 按 agent 报的形状挑通道:报了
|
|
26410
|
+
// `configOptions` 里 `category: "mode"` 那一项就走 `session/set_config_option`
|
|
26411
|
+
// (claude-agent-acp),否则走 `session/set_mode`。
|
|
26412
|
+
//
|
|
26413
|
+
// 两条路都实测过:kimi `acp` 的 `session/set_mode plan` 回 `{}` 并推
|
|
26414
|
+
// `current_mode_update`,不存在的 modeId 被 `-32602 Unknown modeId` 拒掉——不是
|
|
26415
|
+
// Grok 那种「收下任何 modeId 都回 {}」的静默无效。dsh 两条都没有(`-32601`),
|
|
26416
|
+
// 所以它不声明这一位。
|
|
26417
|
+
nativeModeSwitch: true
|
|
26003
26418
|
},
|
|
26004
26419
|
credentialSources: [],
|
|
26005
26420
|
diagnostics: [],
|
|
@@ -26022,12 +26437,20 @@ var ACP_CARD = {
|
|
|
26022
26437
|
},
|
|
26023
26438
|
modelConnectivity: {
|
|
26024
26439
|
dialects: ["anthropic-messages", "openai-responses", "openai-chat-completions"],
|
|
26025
|
-
|
|
26440
|
+
// **通用 ACP 这张名片接不了外部端点,而且接不了是对的。** ACP 协议本身没有端点
|
|
26441
|
+
// 概念,地址与钥匙全靠各家 CLI 自己的环境变量,五家各不相同(kimi 的
|
|
26442
|
+
// `KIMI_MODEL_*`、qwen 的 `OPENAI_*`、gemini 的 `GOOGLE_GEMINI_*`……)。这张名片
|
|
26443
|
+
// 是认不出是哪一家时的兜底,它不知道该注什么。
|
|
26444
|
+
//
|
|
26445
|
+
// 原来这里写着 `true` 却一栏开关都不给——名片对外宣称能接,实际绑定时报一个含糊
|
|
26446
|
+
// 的 `driver-unknown`,而提案 0025 的进度表据此把 kimi 记成「通」。哪家要接,就为
|
|
26447
|
+
// 那一家单出一张名片(`resolveByLocator` 按启动命令认家),别回来改这一张。
|
|
26448
|
+
acceptsExternalEndpoints: false
|
|
26026
26449
|
}
|
|
26027
26450
|
};
|
|
26028
26451
|
|
|
26029
26452
|
// src/config.ts
|
|
26030
|
-
function
|
|
26453
|
+
function isRecord6(value) {
|
|
26031
26454
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26032
26455
|
}
|
|
26033
26456
|
function readString(value) {
|
|
@@ -26040,7 +26463,7 @@ function readEnvironment(value) {
|
|
|
26040
26463
|
if (!Array.isArray(value)) return {};
|
|
26041
26464
|
const env = {};
|
|
26042
26465
|
for (const entry of value) {
|
|
26043
|
-
if (!
|
|
26466
|
+
if (!isRecord6(entry)) continue;
|
|
26044
26467
|
const name = readTrimmed(entry["name"]);
|
|
26045
26468
|
if (name.length === 0) continue;
|
|
26046
26469
|
env[name] = readString(entry["value"]);
|
|
@@ -26048,17 +26471,18 @@ function readEnvironment(value) {
|
|
|
26048
26471
|
return env;
|
|
26049
26472
|
}
|
|
26050
26473
|
function parseAcpInstanceConfig(config2) {
|
|
26051
|
-
if (!
|
|
26474
|
+
if (!isRecord6(config2)) {
|
|
26052
26475
|
return {
|
|
26053
26476
|
binaryPath: "",
|
|
26054
26477
|
launchArgs: "",
|
|
26055
26478
|
homePath: "",
|
|
26056
26479
|
homeEnvVar: "",
|
|
26057
26480
|
environment: {},
|
|
26058
|
-
envelopeDriver: void 0
|
|
26481
|
+
envelopeDriver: void 0,
|
|
26482
|
+
providerId: ""
|
|
26059
26483
|
};
|
|
26060
26484
|
}
|
|
26061
|
-
const nested =
|
|
26485
|
+
const nested = isRecord6(config2["config"]) ? config2["config"] : void 0;
|
|
26062
26486
|
const settings = nested ?? config2;
|
|
26063
26487
|
return {
|
|
26064
26488
|
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
@@ -26066,7 +26490,8 @@ function parseAcpInstanceConfig(config2) {
|
|
|
26066
26490
|
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config2["homePath"]),
|
|
26067
26491
|
homeEnvVar: readTrimmed(settings["homeEnvVar"]) || readTrimmed(config2["homeEnvVar"]),
|
|
26068
26492
|
environment: readEnvironment(config2["environment"]),
|
|
26069
|
-
envelopeDriver: readTrimmed(config2["driver"]) || void 0
|
|
26493
|
+
envelopeDriver: readTrimmed(config2["driver"]) || void 0,
|
|
26494
|
+
providerId: readTrimmed(settings["providerId"]) || readTrimmed(config2["providerId"])
|
|
26070
26495
|
};
|
|
26071
26496
|
}
|
|
26072
26497
|
function tokenizeLaunchArgs(value) {
|
|
@@ -26121,57 +26546,372 @@ function tokenizeLaunchArgs(value) {
|
|
|
26121
26546
|
return tokens;
|
|
26122
26547
|
}
|
|
26123
26548
|
|
|
26124
|
-
// src/
|
|
26125
|
-
import * as
|
|
26126
|
-
|
|
26127
|
-
|
|
26128
|
-
|
|
26549
|
+
// src/kimi.ts
|
|
26550
|
+
import * as NodeFS from "node:fs";
|
|
26551
|
+
import * as NodePath from "node:path";
|
|
26552
|
+
var KIMI_PROVIDER_ID = "kimiCode";
|
|
26553
|
+
var KIMI_HOME_ENV_VAR = "KIMI_CODE_HOME";
|
|
26554
|
+
var KIMI_USER_INPUT_TITLES = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
|
|
26555
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26556
|
+
function questionTextFromContent(content) {
|
|
26557
|
+
if (!Array.isArray(content)) return "";
|
|
26558
|
+
const parts = [];
|
|
26559
|
+
for (const entry of content) {
|
|
26560
|
+
if (!isRecord7(entry) || entry["type"] !== "content") continue;
|
|
26561
|
+
const inner = entry["content"];
|
|
26562
|
+
if (!isRecord7(inner) || inner["type"] !== "text") continue;
|
|
26563
|
+
const text = inner["text"];
|
|
26564
|
+
if (typeof text === "string") parts.push(text);
|
|
26565
|
+
}
|
|
26566
|
+
return parts.join("\n\n").trim();
|
|
26567
|
+
}
|
|
26568
|
+
function kimiPermissionUserInput(request) {
|
|
26569
|
+
const title = request.toolCall.title;
|
|
26570
|
+
if (typeof title !== "string" || !KIMI_USER_INPUT_TITLES.has(title)) return void 0;
|
|
26571
|
+
const ids = new Set(request.options.map((option) => option.optionId));
|
|
26572
|
+
if (request.options.length === 0 || ids.size !== request.options.length) {
|
|
26573
|
+
throw new Error("Kimi interaction must provide distinct response options.");
|
|
26574
|
+
}
|
|
26575
|
+
const question = questionTextFromContent(request.toolCall.content);
|
|
26576
|
+
if (question.length === 0) {
|
|
26577
|
+
throw new Error("Kimi interaction is missing a question or plan.");
|
|
26578
|
+
}
|
|
26579
|
+
return {
|
|
26580
|
+
id: request.toolCall.toolCallId,
|
|
26581
|
+
header: title,
|
|
26582
|
+
question,
|
|
26583
|
+
kind: title === "ExitPlanMode" ? "plan" : "question",
|
|
26584
|
+
allowFreeform: false,
|
|
26585
|
+
multiSelect: false,
|
|
26586
|
+
options: request.options.map((option) => ({
|
|
26587
|
+
id: option.optionId,
|
|
26588
|
+
label: option.name,
|
|
26589
|
+
description: ""
|
|
26590
|
+
}))
|
|
26591
|
+
};
|
|
26592
|
+
}
|
|
26593
|
+
var WIRE_LOG_SEGMENTS = ["agents", "main", "wire.jsonl"];
|
|
26594
|
+
var SESSIONS_DIR = "sessions";
|
|
26595
|
+
var TAIL_SCAN_BYTES = 256 * 1024;
|
|
26596
|
+
var positiveInt = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
26597
|
+
function parseKimiContextWindow(contents) {
|
|
26598
|
+
let usedTokens;
|
|
26599
|
+
let maxTokens;
|
|
26600
|
+
for (const line of contents.split("\n")) {
|
|
26601
|
+
const trimmed = line.trim();
|
|
26602
|
+
if (trimmed.length === 0) continue;
|
|
26603
|
+
let record2;
|
|
26129
26604
|
try {
|
|
26130
|
-
|
|
26131
|
-
|
|
26132
|
-
|
|
26133
|
-
await new Promise((resolve) => {
|
|
26134
|
-
const onDone = () => {
|
|
26135
|
-
readable.off("drain", onDone);
|
|
26136
|
-
readable.off("close", onDone);
|
|
26137
|
-
resolve();
|
|
26138
|
-
};
|
|
26139
|
-
readable.once("drain", onDone);
|
|
26140
|
-
readable.once("close", onDone);
|
|
26141
|
-
});
|
|
26142
|
-
}
|
|
26143
|
-
}
|
|
26144
|
-
} catch (error62) {
|
|
26145
|
-
readable.destroy(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
26146
|
-
return;
|
|
26605
|
+
record2 = JSON.parse(trimmed);
|
|
26606
|
+
} catch {
|
|
26607
|
+
continue;
|
|
26147
26608
|
}
|
|
26148
|
-
if (
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
})().catch(() => void 0);
|
|
26154
|
-
const writable = new NodeStream2.Writable({
|
|
26155
|
-
write(chunk, _encoding, callback) {
|
|
26156
|
-
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
26157
|
-
handle.writeStdin(bytes).then(
|
|
26158
|
-
() => callback(),
|
|
26159
|
-
(error62) => callback(error62 instanceof Error ? error62 : new Error(String(error62)))
|
|
26160
|
-
);
|
|
26161
|
-
},
|
|
26162
|
-
final(callback) {
|
|
26163
|
-
handle.closeStdin().then(
|
|
26164
|
-
() => callback(),
|
|
26165
|
-
(error62) => callback(error62 instanceof Error ? error62 : new Error(String(error62)))
|
|
26166
|
-
);
|
|
26609
|
+
if (!isRecord7(record2)) continue;
|
|
26610
|
+
const type = record2["type"];
|
|
26611
|
+
if (type === "token_counting.turn_recorded" || type === "token_counting.measured") {
|
|
26612
|
+
usedTokens = positiveInt(record2["tokens"]) ?? usedTokens;
|
|
26613
|
+
continue;
|
|
26167
26614
|
}
|
|
26615
|
+
if (type === "llm.request") {
|
|
26616
|
+
maxTokens = positiveInt(record2["maxTokens"]) ?? maxTokens;
|
|
26617
|
+
}
|
|
26618
|
+
}
|
|
26619
|
+
if (usedTokens === void 0) return void 0;
|
|
26620
|
+
return maxTokens === void 0 ? { usedTokens } : { usedTokens, maxTokens };
|
|
26621
|
+
}
|
|
26622
|
+
function readTail(filePath) {
|
|
26623
|
+
let handle;
|
|
26624
|
+
try {
|
|
26625
|
+
const size = NodeFS.statSync(filePath).size;
|
|
26626
|
+
if (!Number.isFinite(size) || size <= 0) return void 0;
|
|
26627
|
+
const length = size > TAIL_SCAN_BYTES ? TAIL_SCAN_BYTES : size;
|
|
26628
|
+
const buffer = Buffer.alloc(length);
|
|
26629
|
+
handle = NodeFS.openSync(filePath, "r");
|
|
26630
|
+
NodeFS.readSync(handle, buffer, 0, length, size - length);
|
|
26631
|
+
return buffer.toString("utf8");
|
|
26632
|
+
} catch {
|
|
26633
|
+
return void 0;
|
|
26634
|
+
} finally {
|
|
26635
|
+
if (handle !== void 0) {
|
|
26636
|
+
try {
|
|
26637
|
+
NodeFS.closeSync(handle);
|
|
26638
|
+
} catch {
|
|
26639
|
+
}
|
|
26640
|
+
}
|
|
26641
|
+
}
|
|
26642
|
+
}
|
|
26643
|
+
function findKimiSessionWireLog(input2) {
|
|
26644
|
+
const sessionsRoot = NodePath.join(input2.homePath, SESSIONS_DIR);
|
|
26645
|
+
let workspaces;
|
|
26646
|
+
try {
|
|
26647
|
+
workspaces = NodeFS.readdirSync(sessionsRoot);
|
|
26648
|
+
} catch {
|
|
26649
|
+
return void 0;
|
|
26650
|
+
}
|
|
26651
|
+
for (const workspace of workspaces) {
|
|
26652
|
+
const candidate = NodePath.join(
|
|
26653
|
+
sessionsRoot,
|
|
26654
|
+
workspace,
|
|
26655
|
+
input2.acpSessionId,
|
|
26656
|
+
...WIRE_LOG_SEGMENTS
|
|
26657
|
+
);
|
|
26658
|
+
if (NodeFS.existsSync(candidate)) return candidate;
|
|
26659
|
+
}
|
|
26660
|
+
return void 0;
|
|
26661
|
+
}
|
|
26662
|
+
function readKimiContextWindow(input2) {
|
|
26663
|
+
if (input2.homePath.trim().length === 0) return void 0;
|
|
26664
|
+
const wireLog = findKimiSessionWireLog(input2);
|
|
26665
|
+
if (wireLog === void 0) return void 0;
|
|
26666
|
+
const contents = readTail(wireLog);
|
|
26667
|
+
return contents === void 0 ? void 0 : parseKimiContextWindow(contents);
|
|
26668
|
+
}
|
|
26669
|
+
|
|
26670
|
+
// src/kimiModels.ts
|
|
26671
|
+
var PROBE_TIMEOUT_MS = 15e3;
|
|
26672
|
+
var MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
26673
|
+
var KIMI_MODEL_LIST_ARGS = ["provider", "list", "--json"];
|
|
26674
|
+
function isRecord8(value) {
|
|
26675
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26676
|
+
}
|
|
26677
|
+
function asString3(value) {
|
|
26678
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
26679
|
+
}
|
|
26680
|
+
function positiveInt2(value) {
|
|
26681
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
26682
|
+
}
|
|
26683
|
+
function kimiProbeModels(stdout) {
|
|
26684
|
+
let parsed;
|
|
26685
|
+
try {
|
|
26686
|
+
parsed = JSON.parse(stdout);
|
|
26687
|
+
} catch {
|
|
26688
|
+
return void 0;
|
|
26689
|
+
}
|
|
26690
|
+
if (!isRecord8(parsed)) return void 0;
|
|
26691
|
+
const models = parsed["models"];
|
|
26692
|
+
if (!isRecord8(models)) return void 0;
|
|
26693
|
+
const out = [];
|
|
26694
|
+
for (const [slug, entry] of Object.entries(models)) {
|
|
26695
|
+
const trimmed = slug.trim();
|
|
26696
|
+
if (trimmed.length === 0 || !isRecord8(entry)) continue;
|
|
26697
|
+
const name = asString3(entry["displayName"]);
|
|
26698
|
+
const contextWindow = positiveInt2(entry["maxContextSize"]);
|
|
26699
|
+
out.push({
|
|
26700
|
+
slug: trimmed,
|
|
26701
|
+
...name === void 0 ? {} : { name },
|
|
26702
|
+
...contextWindow === void 0 ? {} : { contextWindow }
|
|
26703
|
+
});
|
|
26704
|
+
}
|
|
26705
|
+
return out;
|
|
26706
|
+
}
|
|
26707
|
+
function withProbeTimeout2(promise2, what) {
|
|
26708
|
+
return new Promise((resolve, reject) => {
|
|
26709
|
+
const timer = setTimeout(
|
|
26710
|
+
() => reject(new Error(`${what} timed out after ${PROBE_TIMEOUT_MS}ms`)),
|
|
26711
|
+
PROBE_TIMEOUT_MS
|
|
26712
|
+
);
|
|
26713
|
+
timer.unref?.();
|
|
26714
|
+
promise2.then(
|
|
26715
|
+
(value) => {
|
|
26716
|
+
clearTimeout(timer);
|
|
26717
|
+
resolve(value);
|
|
26718
|
+
},
|
|
26719
|
+
(error62) => {
|
|
26720
|
+
clearTimeout(timer);
|
|
26721
|
+
reject(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
26722
|
+
}
|
|
26723
|
+
);
|
|
26168
26724
|
});
|
|
26169
|
-
|
|
26725
|
+
}
|
|
26726
|
+
function concat(chunks) {
|
|
26727
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
|
26728
|
+
const out = new Uint8Array(total);
|
|
26729
|
+
let offset = 0;
|
|
26730
|
+
for (const chunk of chunks) {
|
|
26731
|
+
out.set(chunk, offset);
|
|
26732
|
+
offset += chunk.byteLength;
|
|
26733
|
+
}
|
|
26734
|
+
return out;
|
|
26735
|
+
}
|
|
26736
|
+
async function probeKimiModels(input2) {
|
|
26737
|
+
const { recipe, host, env } = input2;
|
|
26738
|
+
if (recipe.binaryPath.length === 0) return void 0;
|
|
26739
|
+
let handle;
|
|
26740
|
+
try {
|
|
26741
|
+
handle = await host.process.spawn({
|
|
26742
|
+
program: recipe.binaryPath,
|
|
26743
|
+
// 实例信封里的启动参数(Kimi 那行预填 `acp`)在这一栏用不上:读配置要换成
|
|
26744
|
+
// `provider list --json`,留着 `acp` 就等于让它起 ACP 服务然后什么都不问。
|
|
26745
|
+
args: KIMI_MODEL_LIST_ARGS,
|
|
26746
|
+
cwd: process.cwd(),
|
|
26747
|
+
owner: { bindingId: host.bindingId },
|
|
26748
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
26749
|
+
});
|
|
26750
|
+
const spawned = handle;
|
|
26751
|
+
const collect = withProbeTimeout2(
|
|
26752
|
+
(async () => {
|
|
26753
|
+
const chunks = [];
|
|
26754
|
+
let total = 0;
|
|
26755
|
+
for await (const chunk of spawned.stdout) {
|
|
26756
|
+
total += chunk.byteLength;
|
|
26757
|
+
if (total > MAX_OUTPUT_BYTES) return void 0;
|
|
26758
|
+
chunks.push(chunk);
|
|
26759
|
+
}
|
|
26760
|
+
return new TextDecoder().decode(concat(chunks));
|
|
26761
|
+
})(),
|
|
26762
|
+
"kimi provider list"
|
|
26763
|
+
);
|
|
26764
|
+
const drain = (async () => {
|
|
26765
|
+
for await (const _chunk of spawned.stderr) {
|
|
26766
|
+
}
|
|
26767
|
+
})().catch(() => void 0);
|
|
26768
|
+
const [stdout, , exitCode] = await Promise.all([collect, drain, spawned.exited]);
|
|
26769
|
+
if (stdout === void 0) return void 0;
|
|
26770
|
+
if (exitCode !== 0) return void 0;
|
|
26771
|
+
return kimiProbeModels(stdout);
|
|
26772
|
+
} catch {
|
|
26773
|
+
return void 0;
|
|
26774
|
+
} finally {
|
|
26775
|
+
await handle?.kill("SIGTERM").catch(() => void 0);
|
|
26776
|
+
}
|
|
26777
|
+
}
|
|
26778
|
+
|
|
26779
|
+
// src/probeModels.ts
|
|
26780
|
+
import * as NodeFS2 from "node:fs";
|
|
26781
|
+
import * as NodeOS from "node:os";
|
|
26782
|
+
import * as NodePath2 from "node:path";
|
|
26783
|
+
import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
|
|
26784
|
+
var PROBE_REQUEST_TIMEOUT_MS = 15e3;
|
|
26785
|
+
var CLIENT_INFO = { name: "ycodium-agent-acp-probe", version: "0.2.0" };
|
|
26786
|
+
var ACP_EFFORT_OPTION_ID = "reasoning";
|
|
26787
|
+
function acpProbeSessionCwd(instanceId) {
|
|
26788
|
+
const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
26789
|
+
return NodePath2.join(NodeOS.tmpdir(), `ycodium-acp-probe-${safe}`);
|
|
26790
|
+
}
|
|
26791
|
+
function isRecord9(value) {
|
|
26792
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26793
|
+
}
|
|
26794
|
+
function asString4(value) {
|
|
26795
|
+
return typeof value === "string" ? value : void 0;
|
|
26796
|
+
}
|
|
26797
|
+
function findAcpProbeSessionId(listed, probeCwd) {
|
|
26798
|
+
if (!isRecord9(listed) || !Array.isArray(listed["sessions"])) return void 0;
|
|
26799
|
+
for (const entry of listed["sessions"]) {
|
|
26800
|
+
if (!isRecord9(entry)) continue;
|
|
26801
|
+
if (asString4(entry["cwd"]) !== probeCwd) continue;
|
|
26802
|
+
const sessionId = asString4(entry["sessionId"]);
|
|
26803
|
+
if (sessionId !== void 0) return sessionId;
|
|
26804
|
+
}
|
|
26805
|
+
return void 0;
|
|
26806
|
+
}
|
|
26807
|
+
async function probeSessionSetup(handshake, probeCwd) {
|
|
26808
|
+
const listed = await handshake.request("session/list", {}).catch(() => void 0);
|
|
26809
|
+
const reusable = findAcpProbeSessionId(listed, probeCwd);
|
|
26810
|
+
if (reusable !== void 0) {
|
|
26811
|
+
const resumed = await handshake.request("session/resume", { sessionId: reusable, cwd: probeCwd, mcpServers: [] }).catch(() => void 0);
|
|
26812
|
+
if (resumed !== void 0) return resumed;
|
|
26813
|
+
}
|
|
26814
|
+
return handshake.request("session/new", { cwd: probeCwd, mcpServers: [] });
|
|
26815
|
+
}
|
|
26816
|
+
function acpProbeModels(setup) {
|
|
26817
|
+
if (!isRecord9(setup)) return void 0;
|
|
26818
|
+
const rawOptions = setup["configOptions"];
|
|
26819
|
+
const choices = acpModelChoicesFromConfigOptions(rawOptions) ?? acpModelChoicesFromSessionModels(setup["models"]);
|
|
26820
|
+
if (choices === void 0 || choices.length === 0) return void 0;
|
|
26821
|
+
const models = choices.map((choice) => ({
|
|
26822
|
+
slug: choice.value,
|
|
26823
|
+
...choice.name === void 0 ? {} : { name: choice.name },
|
|
26824
|
+
...choice.isDefault === true ? { isDefault: true } : {}
|
|
26825
|
+
}));
|
|
26826
|
+
const effort = findAcpEffortConfig(rawOptions);
|
|
26827
|
+
if (effort === void 0) return models;
|
|
26828
|
+
const capabilities = {
|
|
26829
|
+
optionDescriptors: [
|
|
26830
|
+
{
|
|
26831
|
+
id: ACP_EFFORT_OPTION_ID,
|
|
26832
|
+
label: effort.label || "Reasoning",
|
|
26833
|
+
type: "select",
|
|
26834
|
+
options: effort.choices.map((choice) => ({
|
|
26835
|
+
id: choice.value,
|
|
26836
|
+
label: choice.label,
|
|
26837
|
+
...choice.description === void 0 ? {} : { description: choice.description },
|
|
26838
|
+
...choice.isDefault === true ? { isDefault: true } : {}
|
|
26839
|
+
}))
|
|
26840
|
+
}
|
|
26841
|
+
]
|
|
26842
|
+
};
|
|
26843
|
+
return models.map((model) => ({ ...model, capabilities }));
|
|
26844
|
+
}
|
|
26845
|
+
var failureDetail = (error62) => (error62 instanceof Error ? error62.message : String(error62)).trim() || void 0;
|
|
26846
|
+
async function probeAcpModelsViaSession(input2) {
|
|
26847
|
+
const { recipe, host, env } = input2;
|
|
26848
|
+
const probeCwd = acpProbeSessionCwd(host.instanceId);
|
|
26849
|
+
try {
|
|
26850
|
+
NodeFS2.mkdirSync(probeCwd, { recursive: true });
|
|
26851
|
+
} catch (error62) {
|
|
26852
|
+
return { kind: "failed", detail: failureDetail(error62) };
|
|
26853
|
+
}
|
|
26854
|
+
let handle;
|
|
26855
|
+
try {
|
|
26856
|
+
handle = await host.process.spawn({
|
|
26857
|
+
program: recipe.binaryPath,
|
|
26858
|
+
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
26859
|
+
cwd: probeCwd,
|
|
26860
|
+
owner: { bindingId: host.bindingId },
|
|
26861
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
26862
|
+
});
|
|
26863
|
+
} catch (error62) {
|
|
26864
|
+
return { kind: "not-started", detail: failureDetail(error62) };
|
|
26865
|
+
}
|
|
26866
|
+
let handshake;
|
|
26867
|
+
try {
|
|
26868
|
+
const { readable, writable } = nodeStreamsFromHandle(handle);
|
|
26869
|
+
handshake = await openAcpProbeHandshake({
|
|
26870
|
+
readable,
|
|
26871
|
+
writable,
|
|
26872
|
+
clientInfo: CLIENT_INFO,
|
|
26873
|
+
requestTimeoutMs: PROBE_REQUEST_TIMEOUT_MS
|
|
26874
|
+
});
|
|
26875
|
+
const setup = await probeSessionSetup(handshake, probeCwd);
|
|
26876
|
+
return {
|
|
26877
|
+
kind: "answered",
|
|
26878
|
+
models: acpProbeModels(setup),
|
|
26879
|
+
// 审批档原样上报:宿主落进 provider 快照的 `nativeModes`,composer 直接画这只手
|
|
26880
|
+
// 自己的那几档,不再退回宿主四档开关。
|
|
26881
|
+
nativeModes: acpAvailableModes(setup).map((mode) => ({
|
|
26882
|
+
id: mode.id,
|
|
26883
|
+
name: mode.name,
|
|
26884
|
+
...mode.description === void 0 ? {} : { description: mode.description }
|
|
26885
|
+
})),
|
|
26886
|
+
currentNativeModeId: acpCurrentModeId(setup)
|
|
26887
|
+
};
|
|
26888
|
+
} catch (error62) {
|
|
26889
|
+
return { kind: "failed", detail: failureDetail(error62) };
|
|
26890
|
+
} finally {
|
|
26891
|
+
await handshake?.close().catch(() => void 0);
|
|
26892
|
+
await handle.kill("SIGTERM").catch(() => void 0);
|
|
26893
|
+
}
|
|
26894
|
+
}
|
|
26895
|
+
|
|
26896
|
+
// src/runtimeModeApproval.ts
|
|
26897
|
+
function acpRuntimeModeAutoApproves(runtimeMode, toolKind) {
|
|
26898
|
+
switch (runtimeMode) {
|
|
26899
|
+
case "full-access":
|
|
26900
|
+
return true;
|
|
26901
|
+
case "auto-accept-edits":
|
|
26902
|
+
return toolKind === "edit";
|
|
26903
|
+
case "approval-required":
|
|
26904
|
+
case "auto":
|
|
26905
|
+
return false;
|
|
26906
|
+
}
|
|
26907
|
+
}
|
|
26908
|
+
function acpSessionModeToApply(requestedNativeModeId, startedModeId) {
|
|
26909
|
+
return requestedNativeModeId !== void 0 && requestedNativeModeId !== startedModeId ? requestedNativeModeId : void 0;
|
|
26170
26910
|
}
|
|
26171
26911
|
|
|
26172
26912
|
// src/acpInstance.ts
|
|
26173
26913
|
var RESUME_SCHEMA_VERSION = 1;
|
|
26174
|
-
var
|
|
26914
|
+
var CLIENT_INFO2 = { name: "ycodium-agent-acp", version: "0.2.0" };
|
|
26175
26915
|
var yieldTick = () => new Promise((resolve) => {
|
|
26176
26916
|
setImmediate(resolve);
|
|
26177
26917
|
});
|
|
@@ -26208,19 +26948,12 @@ var EventBus = class {
|
|
|
26208
26948
|
}
|
|
26209
26949
|
};
|
|
26210
26950
|
function expandHomePath(value) {
|
|
26211
|
-
if (value === "~") return
|
|
26951
|
+
if (value === "~") return NodeOS2.homedir();
|
|
26212
26952
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
26213
|
-
return
|
|
26953
|
+
return NodePath3.join(NodeOS2.homedir(), value.slice(2));
|
|
26214
26954
|
}
|
|
26215
26955
|
return value;
|
|
26216
26956
|
}
|
|
26217
|
-
function compactEnv(env) {
|
|
26218
|
-
const out = {};
|
|
26219
|
-
for (const [key, value] of Object.entries(env)) {
|
|
26220
|
-
if (value !== void 0) out[key] = value;
|
|
26221
|
-
}
|
|
26222
|
-
return out;
|
|
26223
|
-
}
|
|
26224
26957
|
function modelIdFromSelection(selection) {
|
|
26225
26958
|
if (typeof selection !== "object" || selection === null || Array.isArray(selection)) {
|
|
26226
26959
|
return void 0;
|
|
@@ -26228,19 +26961,42 @@ function modelIdFromSelection(selection) {
|
|
|
26228
26961
|
const model = selection["model"];
|
|
26229
26962
|
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
26230
26963
|
}
|
|
26231
|
-
function buildSpawnEnv(recipe,
|
|
26232
|
-
const homePath =
|
|
26964
|
+
function buildSpawnEnv(recipe, configuredHomePath, launchEnv = {}) {
|
|
26965
|
+
const homePath = configuredHomePath.trim();
|
|
26233
26966
|
const homeEnvVar = recipe.homeEnvVar.trim();
|
|
26234
26967
|
const homeInjection = homePath.length > 0 && homeEnvVar.length > 0 ? { [homeEnvVar]: expandHomePath(homePath) } : {};
|
|
26235
|
-
return {
|
|
26236
|
-
|
|
26237
|
-
|
|
26238
|
-
|
|
26239
|
-
|
|
26968
|
+
return mergeLaunchEnv({
|
|
26969
|
+
brainSlots: brainSlotEnvKeys(ACP_CARD),
|
|
26970
|
+
accountHome: homeInjection,
|
|
26971
|
+
instanceTable: recipe.environment,
|
|
26972
|
+
launch: launchEnv
|
|
26973
|
+
});
|
|
26240
26974
|
}
|
|
26241
26975
|
function nowIso() {
|
|
26242
26976
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
26243
26977
|
}
|
|
26978
|
+
function resolveHomePath(recipe, launchHomePath) {
|
|
26979
|
+
const envVar = recipe.homeEnvVar.trim();
|
|
26980
|
+
const fromEnvironment = envVar.length > 0 ? recipe.environment[envVar]?.trim() : void 0;
|
|
26981
|
+
if (fromEnvironment !== void 0 && fromEnvironment.length > 0) {
|
|
26982
|
+
return expandHomePath(fromEnvironment);
|
|
26983
|
+
}
|
|
26984
|
+
const configured = (launchHomePath?.trim() || recipe.homePath).trim();
|
|
26985
|
+
return configured.length > 0 ? expandHomePath(configured) : "";
|
|
26986
|
+
}
|
|
26987
|
+
function isKimiInstance(recipe) {
|
|
26988
|
+
return recipe.providerId === KIMI_PROVIDER_ID || recipe.homeEnvVar.trim() === KIMI_HOME_ENV_VAR;
|
|
26989
|
+
}
|
|
26990
|
+
function vendorHooksFor(recipe, launchHomePath) {
|
|
26991
|
+
if (!isKimiInstance(recipe)) return void 0;
|
|
26992
|
+
const homePath = resolveHomePath(recipe, launchHomePath);
|
|
26993
|
+
return {
|
|
26994
|
+
permissionUserInput: kimiPermissionUserInput,
|
|
26995
|
+
// ACP 的 `usage_update` 我们这边不消费,进度圈只能从各家自己写在磁盘上的
|
|
26996
|
+
// 记录里读。目前只有 Kimi 的格式核实过。
|
|
26997
|
+
readContextWindow: ({ sessionId }) => readKimiContextWindow({ homePath, acpSessionId: sessionId })
|
|
26998
|
+
};
|
|
26999
|
+
}
|
|
26244
27000
|
async function stopBooked(booked) {
|
|
26245
27001
|
await booked.executor.dispose().catch(() => void 0);
|
|
26246
27002
|
await booked.handle.kill("SIGTERM").catch(() => void 0);
|
|
@@ -26267,11 +27023,33 @@ var createAcpInstance = (config2, host) => {
|
|
|
26267
27023
|
detail: "ACP program path is not configured"
|
|
26268
27024
|
};
|
|
26269
27025
|
}
|
|
27026
|
+
const outcome = isKimiInstance(recipe) ? {
|
|
27027
|
+
kind: "answered",
|
|
27028
|
+
models: await probeKimiModels({
|
|
27029
|
+
recipe,
|
|
27030
|
+
host,
|
|
27031
|
+
env: buildSpawnEnv(recipe, recipe.homePath)
|
|
27032
|
+
}),
|
|
27033
|
+
nativeModes: void 0,
|
|
27034
|
+
currentNativeModeId: void 0
|
|
27035
|
+
} : await probeAcpModelsViaSession({
|
|
27036
|
+
recipe,
|
|
27037
|
+
host,
|
|
27038
|
+
env: buildSpawnEnv(recipe, recipe.homePath)
|
|
27039
|
+
});
|
|
27040
|
+
const models = outcome.kind === "answered" ? outcome.models : void 0;
|
|
27041
|
+
const nativeModes = outcome.kind === "answered" && outcome.nativeModes !== void 0 ? outcome.nativeModes : void 0;
|
|
27042
|
+
const currentNativeModeId = outcome.kind === "answered" ? outcome.currentNativeModeId : void 0;
|
|
26270
27043
|
return {
|
|
26271
27044
|
installed: true,
|
|
26272
27045
|
version: null,
|
|
26273
27046
|
readiness: "unchecked",
|
|
26274
|
-
auth: { status: "unknown" }
|
|
27047
|
+
auth: { status: "unknown" },
|
|
27048
|
+
...models === void 0 ? {} : { models },
|
|
27049
|
+
...nativeModes === void 0 || nativeModes.length === 0 ? {} : {
|
|
27050
|
+
nativeModes,
|
|
27051
|
+
...currentNativeModeId === void 0 ? {} : { currentNativeModeId }
|
|
27052
|
+
}
|
|
26275
27053
|
};
|
|
26276
27054
|
},
|
|
26277
27055
|
startSession: async (input2, signal) => {
|
|
@@ -26287,7 +27065,11 @@ var createAcpInstance = (config2, host) => {
|
|
|
26287
27065
|
await stopBooked(existing);
|
|
26288
27066
|
threads.delete(input2.threadId);
|
|
26289
27067
|
}
|
|
26290
|
-
const env = buildSpawnEnv(
|
|
27068
|
+
const env = buildSpawnEnv(
|
|
27069
|
+
recipe,
|
|
27070
|
+
input2.launch.homePath?.trim() || recipe.homePath,
|
|
27071
|
+
input2.launch.processEnv
|
|
27072
|
+
);
|
|
26291
27073
|
const handle = await host.process.spawn({
|
|
26292
27074
|
program: recipe.binaryPath,
|
|
26293
27075
|
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
@@ -26295,19 +27077,32 @@ var createAcpInstance = (config2, host) => {
|
|
|
26295
27077
|
owner: { bindingId: host.bindingId },
|
|
26296
27078
|
...Object.keys(env).length > 0 ? { env } : {}
|
|
26297
27079
|
});
|
|
26298
|
-
const { readable, writable } =
|
|
27080
|
+
const { readable, writable } = nodeStreamsFromHandle2(handle);
|
|
26299
27081
|
const resume = input2.discardResumeCursor === true ? void 0 : parseAcpResumeCursor(input2.resumeCursor, RESUME_SCHEMA_VERSION);
|
|
26300
27082
|
const requestedModelId = input2.launch.requestedModelId?.trim() || modelIdFromSelection(input2.modelSelection);
|
|
27083
|
+
const requestedEffort = modelSelectionStringOption(
|
|
27084
|
+
input2.modelSelection,
|
|
27085
|
+
ACP_EFFORT_OPTION_ID
|
|
27086
|
+
);
|
|
27087
|
+
const hooks = vendorHooksFor(recipe, input2.launch.homePath);
|
|
27088
|
+
const autoApprove = input2.nativeModeId === void 0 ? (request) => acpRuntimeModeAutoApproves(
|
|
27089
|
+
threads.get(input2.threadId)?.session.runtimeMode ?? input2.runtimeMode,
|
|
27090
|
+
request.kind
|
|
27091
|
+
) : void 0;
|
|
26301
27092
|
const executor = createAcpExecutor({
|
|
26302
27093
|
readable,
|
|
26303
27094
|
writable,
|
|
27095
|
+
...requestedEffort === void 0 ? {} : { requestedEffort },
|
|
26304
27096
|
cwd,
|
|
26305
27097
|
threadId: input2.threadId,
|
|
26306
27098
|
provider: ACP_DRIVER_KIND,
|
|
26307
27099
|
providerInstanceId: host.instanceId,
|
|
26308
|
-
clientInfo:
|
|
27100
|
+
clientInfo: CLIENT_INFO2,
|
|
27101
|
+
log: host.log,
|
|
26309
27102
|
...requestedModelId === void 0 ? {} : { requestedModelId },
|
|
26310
27103
|
...input2.bindingGeneration === void 0 ? {} : { originBindingGeneration: input2.bindingGeneration },
|
|
27104
|
+
...hooks === void 0 ? {} : { hooks },
|
|
27105
|
+
...autoApprove === void 0 ? {} : { autoApprove },
|
|
26311
27106
|
...resume === void 0 ? {} : { resumeSessionId: resume.sessionId }
|
|
26312
27107
|
});
|
|
26313
27108
|
const forwarding = (async () => {
|
|
@@ -26317,6 +27112,13 @@ var createAcpInstance = (config2, host) => {
|
|
|
26317
27112
|
})();
|
|
26318
27113
|
try {
|
|
26319
27114
|
const started = await executor.start();
|
|
27115
|
+
const modeToApply = acpSessionModeToApply(
|
|
27116
|
+
input2.nativeModeId,
|
|
27117
|
+
acpCurrentModeId(started.sessionSetupResult)
|
|
27118
|
+
);
|
|
27119
|
+
if (modeToApply !== void 0) {
|
|
27120
|
+
await executor.setNativeMode(modeToApply);
|
|
27121
|
+
}
|
|
26320
27122
|
await yieldTick();
|
|
26321
27123
|
const createdAt = nowIso();
|
|
26322
27124
|
const resumeCursor = {
|
|
@@ -26328,6 +27130,7 @@ var createAcpInstance = (config2, host) => {
|
|
|
26328
27130
|
providerInstanceId: host.instanceId,
|
|
26329
27131
|
status: "idle",
|
|
26330
27132
|
runtimeMode: input2.runtimeMode,
|
|
27133
|
+
...input2.nativeModeId === void 0 ? {} : { nativeModeId: input2.nativeModeId },
|
|
26331
27134
|
cwd,
|
|
26332
27135
|
threadId: input2.threadId,
|
|
26333
27136
|
createdAt,
|
|
@@ -26407,8 +27210,25 @@ var createAcpInstance = (config2, host) => {
|
|
|
26407
27210
|
reason
|
|
26408
27211
|
);
|
|
26409
27212
|
},
|
|
26410
|
-
respondToUserInput: async () => {
|
|
26411
|
-
|
|
27213
|
+
respondToUserInput: async (threadId, requestId, answers) => {
|
|
27214
|
+
const booked = requireThread(threadId);
|
|
27215
|
+
await booked.executor.respondToUserInput(requestId, answers);
|
|
27216
|
+
},
|
|
27217
|
+
/**
|
|
27218
|
+
* 切这只手自报的审批档。`nativeModeId` 是它自己报的 id(探测时原样上报的那些),
|
|
27219
|
+
* 一路不翻译成宿主四档。
|
|
27220
|
+
*
|
|
27221
|
+
* 这是 `setRuntimeMode` 做不到的那一半:那个只改插件自己的会话记录,CLI 收不到
|
|
27222
|
+
* (`runtime-mode-never-reaches-cli` 记的那族缺陷)。
|
|
27223
|
+
*/
|
|
27224
|
+
setNativeMode: async (threadId, nativeModeId) => {
|
|
27225
|
+
const booked = requireThread(threadId);
|
|
27226
|
+
await booked.executor.setNativeMode(nativeModeId);
|
|
27227
|
+
booked.session = {
|
|
27228
|
+
...booked.session,
|
|
27229
|
+
nativeModeId,
|
|
27230
|
+
updatedAt: nowIso()
|
|
27231
|
+
};
|
|
26412
27232
|
},
|
|
26413
27233
|
setRuntimeMode: async (threadId, runtimeMode) => {
|
|
26414
27234
|
const booked = requireThread(threadId);
|