@ycodium-ai/agent-dsh 0.2.2092 → 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/dist/index.js +605 -123
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
|
9
9
|
|
|
10
10
|
// src/card.ts
|
|
11
11
|
var DSH_DRIVER_KIND = "dsh";
|
|
12
|
+
var DSH_CLIENT_INFO = { name: "ycodium-agent-dsh", version: "0.1.0" };
|
|
12
13
|
var DSH_CARD = {
|
|
13
14
|
driverKind: DSH_DRIVER_KIND,
|
|
14
15
|
displayName: "DeepSeek Harness",
|
|
@@ -30,6 +31,12 @@ var DSH_CARD = {
|
|
|
30
31
|
setupNote: "",
|
|
31
32
|
// 模型 id 是 agent 自家目录的 `provider/model` 对:只 trim,不做别名展开,
|
|
32
33
|
// 也没有默认值——空选择 = 保持 agent 起来时那个。
|
|
34
|
+
//
|
|
35
|
+
// **清单不靠这一栏兜底**:`probeDshModels` 每次探测都问 CLI 要那份目录
|
|
36
|
+
// (会话握手的 `configOptions`),报上来的是四个带名字的型号。这里留空是有意的:
|
|
37
|
+
// 编一个型号当兜底,等 CLI 换了目录就变成了发出去被拒的坏 id(grok 的名片上
|
|
38
|
+
// 有一条这样的兜底,代价写在它自己的注释里)。探测问不到时这双手就是没有清单,
|
|
39
|
+
// 界面按「机器没报模型」处理,比摆一个可能不对的型号诚实。
|
|
33
40
|
defaultModel: "",
|
|
34
41
|
defaultTextGenerationModel: "",
|
|
35
42
|
customModelIdExample: "",
|
|
@@ -47,6 +54,17 @@ var DSH_CARD = {
|
|
|
47
54
|
// DSH 换模型只有 `session/set_config_option` 一条路;库会按握手形状自动协商,
|
|
48
55
|
// 但插件侧的执行路径还没接到模型管理 UI,名片必须说实话。
|
|
49
56
|
sessionModelSwitch: "unsupported",
|
|
57
|
+
// **这一位今天是空头支票,别当它验过**(2026-09-19 拿真 `dsh --profile acp`
|
|
58
|
+
// 起一轮 ACP 会话实测)。两件事都不成立:
|
|
59
|
+
//
|
|
60
|
+
// 1. 本插件的 `setRuntimeMode` 只改自己的会话记录,一个字节都不发给 CLI——用户
|
|
61
|
+
// 中途切档,什么也没发生(与 Grok 那次 F8 同款缺陷)。
|
|
62
|
+
// 2. CLI 那头根本没有这条路:`session/new` 不报 `modes`,`session/set_mode` 回
|
|
63
|
+
// `-32601 "Method not found"`。所以照 kimi 那样接 `session/set_mode` 也没用,
|
|
64
|
+
// 得先查 dsh 自己有没有启动旗标(Grok 那条是 `--permission-mode`)。
|
|
65
|
+
//
|
|
66
|
+
// 改这一位要连着 `packages/contracts` 那张表一起改(`executorRegistry.test.ts`
|
|
67
|
+
// 的防漂移闸把两边钉成同值)。
|
|
50
68
|
runtimeModeSwitch: "in-session"
|
|
51
69
|
},
|
|
52
70
|
// 凭据由 CLI 自己保管在它 home 里,宿主不读 token。
|
|
@@ -85,8 +103,7 @@ var DSH_CARD = {
|
|
|
85
103
|
};
|
|
86
104
|
|
|
87
105
|
// src/dshInstance.ts
|
|
88
|
-
import
|
|
89
|
-
import * as NodePath from "node:path";
|
|
106
|
+
import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
|
|
90
107
|
|
|
91
108
|
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
92
109
|
import * as NodeCrypto from "node:crypto";
|
|
@@ -23956,6 +23973,12 @@ function acpApprovalOptions(request) {
|
|
|
23956
23973
|
}
|
|
23957
23974
|
return options;
|
|
23958
23975
|
}
|
|
23976
|
+
function selectAutoApprovedAcpPermissionOption(request) {
|
|
23977
|
+
if (new Set(request.options.map((option) => option.kind)).size !== request.options.length) {
|
|
23978
|
+
return void 0;
|
|
23979
|
+
}
|
|
23980
|
+
return selectAcpPermissionOptionId(request, "acceptForSession") ?? selectAcpPermissionOptionId(request, "accept");
|
|
23981
|
+
}
|
|
23959
23982
|
function parseAcpResumeCursor(raw, schemaVersion) {
|
|
23960
23983
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
23961
23984
|
const record2 = raw;
|
|
@@ -24338,7 +24361,7 @@ function makeAcpContentDeltaEvent(input2) {
|
|
|
24338
24361
|
...input2.turnId !== void 0 ? { turnId: input2.turnId } : {},
|
|
24339
24362
|
...input2.itemId ? { itemId: input2.itemId } : {},
|
|
24340
24363
|
payload: {
|
|
24341
|
-
streamKind: "assistant_text",
|
|
24364
|
+
streamKind: input2.streamKind ?? "assistant_text",
|
|
24342
24365
|
delta: input2.text
|
|
24343
24366
|
},
|
|
24344
24367
|
raw: {
|
|
@@ -24349,6 +24372,158 @@ function makeAcpContentDeltaEvent(input2) {
|
|
|
24349
24372
|
};
|
|
24350
24373
|
}
|
|
24351
24374
|
|
|
24375
|
+
// ../../packages/ycodium-acp-executor/src/config-options.ts
|
|
24376
|
+
function isRecord3(value) {
|
|
24377
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24378
|
+
}
|
|
24379
|
+
function asString(value) {
|
|
24380
|
+
return typeof value === "string" ? value : void 0;
|
|
24381
|
+
}
|
|
24382
|
+
function normalizedField(option, key) {
|
|
24383
|
+
return asString(option[key])?.trim().toLowerCase() ?? "";
|
|
24384
|
+
}
|
|
24385
|
+
function looksLikeEffortOption(option) {
|
|
24386
|
+
const id = normalizedField(option, "id");
|
|
24387
|
+
const name = normalizedField(option, "name");
|
|
24388
|
+
return id === "effort" || id === "reasoning" || name === "effort" || name === "reasoning" || name.includes("effort") || name.includes("reasoning") || normalizedField(option, "category") === "thought_level";
|
|
24389
|
+
}
|
|
24390
|
+
function flattenChoices(rawOptions, currentValue) {
|
|
24391
|
+
if (!Array.isArray(rawOptions)) return [];
|
|
24392
|
+
const out = [];
|
|
24393
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24394
|
+
const push = (entry) => {
|
|
24395
|
+
if (!isRecord3(entry)) return;
|
|
24396
|
+
const value = asString(entry["value"]);
|
|
24397
|
+
if (value === void 0 || seen.has(value)) return;
|
|
24398
|
+
seen.add(value);
|
|
24399
|
+
const description = asString(entry["description"])?.trim();
|
|
24400
|
+
const name = asString(entry["name"])?.trim();
|
|
24401
|
+
out.push({
|
|
24402
|
+
value,
|
|
24403
|
+
...name ? { name } : {},
|
|
24404
|
+
label: name || value,
|
|
24405
|
+
...description ? { description } : {},
|
|
24406
|
+
...currentValue !== void 0 && currentValue === value ? { isDefault: true } : {}
|
|
24407
|
+
});
|
|
24408
|
+
};
|
|
24409
|
+
for (const entry of rawOptions) {
|
|
24410
|
+
if (isRecord3(entry) && Array.isArray(entry["options"])) {
|
|
24411
|
+
for (const nested of entry["options"]) push(nested);
|
|
24412
|
+
continue;
|
|
24413
|
+
}
|
|
24414
|
+
push(entry);
|
|
24415
|
+
}
|
|
24416
|
+
return out;
|
|
24417
|
+
}
|
|
24418
|
+
function findAcpEffortConfig(configOptions) {
|
|
24419
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24420
|
+
const candidates = configOptions.filter(isRecord3).filter((option) => normalizedField(option, "type") === "select").filter(looksLikeEffortOption);
|
|
24421
|
+
if (candidates.length === 0) return void 0;
|
|
24422
|
+
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];
|
|
24423
|
+
if (picked === void 0) return void 0;
|
|
24424
|
+
const configId = asString(picked["id"])?.trim();
|
|
24425
|
+
if (!configId) return void 0;
|
|
24426
|
+
const choices = flattenChoices(picked["options"], asString(picked["currentValue"])?.trim());
|
|
24427
|
+
if (choices.length === 0) return void 0;
|
|
24428
|
+
return {
|
|
24429
|
+
configId,
|
|
24430
|
+
label: asString(picked["name"])?.trim() ?? "",
|
|
24431
|
+
choices
|
|
24432
|
+
};
|
|
24433
|
+
}
|
|
24434
|
+
function acpModelChoicesFromConfigOptions(configOptions) {
|
|
24435
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24436
|
+
const records = configOptions.filter(isRecord3);
|
|
24437
|
+
const modelOption = records.find((option) => normalizedField(option, "category") === "model");
|
|
24438
|
+
if (modelOption === void 0) return void 0;
|
|
24439
|
+
if (!asString(modelOption["id"])?.trim()) return void 0;
|
|
24440
|
+
return flattenChoices(modelOption["options"], asString(modelOption["currentValue"])?.trim());
|
|
24441
|
+
}
|
|
24442
|
+
|
|
24443
|
+
// ../../packages/ycodium-acp-executor/src/runtime-mode.ts
|
|
24444
|
+
function isRecord4(value) {
|
|
24445
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24446
|
+
}
|
|
24447
|
+
function asString2(value) {
|
|
24448
|
+
return typeof value === "string" ? value : void 0;
|
|
24449
|
+
}
|
|
24450
|
+
function acpModeConfigId(setup) {
|
|
24451
|
+
if (!isRecord4(setup)) return void 0;
|
|
24452
|
+
const configOptions = setup["configOptions"];
|
|
24453
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24454
|
+
for (const option of configOptions) {
|
|
24455
|
+
if (!isRecord4(option)) continue;
|
|
24456
|
+
if (asString2(option["category"])?.trim().toLowerCase() !== "mode") continue;
|
|
24457
|
+
const id = asString2(option["id"])?.trim();
|
|
24458
|
+
if (id) return id;
|
|
24459
|
+
}
|
|
24460
|
+
return void 0;
|
|
24461
|
+
}
|
|
24462
|
+
|
|
24463
|
+
// ../../packages/ycodium-acp-executor/src/handshake.ts
|
|
24464
|
+
function acpInitializePayload(clientInfo, overrides) {
|
|
24465
|
+
return {
|
|
24466
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
24467
|
+
clientCapabilities: {
|
|
24468
|
+
fs: {
|
|
24469
|
+
readTextFile: false,
|
|
24470
|
+
writeTextFile: false,
|
|
24471
|
+
...overrides?.fs
|
|
24472
|
+
},
|
|
24473
|
+
terminal: overrides?.terminal ?? false
|
|
24474
|
+
},
|
|
24475
|
+
clientInfo
|
|
24476
|
+
};
|
|
24477
|
+
}
|
|
24478
|
+
|
|
24479
|
+
// ../../packages/ycodium-acp-executor/src/config-option-wiring.ts
|
|
24480
|
+
var VENDOR_CATEGORY_PREFIX = "_";
|
|
24481
|
+
var ACP_CONFIG_CATEGORY_HANDLING = {
|
|
24482
|
+
mode: {
|
|
24483
|
+
consumed: true,
|
|
24484
|
+
via: "runtime-mode.ts\uFF1AacpAvailableModes / acpCurrentModeId / acpModeConfigId"
|
|
24485
|
+
},
|
|
24486
|
+
model: {
|
|
24487
|
+
consumed: true,
|
|
24488
|
+
via: "runtime-model.ts:extractModelConfigId \u2192 executor.ts:applyRequestedModel"
|
|
24489
|
+
},
|
|
24490
|
+
thought_level: {
|
|
24491
|
+
consumed: true,
|
|
24492
|
+
via: "config-options.ts:findAcpEffortConfig \u2192 executor.ts:applyRequestedEffort"
|
|
24493
|
+
},
|
|
24494
|
+
model_option: {
|
|
24495
|
+
consumed: true,
|
|
24496
|
+
// 精确说法:它不是**识别器**,是**优先级**。`looksLikeEffortOption` 先筛出候选,
|
|
24497
|
+
// 标了 `model_option` 的在候选里排第一(厂商自己标的最准),排在 id 叫 `effort`
|
|
24498
|
+
// 的和标 `thought_level` 的前面。光有这个 category 而 id/name 不像力度档的,
|
|
24499
|
+
// 压根进不了候选。
|
|
24500
|
+
via: "config-options.ts:findAcpEffortConfig\uFF08\u5019\u9009\u91CC\u7684\u6700\u9AD8\u4F18\u5148\u7EA7\uFF0C\u538B\u8FC7 thought_level\uFF09"
|
|
24501
|
+
},
|
|
24502
|
+
model_config: {
|
|
24503
|
+
consumed: false,
|
|
24504
|
+
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"
|
|
24505
|
+
}
|
|
24506
|
+
};
|
|
24507
|
+
var KNOWN_CATEGORIES = new Set(Object.keys(ACP_CONFIG_CATEGORY_HANDLING));
|
|
24508
|
+
function unhandledConfigCategories(configOptions) {
|
|
24509
|
+
if (!configOptions) return [];
|
|
24510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24511
|
+
const out = [];
|
|
24512
|
+
for (const option of configOptions) {
|
|
24513
|
+
const category = option.category?.trim();
|
|
24514
|
+
if (!category) continue;
|
|
24515
|
+
if (KNOWN_CATEGORIES.has(category)) continue;
|
|
24516
|
+
if (seen.has(category)) continue;
|
|
24517
|
+
seen.add(category);
|
|
24518
|
+
out.push({
|
|
24519
|
+
category,
|
|
24520
|
+
optionId: option.id.trim(),
|
|
24521
|
+
vendorExtension: category.startsWith(VENDOR_CATEGORY_PREFIX)
|
|
24522
|
+
});
|
|
24523
|
+
}
|
|
24524
|
+
return out;
|
|
24525
|
+
}
|
|
24526
|
+
|
|
24352
24527
|
// ../../packages/ycodium-acp-executor/src/mutex.ts
|
|
24353
24528
|
var Mutex = class {
|
|
24354
24529
|
locked = false;
|
|
@@ -24391,7 +24566,7 @@ var Mutex = class {
|
|
|
24391
24566
|
};
|
|
24392
24567
|
|
|
24393
24568
|
// ../../packages/ycodium-acp-executor/src/util.ts
|
|
24394
|
-
function
|
|
24569
|
+
function isRecord5(value) {
|
|
24395
24570
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24396
24571
|
}
|
|
24397
24572
|
function asTrimmedString(value) {
|
|
@@ -24437,11 +24612,11 @@ function extractCommandFromTitle(title) {
|
|
|
24437
24612
|
return backtickMatch?.[1]?.trim() || void 0;
|
|
24438
24613
|
}
|
|
24439
24614
|
function extractToolCommand(data, title) {
|
|
24440
|
-
const item =
|
|
24441
|
-
const itemInput = item &&
|
|
24442
|
-
const itemResult = item &&
|
|
24443
|
-
const rawInput =
|
|
24444
|
-
const dataInput =
|
|
24615
|
+
const item = isRecord5(data?.["item"]) ? data["item"] : void 0;
|
|
24616
|
+
const itemInput = item && isRecord5(item["input"]) ? item["input"] : void 0;
|
|
24617
|
+
const itemResult = item && isRecord5(item["result"]) ? item["result"] : void 0;
|
|
24618
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24619
|
+
const dataInput = isRecord5(data?.["input"]) ? data["input"] : void 0;
|
|
24445
24620
|
const candidates = [
|
|
24446
24621
|
normalizeCommandValue(item?.["command"]),
|
|
24447
24622
|
normalizeCommandValue(itemInput?.["command"]),
|
|
@@ -24486,7 +24661,7 @@ function collectPaths(value, paths, seen, depth) {
|
|
|
24486
24661
|
}
|
|
24487
24662
|
return;
|
|
24488
24663
|
}
|
|
24489
|
-
if (!
|
|
24664
|
+
if (!isRecord5(value)) {
|
|
24490
24665
|
return;
|
|
24491
24666
|
}
|
|
24492
24667
|
for (const key of ["path", "filePath", "relativePath", "filename", "newPath", "oldPath"]) {
|
|
@@ -24549,7 +24724,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24549
24724
|
const title = asTrimmedString(input2.title);
|
|
24550
24725
|
const detail = stripTrailingExitCode(asTrimmedString(input2.detail));
|
|
24551
24726
|
const fallbackSummary = asTrimmedString(input2.fallbackSummary) ?? "Tool";
|
|
24552
|
-
const data =
|
|
24727
|
+
const data = isRecord5(input2.data) ? input2.data : void 0;
|
|
24553
24728
|
const command = extractToolCommand(data, title);
|
|
24554
24729
|
const primaryPath = extractPrimaryPath(data);
|
|
24555
24730
|
const action = classifyToolAction({
|
|
@@ -24581,7 +24756,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24581
24756
|
};
|
|
24582
24757
|
}
|
|
24583
24758
|
if (action === "search") {
|
|
24584
|
-
const rawInput =
|
|
24759
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24585
24760
|
const query = asTrimmedString(rawInput?.["query"]) ?? asTrimmedString(rawInput?.["pattern"]) ?? asTrimmedString(rawInput?.["searchTerm"]);
|
|
24586
24761
|
return {
|
|
24587
24762
|
summary: "Searched files",
|
|
@@ -24620,6 +24795,46 @@ function findSessionConfigOption(configOptions, configId) {
|
|
|
24620
24795
|
}
|
|
24621
24796
|
return configOptions.find((option) => option.id.trim() === normalizedConfigId);
|
|
24622
24797
|
}
|
|
24798
|
+
function collectSessionConfigOptionValues(configOption) {
|
|
24799
|
+
if (configOption.type !== "select" || !configOption.options) {
|
|
24800
|
+
return [];
|
|
24801
|
+
}
|
|
24802
|
+
return configOption.options.flatMap(
|
|
24803
|
+
(entry) => "value" in entry ? [entry.value] : entry.options.map((option) => option.value)
|
|
24804
|
+
);
|
|
24805
|
+
}
|
|
24806
|
+
function collectSessionModelIds(models) {
|
|
24807
|
+
if (!isRecord5(models) || !Array.isArray(models["availableModels"])) {
|
|
24808
|
+
return [];
|
|
24809
|
+
}
|
|
24810
|
+
return models["availableModels"].flatMap(
|
|
24811
|
+
(model) => isRecord5(model) && typeof model["modelId"] === "string" ? [model["modelId"]] : []
|
|
24812
|
+
);
|
|
24813
|
+
}
|
|
24814
|
+
function catalogModelLastSegment(value) {
|
|
24815
|
+
if (value.startsWith("[")) {
|
|
24816
|
+
let parsed;
|
|
24817
|
+
try {
|
|
24818
|
+
parsed = JSON.parse(value);
|
|
24819
|
+
} catch {
|
|
24820
|
+
return void 0;
|
|
24821
|
+
}
|
|
24822
|
+
if (!Array.isArray(parsed) || parsed.length < 2) return void 0;
|
|
24823
|
+
const last = parsed[parsed.length - 1];
|
|
24824
|
+
return typeof last === "string" ? last : void 0;
|
|
24825
|
+
}
|
|
24826
|
+
const separator = value.indexOf("/");
|
|
24827
|
+
return separator > 0 && separator < value.length - 1 ? value.slice(separator + 1) : void 0;
|
|
24828
|
+
}
|
|
24829
|
+
function matchAdvertisedModelValue(requestedModelId, advertisedValues) {
|
|
24830
|
+
const wanted = requestedModelId.trim();
|
|
24831
|
+
if (!wanted) return void 0;
|
|
24832
|
+
if (advertisedValues.includes(wanted)) return wanted;
|
|
24833
|
+
const byLastSegment = advertisedValues.filter(
|
|
24834
|
+
(value) => catalogModelLastSegment(value) === wanted
|
|
24835
|
+
);
|
|
24836
|
+
return byLastSegment.length === 1 ? byLastSegment[0] : void 0;
|
|
24837
|
+
}
|
|
24623
24838
|
function parseSessionModeState(sessionResponse) {
|
|
24624
24839
|
const modes = sessionResponse.modes;
|
|
24625
24840
|
if (!modes) return void 0;
|
|
@@ -24658,7 +24873,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24658
24873
|
}
|
|
24659
24874
|
const commands = [];
|
|
24660
24875
|
for (const command of availableCommands) {
|
|
24661
|
-
if (!
|
|
24876
|
+
if (!isRecord5(command)) {
|
|
24662
24877
|
continue;
|
|
24663
24878
|
}
|
|
24664
24879
|
const name = typeof command["name"] === "string" ? command["name"].trim() : "";
|
|
@@ -24666,7 +24881,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24666
24881
|
continue;
|
|
24667
24882
|
}
|
|
24668
24883
|
const description = typeof command["description"] === "string" ? command["description"].trim() || void 0 : void 0;
|
|
24669
|
-
const input2 =
|
|
24884
|
+
const input2 = isRecord5(command["input"]) ? command["input"] : void 0;
|
|
24670
24885
|
const inputHint = typeof input2?.["hint"] === "string" ? input2["hint"].trim() || void 0 : void 0;
|
|
24671
24886
|
commands.push({
|
|
24672
24887
|
name,
|
|
@@ -24728,7 +24943,7 @@ function extractCommandFromTitle2(title) {
|
|
|
24728
24943
|
return match?.[1]?.trim() || void 0;
|
|
24729
24944
|
}
|
|
24730
24945
|
function extractToolCallCommand(rawInput, title) {
|
|
24731
|
-
if (
|
|
24946
|
+
if (isRecord5(rawInput)) {
|
|
24732
24947
|
const directCommand = normalizeCommandValue2(rawInput["command"]);
|
|
24733
24948
|
if (directCommand) {
|
|
24734
24949
|
return directCommand;
|
|
@@ -24755,7 +24970,7 @@ function boundToolCallOutputText(text) {
|
|
|
24755
24970
|
}
|
|
24756
24971
|
var RAW_OUTPUT_TEXT_FIELDS = ["content", "stdout", "stderr", "output"];
|
|
24757
24972
|
function boundToolCallRawOutput(rawOutput) {
|
|
24758
|
-
if (!
|
|
24973
|
+
if (!isRecord5(rawOutput)) {
|
|
24759
24974
|
return rawOutput;
|
|
24760
24975
|
}
|
|
24761
24976
|
let changed = false;
|
|
@@ -24985,7 +25200,7 @@ function parseSessionUpdateEvent(params) {
|
|
|
24985
25200
|
const entries = Array.isArray(upd["entries"]) ? upd["entries"] : [];
|
|
24986
25201
|
const plan = entries.map((entry, index) => ({
|
|
24987
25202
|
step: readAcpText(entry, "content") ?? `Step ${index + 1}`,
|
|
24988
|
-
status: normalizePlanStepStatus(
|
|
25203
|
+
status: normalizePlanStepStatus(isRecord5(entry) ? entry["status"] : void 0)
|
|
24989
25204
|
}));
|
|
24990
25205
|
if (plan.length > 0) {
|
|
24991
25206
|
events.push({
|
|
@@ -25022,21 +25237,24 @@ function parseSessionUpdateEvent(params) {
|
|
|
25022
25237
|
}
|
|
25023
25238
|
break;
|
|
25024
25239
|
}
|
|
25025
|
-
case "agent_message_chunk":
|
|
25026
|
-
|
|
25240
|
+
case "agent_message_chunk":
|
|
25241
|
+
case "agent_thought_chunk": {
|
|
25242
|
+
const content = isRecord5(upd["content"]) ? upd["content"] : void 0;
|
|
25027
25243
|
const contentType = content?.["type"];
|
|
25244
|
+
const streamKind = kind === "agent_thought_chunk" ? "reasoning_text" : "assistant_text";
|
|
25028
25245
|
if (contentType === "text") {
|
|
25029
25246
|
const text = typeof content?.["text"] === "string" ? content["text"] : "";
|
|
25030
25247
|
if (text.length > 0) {
|
|
25031
25248
|
events.push({
|
|
25032
25249
|
_tag: "ContentDelta",
|
|
25033
25250
|
text,
|
|
25251
|
+
streamKind,
|
|
25034
25252
|
rawPayload: params
|
|
25035
25253
|
});
|
|
25036
25254
|
}
|
|
25037
25255
|
break;
|
|
25038
25256
|
}
|
|
25039
|
-
if (content && contentType !== "audio") {
|
|
25257
|
+
if (streamKind === "assistant_text" && content && contentType !== "audio") {
|
|
25040
25258
|
events.push({
|
|
25041
25259
|
_tag: "AssistantContentBlock",
|
|
25042
25260
|
content,
|
|
@@ -25088,16 +25306,18 @@ function normalizeModelId(value) {
|
|
|
25088
25306
|
return value?.trim() || void 0;
|
|
25089
25307
|
}
|
|
25090
25308
|
function modelSelectionStateFromSetup(setup) {
|
|
25091
|
-
const sessionModels =
|
|
25309
|
+
const sessionModels = isRecord5(setup.models) ? setup.models : void 0;
|
|
25092
25310
|
const modelConfigId = extractModelConfigId(setup);
|
|
25093
25311
|
const strategy = sessionModels === void 0 && modelConfigId !== void 0 ? "config-option" : "session/set_model";
|
|
25094
|
-
const
|
|
25312
|
+
const modelConfigOption = modelConfigId === void 0 ? void 0 : findSessionConfigOption(setup.configOptions, modelConfigId);
|
|
25313
|
+
const configModel = modelConfigOption?.currentValue;
|
|
25095
25314
|
const currentModelId = strategy === "config-option" ? typeof configModel === "string" ? normalizeModelId(configModel) : void 0 : typeof sessionModels?.["currentModelId"] === "string" ? normalizeModelId(sessionModels["currentModelId"]) : void 0;
|
|
25096
25315
|
return {
|
|
25097
25316
|
strategy,
|
|
25098
25317
|
sessionModelsAdvertised: sessionModels !== void 0,
|
|
25099
25318
|
modelConfigId,
|
|
25100
|
-
currentModelId
|
|
25319
|
+
currentModelId,
|
|
25320
|
+
advertisedModelValues: strategy === "config-option" ? modelConfigOption === void 0 ? [] : collectSessionConfigOptionValues(modelConfigOption) : collectSessionModelIds(sessionModels)
|
|
25101
25321
|
};
|
|
25102
25322
|
}
|
|
25103
25323
|
function createAcpExecutor(options) {
|
|
@@ -25116,8 +25336,10 @@ function createAcpExecutor(options) {
|
|
|
25116
25336
|
strategy: "session/set_model",
|
|
25117
25337
|
sessionModelsAdvertised: false,
|
|
25118
25338
|
modelConfigId: void 0,
|
|
25119
|
-
currentModelId: void 0
|
|
25339
|
+
currentModelId: void 0,
|
|
25340
|
+
advertisedModelValues: []
|
|
25120
25341
|
};
|
|
25342
|
+
let lastUnmatchedModelId;
|
|
25121
25343
|
let initializeResult;
|
|
25122
25344
|
let startResult;
|
|
25123
25345
|
let startInFlight;
|
|
@@ -25252,6 +25474,23 @@ function createAcpExecutor(options) {
|
|
|
25252
25474
|
continue;
|
|
25253
25475
|
}
|
|
25254
25476
|
if (event._tag === "ContentDelta") {
|
|
25477
|
+
if (event.streamKind === "reasoning_text") {
|
|
25478
|
+
if (event.text.trim().length === 0) {
|
|
25479
|
+
continue;
|
|
25480
|
+
}
|
|
25481
|
+
emit(
|
|
25482
|
+
makeAcpContentDeltaEvent({
|
|
25483
|
+
stamp: stamp(),
|
|
25484
|
+
provider: options.provider,
|
|
25485
|
+
threadId: options.threadId,
|
|
25486
|
+
turnId: activeTurnId,
|
|
25487
|
+
text: event.text,
|
|
25488
|
+
streamKind: "reasoning_text",
|
|
25489
|
+
rawPayload: event.rawPayload
|
|
25490
|
+
})
|
|
25491
|
+
);
|
|
25492
|
+
continue;
|
|
25493
|
+
}
|
|
25255
25494
|
if (event.text.trim().length === 0 && !assistantSegment.activeItemId) {
|
|
25256
25495
|
continue;
|
|
25257
25496
|
}
|
|
@@ -25264,6 +25503,7 @@ function createAcpExecutor(options) {
|
|
|
25264
25503
|
turnId: activeTurnId,
|
|
25265
25504
|
...itemId ? { itemId } : {},
|
|
25266
25505
|
text: event.text,
|
|
25506
|
+
streamKind: "assistant_text",
|
|
25267
25507
|
rawPayload: event.rawPayload
|
|
25268
25508
|
})
|
|
25269
25509
|
);
|
|
@@ -25424,6 +25664,12 @@ function createAcpExecutor(options) {
|
|
|
25424
25664
|
const userInputOutcome = await handlePermissionAsUserInput(params);
|
|
25425
25665
|
if (userInputOutcome !== void 0) return userInputOutcome;
|
|
25426
25666
|
const permissionRequest = parsePermissionRequest(params);
|
|
25667
|
+
if (options.autoApprove?.(permissionRequest) === true) {
|
|
25668
|
+
const optionId = selectAutoApprovedAcpPermissionOption(params);
|
|
25669
|
+
if (optionId !== void 0) {
|
|
25670
|
+
return { outcome: { outcome: "selected", optionId } };
|
|
25671
|
+
}
|
|
25672
|
+
}
|
|
25427
25673
|
const requestId = randomId();
|
|
25428
25674
|
const outcome = await new Promise((resolve2) => {
|
|
25429
25675
|
const pending = {
|
|
@@ -25511,36 +25757,70 @@ function createAcpExecutor(options) {
|
|
|
25511
25757
|
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) {
|
|
25512
25758
|
return input2.state;
|
|
25513
25759
|
}
|
|
25760
|
+
const value = matchAdvertisedModelValue(requestedModelId, input2.state.advertisedModelValues);
|
|
25761
|
+
if (value === void 0) {
|
|
25762
|
+
if (requestedModelId !== lastUnmatchedModelId) {
|
|
25763
|
+
lastUnmatchedModelId = requestedModelId;
|
|
25764
|
+
options.log?.info("requested model is not in the agent catalog; keeping its own model", {
|
|
25765
|
+
requestedModelId,
|
|
25766
|
+
currentModelId: input2.state.currentModelId,
|
|
25767
|
+
advertisedModelValues: input2.state.advertisedModelValues
|
|
25768
|
+
});
|
|
25769
|
+
}
|
|
25770
|
+
return input2.state;
|
|
25771
|
+
}
|
|
25772
|
+
if (value === input2.state.currentModelId) {
|
|
25773
|
+
return input2.state;
|
|
25774
|
+
}
|
|
25514
25775
|
if (input2.state.strategy === "config-option") {
|
|
25515
25776
|
await connection.request("session/set_config_option", {
|
|
25516
25777
|
sessionId: input2.acpSessionId,
|
|
25517
25778
|
configId: input2.state.modelConfigId,
|
|
25518
|
-
value
|
|
25779
|
+
value
|
|
25519
25780
|
});
|
|
25520
25781
|
} else {
|
|
25521
25782
|
await connection.request("session/set_model", {
|
|
25522
25783
|
sessionId: input2.acpSessionId,
|
|
25523
|
-
modelId:
|
|
25784
|
+
modelId: value
|
|
25524
25785
|
});
|
|
25525
25786
|
}
|
|
25526
25787
|
if (!isLive(input2.expectedGeneration)) {
|
|
25527
25788
|
throw new AcpExecutorDisposedError();
|
|
25528
25789
|
}
|
|
25529
|
-
return { ...input2.state, currentModelId:
|
|
25790
|
+
return { ...input2.state, currentModelId: value };
|
|
25791
|
+
};
|
|
25792
|
+
const applyRequestedEffort = async (input2) => {
|
|
25793
|
+
const requested = input2.requestedEffort?.trim();
|
|
25794
|
+
if (!requested) return;
|
|
25795
|
+
const configOptions = typeof input2.setup === "object" && input2.setup !== null ? input2.setup.configOptions : void 0;
|
|
25796
|
+
const effort = findAcpEffortConfig(configOptions);
|
|
25797
|
+
if (effort === void 0) return;
|
|
25798
|
+
const matched = effort.choices.find((choice) => choice.value === requested);
|
|
25799
|
+
if (matched === void 0) {
|
|
25800
|
+
options.log?.info("requested effort is not in the agent catalog; keeping its own", {
|
|
25801
|
+
requestedEffort: requested,
|
|
25802
|
+
advertised: effort.choices.map((choice) => choice.value)
|
|
25803
|
+
});
|
|
25804
|
+
return;
|
|
25805
|
+
}
|
|
25806
|
+
if (matched.isDefault === true) return;
|
|
25807
|
+
if (!isLive(input2.expectedGeneration)) return;
|
|
25808
|
+
try {
|
|
25809
|
+
await connection.request("session/set_config_option", {
|
|
25810
|
+
sessionId: input2.acpSessionId,
|
|
25811
|
+
configId: effort.configId,
|
|
25812
|
+
value: requested
|
|
25813
|
+
});
|
|
25814
|
+
} catch (error62) {
|
|
25815
|
+
options.log?.info("setting the effort level failed; the session keeps its own", {
|
|
25816
|
+
requestedEffort: requested,
|
|
25817
|
+
configId: effort.configId,
|
|
25818
|
+
error: error62 instanceof Error ? error62.message : String(error62)
|
|
25819
|
+
});
|
|
25820
|
+
}
|
|
25530
25821
|
};
|
|
25531
25822
|
const startOnce = async (expectedGeneration) => {
|
|
25532
|
-
const initializePayload =
|
|
25533
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
25534
|
-
clientCapabilities: {
|
|
25535
|
-
fs: {
|
|
25536
|
-
readTextFile: false,
|
|
25537
|
-
writeTextFile: false,
|
|
25538
|
-
...options.clientCapabilities?.fs
|
|
25539
|
-
},
|
|
25540
|
-
terminal: options.clientCapabilities?.terminal ?? false
|
|
25541
|
-
},
|
|
25542
|
-
clientInfo: options.clientInfo
|
|
25543
|
-
};
|
|
25823
|
+
const initializePayload = acpInitializePayload(options.clientInfo, options.clientCapabilities);
|
|
25544
25824
|
const initialized = await connection.request(
|
|
25545
25825
|
"initialize",
|
|
25546
25826
|
initializePayload
|
|
@@ -25584,12 +25864,27 @@ function createAcpExecutor(options) {
|
|
|
25584
25864
|
nextSessionId = created.sessionId;
|
|
25585
25865
|
setup = created;
|
|
25586
25866
|
}
|
|
25867
|
+
const unhandledCategories = unhandledConfigCategories(
|
|
25868
|
+
setup.configOptions
|
|
25869
|
+
);
|
|
25870
|
+
if (unhandledCategories.length > 0) {
|
|
25871
|
+
options.log?.info("acp session reported config option categories we do not handle", {
|
|
25872
|
+
sessionId: nextSessionId,
|
|
25873
|
+
categories: unhandledCategories
|
|
25874
|
+
});
|
|
25875
|
+
}
|
|
25587
25876
|
const nextModelSelectionState = await applyRequestedModel({
|
|
25588
25877
|
state: modelSelectionStateFromSetup(setup),
|
|
25589
25878
|
acpSessionId: nextSessionId,
|
|
25590
25879
|
requestedModelId: options.requestedModelId,
|
|
25591
25880
|
expectedGeneration
|
|
25592
25881
|
});
|
|
25882
|
+
await applyRequestedEffort({
|
|
25883
|
+
setup,
|
|
25884
|
+
acpSessionId: nextSessionId,
|
|
25885
|
+
requestedEffort: options.requestedEffort,
|
|
25886
|
+
expectedGeneration
|
|
25887
|
+
});
|
|
25593
25888
|
if (options.beforeApplyResult) {
|
|
25594
25889
|
await options.beforeApplyResult();
|
|
25595
25890
|
}
|
|
@@ -25954,6 +26249,26 @@ function createAcpExecutor(options) {
|
|
|
25954
26249
|
};
|
|
25955
26250
|
apply();
|
|
25956
26251
|
};
|
|
26252
|
+
const setNativeMode = async (modeId) => {
|
|
26253
|
+
failIfDisposed();
|
|
26254
|
+
const started = startResult;
|
|
26255
|
+
if (started === void 0) {
|
|
26256
|
+
throw new AcpExecutorRequestError("session/set_mode", "session has not started yet");
|
|
26257
|
+
}
|
|
26258
|
+
const configId = acpModeConfigId(started.sessionSetupResult);
|
|
26259
|
+
if (configId !== void 0) {
|
|
26260
|
+
await connection.request("session/set_config_option", {
|
|
26261
|
+
sessionId: started.sessionId,
|
|
26262
|
+
configId,
|
|
26263
|
+
value: modeId
|
|
26264
|
+
});
|
|
26265
|
+
return;
|
|
26266
|
+
}
|
|
26267
|
+
await connection.request("session/set_mode", {
|
|
26268
|
+
sessionId: started.sessionId,
|
|
26269
|
+
modeId
|
|
26270
|
+
});
|
|
26271
|
+
};
|
|
25957
26272
|
const respondToUserInput = async (requestId, answers) => {
|
|
25958
26273
|
failIfDisposed();
|
|
25959
26274
|
const pending = pendingUserInputs.get(requestId);
|
|
@@ -25970,7 +26285,7 @@ function createAcpExecutor(options) {
|
|
|
25970
26285
|
pendingUserInputs.delete(requestId);
|
|
25971
26286
|
pending.resolve({
|
|
25972
26287
|
kind: "answered",
|
|
25973
|
-
answers:
|
|
26288
|
+
answers: isRecord5(answers) ? answers : {}
|
|
25974
26289
|
});
|
|
25975
26290
|
};
|
|
25976
26291
|
const dispose = async () => {
|
|
@@ -26020,13 +26335,56 @@ function createAcpExecutor(options) {
|
|
|
26020
26335
|
cancel,
|
|
26021
26336
|
respondToRequest,
|
|
26022
26337
|
respondToUserInput,
|
|
26338
|
+
setNativeMode,
|
|
26023
26339
|
dispose
|
|
26024
26340
|
};
|
|
26025
26341
|
}
|
|
26026
26342
|
|
|
26343
|
+
// ../../packages/ycodium-acp-executor/src/probe.ts
|
|
26344
|
+
function withProbeTimeout(promise2, timeoutMs, method) {
|
|
26345
|
+
return new Promise((resolve2, reject) => {
|
|
26346
|
+
const timer = setTimeout(() => {
|
|
26347
|
+
reject(new Error(`ACP probe request '${method}' timed out after ${timeoutMs}ms`));
|
|
26348
|
+
}, timeoutMs);
|
|
26349
|
+
timer.unref?.();
|
|
26350
|
+
promise2.then(
|
|
26351
|
+
(value) => {
|
|
26352
|
+
clearTimeout(timer);
|
|
26353
|
+
resolve2(value);
|
|
26354
|
+
},
|
|
26355
|
+
(error62) => {
|
|
26356
|
+
clearTimeout(timer);
|
|
26357
|
+
reject(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
26358
|
+
}
|
|
26359
|
+
);
|
|
26360
|
+
});
|
|
26361
|
+
}
|
|
26362
|
+
async function openAcpProbeHandshake(input2) {
|
|
26363
|
+
const connection = createAcpConnection({
|
|
26364
|
+
readable: input2.readable,
|
|
26365
|
+
writable: input2.writable,
|
|
26366
|
+
onNotification: () => void 0
|
|
26367
|
+
});
|
|
26368
|
+
try {
|
|
26369
|
+
const initializeResult = await withProbeTimeout(
|
|
26370
|
+
connection.request("initialize", acpInitializePayload(input2.clientInfo)),
|
|
26371
|
+
input2.requestTimeoutMs,
|
|
26372
|
+
"initialize"
|
|
26373
|
+
);
|
|
26374
|
+
return {
|
|
26375
|
+
initializeResult,
|
|
26376
|
+
request: (method, params) => withProbeTimeout(connection.request(method, params), input2.requestTimeoutMs, method),
|
|
26377
|
+
close: () => connection.close()
|
|
26378
|
+
};
|
|
26379
|
+
} catch (error62) {
|
|
26380
|
+
await connection.close().catch(() => void 0);
|
|
26381
|
+
throw error62;
|
|
26382
|
+
}
|
|
26383
|
+
}
|
|
26384
|
+
|
|
26027
26385
|
// src/config.ts
|
|
26028
26386
|
var DSH_DEFAULT_LAUNCH_ARGS = "--profile acp";
|
|
26029
|
-
function
|
|
26387
|
+
function isRecord6(value) {
|
|
26030
26388
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26031
26389
|
}
|
|
26032
26390
|
function readString(value) {
|
|
@@ -26039,7 +26397,7 @@ function readEnvironment(value) {
|
|
|
26039
26397
|
if (!Array.isArray(value)) return {};
|
|
26040
26398
|
const env = {};
|
|
26041
26399
|
for (const entry of value) {
|
|
26042
|
-
if (!
|
|
26400
|
+
if (!isRecord6(entry)) continue;
|
|
26043
26401
|
const name = readTrimmed(entry["name"]);
|
|
26044
26402
|
if (name.length === 0) continue;
|
|
26045
26403
|
env[name] = readString(entry["value"]);
|
|
@@ -26047,7 +26405,7 @@ function readEnvironment(value) {
|
|
|
26047
26405
|
return env;
|
|
26048
26406
|
}
|
|
26049
26407
|
function parseDshInstanceConfig(config2) {
|
|
26050
|
-
if (!
|
|
26408
|
+
if (!isRecord6(config2)) {
|
|
26051
26409
|
return {
|
|
26052
26410
|
binaryPath: "",
|
|
26053
26411
|
launchArgs: DSH_DEFAULT_LAUNCH_ARGS,
|
|
@@ -26057,7 +26415,7 @@ function parseDshInstanceConfig(config2) {
|
|
|
26057
26415
|
envelopeDriver: void 0
|
|
26058
26416
|
};
|
|
26059
26417
|
}
|
|
26060
|
-
const nested =
|
|
26418
|
+
const nested = isRecord6(config2["config"]) ? config2["config"] : void 0;
|
|
26061
26419
|
const settings = nested ?? config2;
|
|
26062
26420
|
return {
|
|
26063
26421
|
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
@@ -26120,57 +26478,188 @@ function tokenizeLaunchArgs(value) {
|
|
|
26120
26478
|
return tokens;
|
|
26121
26479
|
}
|
|
26122
26480
|
|
|
26123
|
-
// src/
|
|
26124
|
-
import * as
|
|
26125
|
-
|
|
26126
|
-
|
|
26127
|
-
|
|
26128
|
-
|
|
26129
|
-
|
|
26130
|
-
|
|
26131
|
-
|
|
26132
|
-
|
|
26133
|
-
|
|
26134
|
-
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
|
|
26143
|
-
|
|
26144
|
-
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
|
|
26154
|
-
|
|
26155
|
-
|
|
26156
|
-
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
26162
|
-
|
|
26163
|
-
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
26481
|
+
// src/probeModels.ts
|
|
26482
|
+
import * as NodeFS from "node:fs";
|
|
26483
|
+
import * as NodeOS2 from "node:os";
|
|
26484
|
+
import * as NodePath2 from "node:path";
|
|
26485
|
+
import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
|
|
26486
|
+
|
|
26487
|
+
// src/spawnEnv.ts
|
|
26488
|
+
import * as NodeOS from "node:os";
|
|
26489
|
+
import * as NodePath from "node:path";
|
|
26490
|
+
import { mergeLaunchEnv, brainSlotEnvKeys } from "@ycodium-ai/plugin-api/executor";
|
|
26491
|
+
|
|
26492
|
+
// src/permission.ts
|
|
26493
|
+
var DSH_NATIVE_MODES = [
|
|
26494
|
+
{
|
|
26495
|
+
id: "read-only",
|
|
26496
|
+
name: "Read only",
|
|
26497
|
+
description: "Sandboxed to reading. Asks before anything that writes or runs."
|
|
26498
|
+
},
|
|
26499
|
+
{
|
|
26500
|
+
id: "workspace-write",
|
|
26501
|
+
name: "Workspace write",
|
|
26502
|
+
description: "Writes inside the workspace. Asks before stepping outside it."
|
|
26503
|
+
},
|
|
26504
|
+
{
|
|
26505
|
+
id: "danger-full-access",
|
|
26506
|
+
name: "Full access",
|
|
26507
|
+
description: "No sandbox, never asks. Every command runs immediately."
|
|
26508
|
+
}
|
|
26509
|
+
];
|
|
26510
|
+
var DSH_DEFAULT_NATIVE_MODE_ID = "workspace-write";
|
|
26511
|
+
function isDshNativeModeId(value) {
|
|
26512
|
+
return DSH_NATIVE_MODES.some((mode) => mode.id === value);
|
|
26513
|
+
}
|
|
26514
|
+
function dshNativeModeReport(instanceEnvironment) {
|
|
26515
|
+
const configured = instanceEnvironment["DSH_PERMISSION_MODE"]?.trim();
|
|
26516
|
+
return {
|
|
26517
|
+
nativeModes: DSH_NATIVE_MODES.map((mode) => ({
|
|
26518
|
+
id: mode.id,
|
|
26519
|
+
name: mode.name,
|
|
26520
|
+
description: mode.description
|
|
26521
|
+
})),
|
|
26522
|
+
currentNativeModeId: configured !== void 0 && isDshNativeModeId(configured) ? configured : DSH_DEFAULT_NATIVE_MODE_ID
|
|
26523
|
+
};
|
|
26524
|
+
}
|
|
26525
|
+
function dshPermissionEnv(nativeModeId) {
|
|
26526
|
+
if (nativeModeId === void 0 || !isDshNativeModeId(nativeModeId)) return {};
|
|
26527
|
+
return { DSH_PERMISSION_MODE: nativeModeId };
|
|
26528
|
+
}
|
|
26529
|
+
|
|
26530
|
+
// src/spawnEnv.ts
|
|
26531
|
+
function expandHomePath(value) {
|
|
26532
|
+
if (value === "~") return NodeOS.homedir();
|
|
26533
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
26534
|
+
return NodePath.join(NodeOS.homedir(), value.slice(2));
|
|
26535
|
+
}
|
|
26536
|
+
return value;
|
|
26537
|
+
}
|
|
26538
|
+
function resolveHomePath(value) {
|
|
26539
|
+
const trimmed = value.trim();
|
|
26540
|
+
if (trimmed.length === 0) return "";
|
|
26541
|
+
return NodePath.resolve(expandHomePath(trimmed));
|
|
26542
|
+
}
|
|
26543
|
+
function buildSpawnEnv(recipe, resolvedHomePath, launchEnv = {}, nativeModeId) {
|
|
26544
|
+
const homeEnvVar = recipe.homeEnvVar.trim() || DSH_CARD.homeEnvVar;
|
|
26545
|
+
const homeInjection = resolvedHomePath.length > 0 && homeEnvVar.length > 0 ? { [homeEnvVar]: resolvedHomePath } : {};
|
|
26546
|
+
return mergeLaunchEnv({
|
|
26547
|
+
brainSlots: brainSlotEnvKeys(DSH_CARD),
|
|
26548
|
+
accountHome: homeInjection,
|
|
26549
|
+
instanceTable: recipe.environment,
|
|
26550
|
+
// 用户挑的档压过实例表:实例表里那一栏是这台机器的默认,输入区那一下是这一轮的
|
|
26551
|
+
// 意思。铺在 `handOverrides` 这一层正是为了这个先后(见 `mergeLaunchEnv` 的层序)。
|
|
26552
|
+
handOverrides: dshPermissionEnv(nativeModeId),
|
|
26553
|
+
launch: launchEnv
|
|
26167
26554
|
});
|
|
26168
|
-
|
|
26555
|
+
}
|
|
26556
|
+
|
|
26557
|
+
// src/probeModels.ts
|
|
26558
|
+
var PROBE_REQUEST_TIMEOUT_MS = 15e3;
|
|
26559
|
+
function dshProbeSessionCwd(instanceId) {
|
|
26560
|
+
const safe = instanceId.trim().replace(/[^A-Za-z0-9._-]/g, "-") || "instance";
|
|
26561
|
+
return NodePath2.join(NodeOS2.tmpdir(), `ycodium-dsh-probe-${safe}`);
|
|
26562
|
+
}
|
|
26563
|
+
function isRecord7(value) {
|
|
26564
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26565
|
+
}
|
|
26566
|
+
function asString3(value) {
|
|
26567
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
26568
|
+
}
|
|
26569
|
+
function dshProbeModels(setup) {
|
|
26570
|
+
if (!isRecord7(setup)) return void 0;
|
|
26571
|
+
const rawOptions = setup["configOptions"];
|
|
26572
|
+
const choices = acpModelChoicesFromConfigOptions(rawOptions);
|
|
26573
|
+
if (choices === void 0) return void 0;
|
|
26574
|
+
const models = choices.map((choice) => ({
|
|
26575
|
+
slug: choice.value,
|
|
26576
|
+
...choice.name === void 0 ? {} : { name: choice.name },
|
|
26577
|
+
...choice.isDefault === true ? { isDefault: true } : {}
|
|
26578
|
+
}));
|
|
26579
|
+
const effort = findAcpEffortConfig(rawOptions);
|
|
26580
|
+
if (effort === void 0) return models;
|
|
26581
|
+
const capabilities = {
|
|
26582
|
+
optionDescriptors: [
|
|
26583
|
+
{
|
|
26584
|
+
id: DSH_EFFORT_OPTION_ID,
|
|
26585
|
+
label: effort.label || "Reasoning",
|
|
26586
|
+
type: "select",
|
|
26587
|
+
options: effort.choices.map((choice) => ({
|
|
26588
|
+
id: choice.value,
|
|
26589
|
+
label: choice.label,
|
|
26590
|
+
...choice.description === void 0 ? {} : { description: choice.description },
|
|
26591
|
+
...choice.isDefault === true ? { isDefault: true } : {}
|
|
26592
|
+
}))
|
|
26593
|
+
}
|
|
26594
|
+
]
|
|
26595
|
+
};
|
|
26596
|
+
return models.map((model) => ({ ...model, capabilities }));
|
|
26597
|
+
}
|
|
26598
|
+
var DSH_EFFORT_OPTION_ID = "reasoning";
|
|
26599
|
+
function findProbeSessionId(listed, probeCwd) {
|
|
26600
|
+
if (!isRecord7(listed) || !Array.isArray(listed["sessions"])) return void 0;
|
|
26601
|
+
for (const entry of listed["sessions"]) {
|
|
26602
|
+
if (!isRecord7(entry)) continue;
|
|
26603
|
+
if (asString3(entry["cwd"]) !== probeCwd) continue;
|
|
26604
|
+
const sessionId = asString3(entry["sessionId"]);
|
|
26605
|
+
if (sessionId !== void 0) return sessionId;
|
|
26606
|
+
}
|
|
26607
|
+
return void 0;
|
|
26608
|
+
}
|
|
26609
|
+
async function probeSessionSetup(handshake, probeCwd) {
|
|
26610
|
+
const listed = await handshake.request("session/list", {}).catch(() => void 0);
|
|
26611
|
+
const reusable = findProbeSessionId(listed, probeCwd);
|
|
26612
|
+
if (reusable !== void 0) {
|
|
26613
|
+
const resumed = await handshake.request("session/resume", { sessionId: reusable, cwd: probeCwd, mcpServers: [] }).catch(() => void 0);
|
|
26614
|
+
if (resumed !== void 0) return resumed;
|
|
26615
|
+
}
|
|
26616
|
+
return handshake.request("session/new", { cwd: probeCwd, mcpServers: [] });
|
|
26617
|
+
}
|
|
26618
|
+
var failureDetail = (error62) => (error62 instanceof Error ? error62.message : String(error62)).trim() || void 0;
|
|
26619
|
+
async function probeDshModels(input2) {
|
|
26620
|
+
const { recipe, host } = input2;
|
|
26621
|
+
const probeCwd = dshProbeSessionCwd(host.instanceId);
|
|
26622
|
+
try {
|
|
26623
|
+
NodeFS.mkdirSync(probeCwd, { recursive: true });
|
|
26624
|
+
} catch (error62) {
|
|
26625
|
+
return { kind: "failed", detail: failureDetail(error62) };
|
|
26626
|
+
}
|
|
26627
|
+
const env = buildSpawnEnv(recipe, resolveHomePath(recipe.homePath));
|
|
26628
|
+
let handle;
|
|
26629
|
+
try {
|
|
26630
|
+
handle = await host.process.spawn({
|
|
26631
|
+
program: recipe.binaryPath,
|
|
26632
|
+
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
26633
|
+
cwd: probeCwd,
|
|
26634
|
+
owner: { bindingId: host.bindingId },
|
|
26635
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
26636
|
+
});
|
|
26637
|
+
} catch (error62) {
|
|
26638
|
+
return { kind: "not-started", detail: failureDetail(error62) };
|
|
26639
|
+
}
|
|
26640
|
+
let handshake;
|
|
26641
|
+
try {
|
|
26642
|
+
const { readable, writable } = nodeStreamsFromHandle(handle);
|
|
26643
|
+
handshake = await openAcpProbeHandshake({
|
|
26644
|
+
readable,
|
|
26645
|
+
writable,
|
|
26646
|
+
clientInfo: DSH_CLIENT_INFO,
|
|
26647
|
+
requestTimeoutMs: PROBE_REQUEST_TIMEOUT_MS
|
|
26648
|
+
});
|
|
26649
|
+
return {
|
|
26650
|
+
kind: "answered",
|
|
26651
|
+
models: dshProbeModels(await probeSessionSetup(handshake, probeCwd))
|
|
26652
|
+
};
|
|
26653
|
+
} catch (error62) {
|
|
26654
|
+
return { kind: "failed", detail: failureDetail(error62) };
|
|
26655
|
+
} finally {
|
|
26656
|
+
await handshake?.close().catch(() => void 0);
|
|
26657
|
+
await handle.kill("SIGTERM").catch(() => void 0);
|
|
26658
|
+
}
|
|
26169
26659
|
}
|
|
26170
26660
|
|
|
26171
26661
|
// src/dshInstance.ts
|
|
26172
26662
|
var RESUME_SCHEMA_VERSION = 1;
|
|
26173
|
-
var CLIENT_INFO = { name: "ycodium-agent-dsh", version: "0.1.0" };
|
|
26174
26663
|
var yieldTick = () => new Promise((resolve2) => {
|
|
26175
26664
|
setImmediate(resolve2);
|
|
26176
26665
|
});
|
|
@@ -26206,25 +26695,6 @@ var EventBus = class {
|
|
|
26206
26695
|
};
|
|
26207
26696
|
}
|
|
26208
26697
|
};
|
|
26209
|
-
function expandHomePath(value) {
|
|
26210
|
-
if (value === "~") return NodeOS.homedir();
|
|
26211
|
-
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
26212
|
-
return NodePath.join(NodeOS.homedir(), value.slice(2));
|
|
26213
|
-
}
|
|
26214
|
-
return value;
|
|
26215
|
-
}
|
|
26216
|
-
function resolveHomePath(value) {
|
|
26217
|
-
const trimmed = value.trim();
|
|
26218
|
-
if (trimmed.length === 0) return "";
|
|
26219
|
-
return NodePath.resolve(expandHomePath(trimmed));
|
|
26220
|
-
}
|
|
26221
|
-
function compactEnv(env) {
|
|
26222
|
-
const out = {};
|
|
26223
|
-
for (const [key, value] of Object.entries(env)) {
|
|
26224
|
-
if (value !== void 0) out[key] = value;
|
|
26225
|
-
}
|
|
26226
|
-
return out;
|
|
26227
|
-
}
|
|
26228
26698
|
function modelIdFromSelection(selection) {
|
|
26229
26699
|
if (typeof selection !== "object" || selection === null || Array.isArray(selection)) {
|
|
26230
26700
|
return void 0;
|
|
@@ -26232,15 +26702,6 @@ function modelIdFromSelection(selection) {
|
|
|
26232
26702
|
const model = selection["model"];
|
|
26233
26703
|
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
26234
26704
|
}
|
|
26235
|
-
function buildSpawnEnv(recipe, launch, resolvedHomePath) {
|
|
26236
|
-
const homeEnvVar = recipe.homeEnvVar.trim() || DSH_CARD.homeEnvVar;
|
|
26237
|
-
const homeInjection = resolvedHomePath.length > 0 && homeEnvVar.length > 0 ? { [homeEnvVar]: resolvedHomePath } : {};
|
|
26238
|
-
return {
|
|
26239
|
-
...compactEnv(launch.processEnv),
|
|
26240
|
-
...homeInjection,
|
|
26241
|
-
...recipe.environment
|
|
26242
|
-
};
|
|
26243
|
-
}
|
|
26244
26705
|
function nowIso() {
|
|
26245
26706
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
26246
26707
|
}
|
|
@@ -26270,11 +26731,25 @@ var createDshInstance = (config2, host) => {
|
|
|
26270
26731
|
detail: "DeepSeek Harness program path is not configured"
|
|
26271
26732
|
};
|
|
26272
26733
|
}
|
|
26734
|
+
const outcome = await probeDshModels({ recipe, host });
|
|
26735
|
+
if (outcome.kind !== "answered") {
|
|
26736
|
+
return {
|
|
26737
|
+
installed: outcome.kind === "failed",
|
|
26738
|
+
version: null,
|
|
26739
|
+
readiness: "error",
|
|
26740
|
+
auth: { status: "unknown" },
|
|
26741
|
+
...outcome.detail === void 0 ? {} : { detail: outcome.detail },
|
|
26742
|
+
// 装着但握不上手时界面照样画权限格,不报档就退回宿主四档。
|
|
26743
|
+
...outcome.kind === "failed" ? dshNativeModeReport(recipe.environment) : {}
|
|
26744
|
+
};
|
|
26745
|
+
}
|
|
26273
26746
|
return {
|
|
26274
26747
|
installed: true,
|
|
26275
26748
|
version: null,
|
|
26276
|
-
readiness: "
|
|
26277
|
-
auth: { status: "unknown" }
|
|
26749
|
+
readiness: "ready",
|
|
26750
|
+
auth: { status: "unknown" },
|
|
26751
|
+
...outcome.models === void 0 ? {} : { models: outcome.models },
|
|
26752
|
+
...dshNativeModeReport(recipe.environment)
|
|
26278
26753
|
};
|
|
26279
26754
|
},
|
|
26280
26755
|
startSession: async (input2, signal) => {
|
|
@@ -26291,7 +26766,12 @@ var createDshInstance = (config2, host) => {
|
|
|
26291
26766
|
threads.delete(input2.threadId);
|
|
26292
26767
|
}
|
|
26293
26768
|
const resolvedHomePath = resolveHomePath(input2.launch.homePath?.trim() || recipe.homePath);
|
|
26294
|
-
const env = buildSpawnEnv(
|
|
26769
|
+
const env = buildSpawnEnv(
|
|
26770
|
+
recipe,
|
|
26771
|
+
resolvedHomePath,
|
|
26772
|
+
input2.launch.processEnv,
|
|
26773
|
+
input2.nativeModeId
|
|
26774
|
+
);
|
|
26295
26775
|
const handle = await host.process.spawn({
|
|
26296
26776
|
program: recipe.binaryPath,
|
|
26297
26777
|
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
@@ -26299,7 +26779,7 @@ var createDshInstance = (config2, host) => {
|
|
|
26299
26779
|
owner: { bindingId: host.bindingId },
|
|
26300
26780
|
...Object.keys(env).length > 0 ? { env } : {}
|
|
26301
26781
|
});
|
|
26302
|
-
const { readable, writable } =
|
|
26782
|
+
const { readable, writable } = nodeStreamsFromHandle2(handle);
|
|
26303
26783
|
const resume = input2.discardResumeCursor === true ? void 0 : parseAcpResumeCursor(input2.resumeCursor, RESUME_SCHEMA_VERSION);
|
|
26304
26784
|
const requestedModelId = input2.launch.requestedModelId?.trim() || modelIdFromSelection(input2.modelSelection);
|
|
26305
26785
|
const executor = createAcpExecutor({
|
|
@@ -26309,7 +26789,8 @@ var createDshInstance = (config2, host) => {
|
|
|
26309
26789
|
threadId: input2.threadId,
|
|
26310
26790
|
provider: DSH_DRIVER_KIND,
|
|
26311
26791
|
providerInstanceId: host.instanceId,
|
|
26312
|
-
clientInfo:
|
|
26792
|
+
clientInfo: DSH_CLIENT_INFO,
|
|
26793
|
+
log: host.log,
|
|
26313
26794
|
// 该 agent 不实现 session/load,只实现 session/resume——续接重新激活
|
|
26314
26795
|
// 持久会话而不重放记录,发 load 会卡在永远不结算的重放门上。
|
|
26315
26796
|
resumeMethod: "session/resume",
|
|
@@ -26335,6 +26816,7 @@ var createDshInstance = (config2, host) => {
|
|
|
26335
26816
|
providerInstanceId: host.instanceId,
|
|
26336
26817
|
status: "idle",
|
|
26337
26818
|
runtimeMode: input2.runtimeMode,
|
|
26819
|
+
...input2.nativeModeId !== void 0 && isDshNativeModeId(input2.nativeModeId) ? { nativeModeId: input2.nativeModeId } : {},
|
|
26338
26820
|
cwd,
|
|
26339
26821
|
threadId: input2.threadId,
|
|
26340
26822
|
createdAt,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-dsh",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2126",
|
|
4
4
|
"description": "DeepSeek Harness executor: dsh CLI over Agent Client Protocol stdio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"esbuild": "0.28.1",
|
|
22
22
|
"vite-plus": "0.2.2",
|
|
23
23
|
"ycodium-acp-executor": "0.0.0",
|
|
24
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
24
|
+
"@ycodium-ai/plugin-api": "0.2.2126",
|
|
25
25
|
"ycodium-acp-protocol": "0.0.0"
|
|
26
26
|
},
|
|
27
27
|
"ycodium": {
|