@ycodium-ai/agent-grok 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 +678 -190
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -9,15 +9,18 @@ import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
|
9
9
|
|
|
10
10
|
// src/card.ts
|
|
11
11
|
var GROK_DRIVER_KIND = "grok";
|
|
12
|
+
var GROK_CLIENT_INFO = { name: "ycodium-agent-grok", version: "0.1.0" };
|
|
12
13
|
var GROK_CARD = {
|
|
13
14
|
driverKind: GROK_DRIVER_KIND,
|
|
14
15
|
displayName: "Grok",
|
|
15
16
|
iconUrl: "./assets/icon.svg",
|
|
16
17
|
commandName: "grok",
|
|
17
18
|
// 启动命令是 `grok agent stdio`(GrokSettings 磁盘形状没有 launchArgs 字段,
|
|
18
|
-
// 宿主旧实现把它写死在 buildGrokAcpSpawnInput
|
|
19
|
-
//
|
|
20
|
-
//
|
|
19
|
+
// 宿主旧实现把它写死在 buildGrokAcpSpawnInput,这里落在名片上)。两个动态旗标
|
|
20
|
+
// 都不走名片这一栏,而且**位置不同**:思考档位 `--reasoning-effort` 是 agent 级、
|
|
21
|
+
// 插在 agent 与 stdio 之间;运行模式 `--permission-mode` 是顶层、排在 `agent`
|
|
22
|
+
// 前面(放进 agent 那一段 grok 当场报 unexpected argument)。两者都在
|
|
23
|
+
// `grokInstance.startSession` 里按用户选择拼。
|
|
21
24
|
launchArgs: "agent stdio",
|
|
22
25
|
homeEnvVar: "GROK_HOME",
|
|
23
26
|
// 只有这一条是实话:实测这个 CLI 从不播报 api key 认证方式,点名 XAI_API_KEY
|
|
@@ -33,7 +36,7 @@ var GROK_CARD = {
|
|
|
33
36
|
signIn: [{ kind: "command", command: "grok login" }],
|
|
34
37
|
deviceCodeSignInArgs: ["login", "--device-auth"],
|
|
35
38
|
// npm 上的 `@xai-official/grok` 只发 darwin-arm64,写出去等于给 Linux/Windows
|
|
36
|
-
//
|
|
39
|
+
// 用户一条装不上的路。
|
|
37
40
|
npmPackage: "",
|
|
38
41
|
homebrewFormula: "",
|
|
39
42
|
selfUpdateArgs: ["update"],
|
|
@@ -57,7 +60,16 @@ var GROK_CARD = {
|
|
|
57
60
|
// Grok 换模型只有 `session/set_config_option` 一条路;库会按握手形状自动协商,
|
|
58
61
|
// 但插件侧的执行路径还没接到模型管理 UI,名片必须说实话。
|
|
59
62
|
sessionModelSwitch: "unsupported",
|
|
60
|
-
|
|
63
|
+
// 运行模式只在 spawn 时定得了(`--permission-mode` 是启动旗标,ACP 那一侧
|
|
64
|
+
// `modes: null`,`session/set_mode` 对它无效),所以不许声称能会话中途换。
|
|
65
|
+
// 报 next-turn 之后宿主 `ProviderCommandReactor` 不再下发,而是把新档记在
|
|
66
|
+
// thread 上;下一轮 `ensureSessionForThread` 判到 runtimeModeChanged,带着
|
|
67
|
+
// resume cursor 真重开会话——历史续上,档位换掉。
|
|
68
|
+
runtimeModeSwitch: "next-turn",
|
|
69
|
+
// 档位走 spawn 旗标,切档要重开会话(与 runtimeModeSwitch 同为 next-turn 的原因)。
|
|
70
|
+
// 声明这一位让界面画这双手自报的三档;不声明就退回宿主四档,而四档在这只手上
|
|
71
|
+
// 有两档撞车(都落到 `auto`)。
|
|
72
|
+
nativeModeSwitch: true
|
|
61
73
|
},
|
|
62
74
|
// 凭据由 CLI 自己保管在 `<GROK_HOME>/auth.json`,宿主读它只认 `/token`。
|
|
63
75
|
credentialSources: [
|
|
@@ -84,11 +96,17 @@ var GROK_CARD = {
|
|
|
84
96
|
modelConnectivity: {
|
|
85
97
|
dialects: ["anthropic-messages", "openai-responses", "openai-chat-completions"],
|
|
86
98
|
acceptsExternalEndpoints: true,
|
|
87
|
-
//
|
|
99
|
+
// 地址那一栏必须投:不设 `GROK_MODELS_BASE_URL` 的话整条请求根本不来我们这儿
|
|
100
|
+
// (`grokModelProxyEgress.test.ts` 拿掉这一栏就红)。
|
|
101
|
+
//
|
|
102
|
+
// **但设了 base 并不会把客户端切成 API-key 认证。** 它的凭据顺序是
|
|
88
103
|
// `api_key` → `env_key` → **已登录的 session token** → `XAI_API_KEY`
|
|
89
|
-
// (`~/.grok/docs/user-guide/11-custom-models.md
|
|
90
|
-
//
|
|
91
|
-
//
|
|
104
|
+
// (`~/.grok/docs/user-guide/11-custom-models.md` 的 "Credential Resolution")。
|
|
105
|
+
// 1.0.34 实测:账号目录里有 `auth.json` 时,启动预取 `/v1/models` 用的是
|
|
106
|
+
// `XAI_API_KEY`,而**推理请求带的是用户自己的 x.ai OIDC token**——本地端点只认
|
|
107
|
+
// 这笔绑定的凭据,别的一律 401。所以绑定时还要把 `GROK_AUTH_PATH` 指到一个不存在
|
|
108
|
+
// 的路径(见下面那栏),让这次进程读不到那份登录。同批的实测落在
|
|
109
|
+
// `grokModelProxyEgress.test.ts`。
|
|
92
110
|
//
|
|
93
111
|
// 它启动时先打 `{base_url}/models` 拉模型列表(README:1953「on startup」),不给就
|
|
94
112
|
// 当端点不可用——代理为此支持了 /models。
|
|
@@ -96,13 +114,26 @@ var GROK_CARD = {
|
|
|
96
114
|
// base 含 /v1(它的例子是 `https://api.acme.com/v1`),后面自己加 /chat/completions。
|
|
97
115
|
nativePathSuffix: "/chat/completions",
|
|
98
116
|
baseUrlEnvKey: "GROK_MODELS_BASE_URL",
|
|
99
|
-
credentialEnvKey: "XAI_API_KEY"
|
|
117
|
+
credentialEnvKey: "XAI_API_KEY",
|
|
118
|
+
// 绑定这一轮不准用它自己的登录:凭据顺序里 session token 排在 `XAI_API_KEY`
|
|
119
|
+
// 前面,账号目录里有 `auth.json` 就一定发那一份,本机端点一律 401。
|
|
120
|
+
// `GROK_AUTH_PATH` 是 CLI 读登录文件的路径(1.0.34 的 argv 里与 `GROK_AUTH`、
|
|
121
|
+
// `GROK_DEPLOYMENT_KEY` 并列在同一张敏感变量表上)。`$absentPath` 是宿主按这次
|
|
122
|
+
// 绑定算的、必定不存在的路径——不用空设备是因为那是平台语义(POSIX `/dev/null`
|
|
123
|
+
// 对 Windows `NUL`),而「读不到」两边只有一种行为。1.0.34 实测:`authMethods`
|
|
124
|
+
// 少掉 `cached_token`、两笔请求(推理与标题)都改带绑定凭据,账号目录里那份
|
|
125
|
+
// `auth.json` 一个字节没动,也没在别处新建文件。
|
|
126
|
+
// 只在绑定时注入,非绑定会话照旧用用户自己的登录。
|
|
127
|
+
extraEnv: [{ name: "GROK_AUTH_PATH", value: "$absentPath" }]
|
|
100
128
|
}
|
|
101
129
|
};
|
|
102
130
|
|
|
103
131
|
// src/grokInstance.ts
|
|
132
|
+
import * as NodeCrypto2 from "node:crypto";
|
|
104
133
|
import * as NodeOS from "node:os";
|
|
105
134
|
import * as NodePath2 from "node:path";
|
|
135
|
+
import { mergeLaunchEnv, brainSlotEnvKeys } from "@ycodium-ai/plugin-api/executor";
|
|
136
|
+
import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
|
|
106
137
|
|
|
107
138
|
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
108
139
|
import * as NodeCrypto from "node:crypto";
|
|
@@ -23972,6 +24003,12 @@ function acpApprovalOptions(request) {
|
|
|
23972
24003
|
}
|
|
23973
24004
|
return options;
|
|
23974
24005
|
}
|
|
24006
|
+
function selectAutoApprovedAcpPermissionOption(request) {
|
|
24007
|
+
if (new Set(request.options.map((option) => option.kind)).size !== request.options.length) {
|
|
24008
|
+
return void 0;
|
|
24009
|
+
}
|
|
24010
|
+
return selectAcpPermissionOptionId(request, "acceptForSession") ?? selectAcpPermissionOptionId(request, "accept");
|
|
24011
|
+
}
|
|
23975
24012
|
function parseAcpResumeCursor(raw, schemaVersion) {
|
|
23976
24013
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
23977
24014
|
const record2 = raw;
|
|
@@ -24354,7 +24391,7 @@ function makeAcpContentDeltaEvent(input2) {
|
|
|
24354
24391
|
...input2.turnId !== void 0 ? { turnId: input2.turnId } : {},
|
|
24355
24392
|
...input2.itemId ? { itemId: input2.itemId } : {},
|
|
24356
24393
|
payload: {
|
|
24357
|
-
streamKind: "assistant_text",
|
|
24394
|
+
streamKind: input2.streamKind ?? "assistant_text",
|
|
24358
24395
|
delta: input2.text
|
|
24359
24396
|
},
|
|
24360
24397
|
raw: {
|
|
@@ -24365,6 +24402,150 @@ function makeAcpContentDeltaEvent(input2) {
|
|
|
24365
24402
|
};
|
|
24366
24403
|
}
|
|
24367
24404
|
|
|
24405
|
+
// ../../packages/ycodium-acp-executor/src/config-options.ts
|
|
24406
|
+
function isRecord3(value) {
|
|
24407
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24408
|
+
}
|
|
24409
|
+
function asString(value) {
|
|
24410
|
+
return typeof value === "string" ? value : void 0;
|
|
24411
|
+
}
|
|
24412
|
+
function normalizedField(option, key) {
|
|
24413
|
+
return asString(option[key])?.trim().toLowerCase() ?? "";
|
|
24414
|
+
}
|
|
24415
|
+
function looksLikeEffortOption(option) {
|
|
24416
|
+
const id = normalizedField(option, "id");
|
|
24417
|
+
const name = normalizedField(option, "name");
|
|
24418
|
+
return id === "effort" || id === "reasoning" || name === "effort" || name === "reasoning" || name.includes("effort") || name.includes("reasoning") || normalizedField(option, "category") === "thought_level";
|
|
24419
|
+
}
|
|
24420
|
+
function flattenChoices(rawOptions, currentValue) {
|
|
24421
|
+
if (!Array.isArray(rawOptions)) return [];
|
|
24422
|
+
const out = [];
|
|
24423
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24424
|
+
const push = (entry) => {
|
|
24425
|
+
if (!isRecord3(entry)) return;
|
|
24426
|
+
const value = asString(entry["value"]);
|
|
24427
|
+
if (value === void 0 || seen.has(value)) return;
|
|
24428
|
+
seen.add(value);
|
|
24429
|
+
const description = asString(entry["description"])?.trim();
|
|
24430
|
+
const name = asString(entry["name"])?.trim();
|
|
24431
|
+
out.push({
|
|
24432
|
+
value,
|
|
24433
|
+
...name ? { name } : {},
|
|
24434
|
+
label: name || value,
|
|
24435
|
+
...description ? { description } : {},
|
|
24436
|
+
...currentValue !== void 0 && currentValue === value ? { isDefault: true } : {}
|
|
24437
|
+
});
|
|
24438
|
+
};
|
|
24439
|
+
for (const entry of rawOptions) {
|
|
24440
|
+
if (isRecord3(entry) && Array.isArray(entry["options"])) {
|
|
24441
|
+
for (const nested of entry["options"]) push(nested);
|
|
24442
|
+
continue;
|
|
24443
|
+
}
|
|
24444
|
+
push(entry);
|
|
24445
|
+
}
|
|
24446
|
+
return out;
|
|
24447
|
+
}
|
|
24448
|
+
function findAcpEffortConfig(configOptions) {
|
|
24449
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24450
|
+
const candidates = configOptions.filter(isRecord3).filter((option) => normalizedField(option, "type") === "select").filter(looksLikeEffortOption);
|
|
24451
|
+
if (candidates.length === 0) return void 0;
|
|
24452
|
+
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];
|
|
24453
|
+
if (picked === void 0) return void 0;
|
|
24454
|
+
const configId = asString(picked["id"])?.trim();
|
|
24455
|
+
if (!configId) return void 0;
|
|
24456
|
+
const choices = flattenChoices(picked["options"], asString(picked["currentValue"])?.trim());
|
|
24457
|
+
if (choices.length === 0) return void 0;
|
|
24458
|
+
return {
|
|
24459
|
+
configId,
|
|
24460
|
+
label: asString(picked["name"])?.trim() ?? "",
|
|
24461
|
+
choices
|
|
24462
|
+
};
|
|
24463
|
+
}
|
|
24464
|
+
|
|
24465
|
+
// ../../packages/ycodium-acp-executor/src/runtime-mode.ts
|
|
24466
|
+
function isRecord4(value) {
|
|
24467
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24468
|
+
}
|
|
24469
|
+
function asString2(value) {
|
|
24470
|
+
return typeof value === "string" ? value : void 0;
|
|
24471
|
+
}
|
|
24472
|
+
function acpModeConfigId(setup) {
|
|
24473
|
+
if (!isRecord4(setup)) return void 0;
|
|
24474
|
+
const configOptions = setup["configOptions"];
|
|
24475
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
24476
|
+
for (const option of configOptions) {
|
|
24477
|
+
if (!isRecord4(option)) continue;
|
|
24478
|
+
if (asString2(option["category"])?.trim().toLowerCase() !== "mode") continue;
|
|
24479
|
+
const id = asString2(option["id"])?.trim();
|
|
24480
|
+
if (id) return id;
|
|
24481
|
+
}
|
|
24482
|
+
return void 0;
|
|
24483
|
+
}
|
|
24484
|
+
|
|
24485
|
+
// ../../packages/ycodium-acp-executor/src/handshake.ts
|
|
24486
|
+
function acpInitializePayload(clientInfo, overrides) {
|
|
24487
|
+
return {
|
|
24488
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
24489
|
+
clientCapabilities: {
|
|
24490
|
+
fs: {
|
|
24491
|
+
readTextFile: false,
|
|
24492
|
+
writeTextFile: false,
|
|
24493
|
+
...overrides?.fs
|
|
24494
|
+
},
|
|
24495
|
+
terminal: overrides?.terminal ?? false
|
|
24496
|
+
},
|
|
24497
|
+
clientInfo
|
|
24498
|
+
};
|
|
24499
|
+
}
|
|
24500
|
+
|
|
24501
|
+
// ../../packages/ycodium-acp-executor/src/config-option-wiring.ts
|
|
24502
|
+
var VENDOR_CATEGORY_PREFIX = "_";
|
|
24503
|
+
var ACP_CONFIG_CATEGORY_HANDLING = {
|
|
24504
|
+
mode: {
|
|
24505
|
+
consumed: true,
|
|
24506
|
+
via: "runtime-mode.ts\uFF1AacpAvailableModes / acpCurrentModeId / acpModeConfigId"
|
|
24507
|
+
},
|
|
24508
|
+
model: {
|
|
24509
|
+
consumed: true,
|
|
24510
|
+
via: "runtime-model.ts:extractModelConfigId \u2192 executor.ts:applyRequestedModel"
|
|
24511
|
+
},
|
|
24512
|
+
thought_level: {
|
|
24513
|
+
consumed: true,
|
|
24514
|
+
via: "config-options.ts:findAcpEffortConfig \u2192 executor.ts:applyRequestedEffort"
|
|
24515
|
+
},
|
|
24516
|
+
model_option: {
|
|
24517
|
+
consumed: true,
|
|
24518
|
+
// 精确说法:它不是**识别器**,是**优先级**。`looksLikeEffortOption` 先筛出候选,
|
|
24519
|
+
// 标了 `model_option` 的在候选里排第一(厂商自己标的最准),排在 id 叫 `effort`
|
|
24520
|
+
// 的和标 `thought_level` 的前面。光有这个 category 而 id/name 不像力度档的,
|
|
24521
|
+
// 压根进不了候选。
|
|
24522
|
+
via: "config-options.ts:findAcpEffortConfig\uFF08\u5019\u9009\u91CC\u7684\u6700\u9AD8\u4F18\u5148\u7EA7\uFF0C\u538B\u8FC7 thought_level\uFF09"
|
|
24523
|
+
},
|
|
24524
|
+
model_config: {
|
|
24525
|
+
consumed: false,
|
|
24526
|
+
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"
|
|
24527
|
+
}
|
|
24528
|
+
};
|
|
24529
|
+
var KNOWN_CATEGORIES = new Set(Object.keys(ACP_CONFIG_CATEGORY_HANDLING));
|
|
24530
|
+
function unhandledConfigCategories(configOptions) {
|
|
24531
|
+
if (!configOptions) return [];
|
|
24532
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24533
|
+
const out = [];
|
|
24534
|
+
for (const option of configOptions) {
|
|
24535
|
+
const category = option.category?.trim();
|
|
24536
|
+
if (!category) continue;
|
|
24537
|
+
if (KNOWN_CATEGORIES.has(category)) continue;
|
|
24538
|
+
if (seen.has(category)) continue;
|
|
24539
|
+
seen.add(category);
|
|
24540
|
+
out.push({
|
|
24541
|
+
category,
|
|
24542
|
+
optionId: option.id.trim(),
|
|
24543
|
+
vendorExtension: category.startsWith(VENDOR_CATEGORY_PREFIX)
|
|
24544
|
+
});
|
|
24545
|
+
}
|
|
24546
|
+
return out;
|
|
24547
|
+
}
|
|
24548
|
+
|
|
24368
24549
|
// ../../packages/ycodium-acp-executor/src/mutex.ts
|
|
24369
24550
|
var Mutex = class {
|
|
24370
24551
|
locked = false;
|
|
@@ -24407,7 +24588,7 @@ var Mutex = class {
|
|
|
24407
24588
|
};
|
|
24408
24589
|
|
|
24409
24590
|
// ../../packages/ycodium-acp-executor/src/util.ts
|
|
24410
|
-
function
|
|
24591
|
+
function isRecord5(value) {
|
|
24411
24592
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24412
24593
|
}
|
|
24413
24594
|
function asTrimmedString(value) {
|
|
@@ -24453,11 +24634,11 @@ function extractCommandFromTitle(title) {
|
|
|
24453
24634
|
return backtickMatch?.[1]?.trim() || void 0;
|
|
24454
24635
|
}
|
|
24455
24636
|
function extractToolCommand(data, title) {
|
|
24456
|
-
const item =
|
|
24457
|
-
const itemInput = item &&
|
|
24458
|
-
const itemResult = item &&
|
|
24459
|
-
const rawInput =
|
|
24460
|
-
const dataInput =
|
|
24637
|
+
const item = isRecord5(data?.["item"]) ? data["item"] : void 0;
|
|
24638
|
+
const itemInput = item && isRecord5(item["input"]) ? item["input"] : void 0;
|
|
24639
|
+
const itemResult = item && isRecord5(item["result"]) ? item["result"] : void 0;
|
|
24640
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24641
|
+
const dataInput = isRecord5(data?.["input"]) ? data["input"] : void 0;
|
|
24461
24642
|
const candidates = [
|
|
24462
24643
|
normalizeCommandValue(item?.["command"]),
|
|
24463
24644
|
normalizeCommandValue(itemInput?.["command"]),
|
|
@@ -24502,7 +24683,7 @@ function collectPaths(value, paths, seen, depth) {
|
|
|
24502
24683
|
}
|
|
24503
24684
|
return;
|
|
24504
24685
|
}
|
|
24505
|
-
if (!
|
|
24686
|
+
if (!isRecord5(value)) {
|
|
24506
24687
|
return;
|
|
24507
24688
|
}
|
|
24508
24689
|
for (const key of ["path", "filePath", "relativePath", "filename", "newPath", "oldPath"]) {
|
|
@@ -24565,7 +24746,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24565
24746
|
const title = asTrimmedString(input2.title);
|
|
24566
24747
|
const detail = stripTrailingExitCode(asTrimmedString(input2.detail));
|
|
24567
24748
|
const fallbackSummary = asTrimmedString(input2.fallbackSummary) ?? "Tool";
|
|
24568
|
-
const data =
|
|
24749
|
+
const data = isRecord5(input2.data) ? input2.data : void 0;
|
|
24569
24750
|
const command = extractToolCommand(data, title);
|
|
24570
24751
|
const primaryPath = extractPrimaryPath(data);
|
|
24571
24752
|
const action = classifyToolAction({
|
|
@@ -24597,7 +24778,7 @@ function deriveToolActivityPresentation(input2) {
|
|
|
24597
24778
|
};
|
|
24598
24779
|
}
|
|
24599
24780
|
if (action === "search") {
|
|
24600
|
-
const rawInput =
|
|
24781
|
+
const rawInput = isRecord5(data?.["rawInput"]) ? data["rawInput"] : void 0;
|
|
24601
24782
|
const query = asTrimmedString(rawInput?.["query"]) ?? asTrimmedString(rawInput?.["pattern"]) ?? asTrimmedString(rawInput?.["searchTerm"]);
|
|
24602
24783
|
return {
|
|
24603
24784
|
summary: "Searched files",
|
|
@@ -24636,6 +24817,46 @@ function findSessionConfigOption(configOptions, configId) {
|
|
|
24636
24817
|
}
|
|
24637
24818
|
return configOptions.find((option) => option.id.trim() === normalizedConfigId);
|
|
24638
24819
|
}
|
|
24820
|
+
function collectSessionConfigOptionValues(configOption) {
|
|
24821
|
+
if (configOption.type !== "select" || !configOption.options) {
|
|
24822
|
+
return [];
|
|
24823
|
+
}
|
|
24824
|
+
return configOption.options.flatMap(
|
|
24825
|
+
(entry) => "value" in entry ? [entry.value] : entry.options.map((option) => option.value)
|
|
24826
|
+
);
|
|
24827
|
+
}
|
|
24828
|
+
function collectSessionModelIds(models) {
|
|
24829
|
+
if (!isRecord5(models) || !Array.isArray(models["availableModels"])) {
|
|
24830
|
+
return [];
|
|
24831
|
+
}
|
|
24832
|
+
return models["availableModels"].flatMap(
|
|
24833
|
+
(model) => isRecord5(model) && typeof model["modelId"] === "string" ? [model["modelId"]] : []
|
|
24834
|
+
);
|
|
24835
|
+
}
|
|
24836
|
+
function catalogModelLastSegment(value) {
|
|
24837
|
+
if (value.startsWith("[")) {
|
|
24838
|
+
let parsed;
|
|
24839
|
+
try {
|
|
24840
|
+
parsed = JSON.parse(value);
|
|
24841
|
+
} catch {
|
|
24842
|
+
return void 0;
|
|
24843
|
+
}
|
|
24844
|
+
if (!Array.isArray(parsed) || parsed.length < 2) return void 0;
|
|
24845
|
+
const last = parsed[parsed.length - 1];
|
|
24846
|
+
return typeof last === "string" ? last : void 0;
|
|
24847
|
+
}
|
|
24848
|
+
const separator = value.indexOf("/");
|
|
24849
|
+
return separator > 0 && separator < value.length - 1 ? value.slice(separator + 1) : void 0;
|
|
24850
|
+
}
|
|
24851
|
+
function matchAdvertisedModelValue(requestedModelId, advertisedValues) {
|
|
24852
|
+
const wanted = requestedModelId.trim();
|
|
24853
|
+
if (!wanted) return void 0;
|
|
24854
|
+
if (advertisedValues.includes(wanted)) return wanted;
|
|
24855
|
+
const byLastSegment = advertisedValues.filter(
|
|
24856
|
+
(value) => catalogModelLastSegment(value) === wanted
|
|
24857
|
+
);
|
|
24858
|
+
return byLastSegment.length === 1 ? byLastSegment[0] : void 0;
|
|
24859
|
+
}
|
|
24639
24860
|
function parseSessionModeState(sessionResponse) {
|
|
24640
24861
|
const modes = sessionResponse.modes;
|
|
24641
24862
|
if (!modes) return void 0;
|
|
@@ -24674,7 +24895,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24674
24895
|
}
|
|
24675
24896
|
const commands = [];
|
|
24676
24897
|
for (const command of availableCommands) {
|
|
24677
|
-
if (!
|
|
24898
|
+
if (!isRecord5(command)) {
|
|
24678
24899
|
continue;
|
|
24679
24900
|
}
|
|
24680
24901
|
const name = typeof command["name"] === "string" ? command["name"].trim() : "";
|
|
@@ -24682,7 +24903,7 @@ function parseAvailableCommandsUpdate(params) {
|
|
|
24682
24903
|
continue;
|
|
24683
24904
|
}
|
|
24684
24905
|
const description = typeof command["description"] === "string" ? command["description"].trim() || void 0 : void 0;
|
|
24685
|
-
const input2 =
|
|
24906
|
+
const input2 = isRecord5(command["input"]) ? command["input"] : void 0;
|
|
24686
24907
|
const inputHint = typeof input2?.["hint"] === "string" ? input2["hint"].trim() || void 0 : void 0;
|
|
24687
24908
|
commands.push({
|
|
24688
24909
|
name,
|
|
@@ -24744,7 +24965,7 @@ function extractCommandFromTitle2(title) {
|
|
|
24744
24965
|
return match?.[1]?.trim() || void 0;
|
|
24745
24966
|
}
|
|
24746
24967
|
function extractToolCallCommand(rawInput, title) {
|
|
24747
|
-
if (
|
|
24968
|
+
if (isRecord5(rawInput)) {
|
|
24748
24969
|
const directCommand = normalizeCommandValue2(rawInput["command"]);
|
|
24749
24970
|
if (directCommand) {
|
|
24750
24971
|
return directCommand;
|
|
@@ -24771,7 +24992,7 @@ function boundToolCallOutputText(text) {
|
|
|
24771
24992
|
}
|
|
24772
24993
|
var RAW_OUTPUT_TEXT_FIELDS = ["content", "stdout", "stderr", "output"];
|
|
24773
24994
|
function boundToolCallRawOutput(rawOutput) {
|
|
24774
|
-
if (!
|
|
24995
|
+
if (!isRecord5(rawOutput)) {
|
|
24775
24996
|
return rawOutput;
|
|
24776
24997
|
}
|
|
24777
24998
|
let changed = false;
|
|
@@ -25001,7 +25222,7 @@ function parseSessionUpdateEvent(params) {
|
|
|
25001
25222
|
const entries = Array.isArray(upd["entries"]) ? upd["entries"] : [];
|
|
25002
25223
|
const plan = entries.map((entry, index) => ({
|
|
25003
25224
|
step: readAcpText(entry, "content") ?? `Step ${index + 1}`,
|
|
25004
|
-
status: normalizePlanStepStatus(
|
|
25225
|
+
status: normalizePlanStepStatus(isRecord5(entry) ? entry["status"] : void 0)
|
|
25005
25226
|
}));
|
|
25006
25227
|
if (plan.length > 0) {
|
|
25007
25228
|
events.push({
|
|
@@ -25038,21 +25259,24 @@ function parseSessionUpdateEvent(params) {
|
|
|
25038
25259
|
}
|
|
25039
25260
|
break;
|
|
25040
25261
|
}
|
|
25041
|
-
case "agent_message_chunk":
|
|
25042
|
-
|
|
25262
|
+
case "agent_message_chunk":
|
|
25263
|
+
case "agent_thought_chunk": {
|
|
25264
|
+
const content = isRecord5(upd["content"]) ? upd["content"] : void 0;
|
|
25043
25265
|
const contentType = content?.["type"];
|
|
25266
|
+
const streamKind = kind === "agent_thought_chunk" ? "reasoning_text" : "assistant_text";
|
|
25044
25267
|
if (contentType === "text") {
|
|
25045
25268
|
const text = typeof content?.["text"] === "string" ? content["text"] : "";
|
|
25046
25269
|
if (text.length > 0) {
|
|
25047
25270
|
events.push({
|
|
25048
25271
|
_tag: "ContentDelta",
|
|
25049
25272
|
text,
|
|
25273
|
+
streamKind,
|
|
25050
25274
|
rawPayload: params
|
|
25051
25275
|
});
|
|
25052
25276
|
}
|
|
25053
25277
|
break;
|
|
25054
25278
|
}
|
|
25055
|
-
if (content && contentType !== "audio") {
|
|
25279
|
+
if (streamKind === "assistant_text" && content && contentType !== "audio") {
|
|
25056
25280
|
events.push({
|
|
25057
25281
|
_tag: "AssistantContentBlock",
|
|
25058
25282
|
content,
|
|
@@ -25104,16 +25328,18 @@ function normalizeModelId(value) {
|
|
|
25104
25328
|
return value?.trim() || void 0;
|
|
25105
25329
|
}
|
|
25106
25330
|
function modelSelectionStateFromSetup(setup) {
|
|
25107
|
-
const sessionModels =
|
|
25331
|
+
const sessionModels = isRecord5(setup.models) ? setup.models : void 0;
|
|
25108
25332
|
const modelConfigId = extractModelConfigId(setup);
|
|
25109
25333
|
const strategy = sessionModels === void 0 && modelConfigId !== void 0 ? "config-option" : "session/set_model";
|
|
25110
|
-
const
|
|
25334
|
+
const modelConfigOption = modelConfigId === void 0 ? void 0 : findSessionConfigOption(setup.configOptions, modelConfigId);
|
|
25335
|
+
const configModel = modelConfigOption?.currentValue;
|
|
25111
25336
|
const currentModelId = strategy === "config-option" ? typeof configModel === "string" ? normalizeModelId(configModel) : void 0 : typeof sessionModels?.["currentModelId"] === "string" ? normalizeModelId(sessionModels["currentModelId"]) : void 0;
|
|
25112
25337
|
return {
|
|
25113
25338
|
strategy,
|
|
25114
25339
|
sessionModelsAdvertised: sessionModels !== void 0,
|
|
25115
25340
|
modelConfigId,
|
|
25116
|
-
currentModelId
|
|
25341
|
+
currentModelId,
|
|
25342
|
+
advertisedModelValues: strategy === "config-option" ? modelConfigOption === void 0 ? [] : collectSessionConfigOptionValues(modelConfigOption) : collectSessionModelIds(sessionModels)
|
|
25117
25343
|
};
|
|
25118
25344
|
}
|
|
25119
25345
|
function createAcpExecutor(options) {
|
|
@@ -25132,8 +25358,10 @@ function createAcpExecutor(options) {
|
|
|
25132
25358
|
strategy: "session/set_model",
|
|
25133
25359
|
sessionModelsAdvertised: false,
|
|
25134
25360
|
modelConfigId: void 0,
|
|
25135
|
-
currentModelId: void 0
|
|
25361
|
+
currentModelId: void 0,
|
|
25362
|
+
advertisedModelValues: []
|
|
25136
25363
|
};
|
|
25364
|
+
let lastUnmatchedModelId;
|
|
25137
25365
|
let initializeResult;
|
|
25138
25366
|
let startResult;
|
|
25139
25367
|
let startInFlight;
|
|
@@ -25268,6 +25496,23 @@ function createAcpExecutor(options) {
|
|
|
25268
25496
|
continue;
|
|
25269
25497
|
}
|
|
25270
25498
|
if (event._tag === "ContentDelta") {
|
|
25499
|
+
if (event.streamKind === "reasoning_text") {
|
|
25500
|
+
if (event.text.trim().length === 0) {
|
|
25501
|
+
continue;
|
|
25502
|
+
}
|
|
25503
|
+
emit(
|
|
25504
|
+
makeAcpContentDeltaEvent({
|
|
25505
|
+
stamp: stamp(),
|
|
25506
|
+
provider: options.provider,
|
|
25507
|
+
threadId: options.threadId,
|
|
25508
|
+
turnId: activeTurnId,
|
|
25509
|
+
text: event.text,
|
|
25510
|
+
streamKind: "reasoning_text",
|
|
25511
|
+
rawPayload: event.rawPayload
|
|
25512
|
+
})
|
|
25513
|
+
);
|
|
25514
|
+
continue;
|
|
25515
|
+
}
|
|
25271
25516
|
if (event.text.trim().length === 0 && !assistantSegment.activeItemId) {
|
|
25272
25517
|
continue;
|
|
25273
25518
|
}
|
|
@@ -25280,6 +25525,7 @@ function createAcpExecutor(options) {
|
|
|
25280
25525
|
turnId: activeTurnId,
|
|
25281
25526
|
...itemId ? { itemId } : {},
|
|
25282
25527
|
text: event.text,
|
|
25528
|
+
streamKind: "assistant_text",
|
|
25283
25529
|
rawPayload: event.rawPayload
|
|
25284
25530
|
})
|
|
25285
25531
|
);
|
|
@@ -25440,6 +25686,12 @@ function createAcpExecutor(options) {
|
|
|
25440
25686
|
const userInputOutcome = await handlePermissionAsUserInput(params);
|
|
25441
25687
|
if (userInputOutcome !== void 0) return userInputOutcome;
|
|
25442
25688
|
const permissionRequest = parsePermissionRequest(params);
|
|
25689
|
+
if (options.autoApprove?.(permissionRequest) === true) {
|
|
25690
|
+
const optionId = selectAutoApprovedAcpPermissionOption(params);
|
|
25691
|
+
if (optionId !== void 0) {
|
|
25692
|
+
return { outcome: { outcome: "selected", optionId } };
|
|
25693
|
+
}
|
|
25694
|
+
}
|
|
25443
25695
|
const requestId = randomId();
|
|
25444
25696
|
const outcome = await new Promise((resolve2) => {
|
|
25445
25697
|
const pending = {
|
|
@@ -25527,36 +25779,70 @@ function createAcpExecutor(options) {
|
|
|
25527
25779
|
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) {
|
|
25528
25780
|
return input2.state;
|
|
25529
25781
|
}
|
|
25782
|
+
const value = matchAdvertisedModelValue(requestedModelId, input2.state.advertisedModelValues);
|
|
25783
|
+
if (value === void 0) {
|
|
25784
|
+
if (requestedModelId !== lastUnmatchedModelId) {
|
|
25785
|
+
lastUnmatchedModelId = requestedModelId;
|
|
25786
|
+
options.log?.info("requested model is not in the agent catalog; keeping its own model", {
|
|
25787
|
+
requestedModelId,
|
|
25788
|
+
currentModelId: input2.state.currentModelId,
|
|
25789
|
+
advertisedModelValues: input2.state.advertisedModelValues
|
|
25790
|
+
});
|
|
25791
|
+
}
|
|
25792
|
+
return input2.state;
|
|
25793
|
+
}
|
|
25794
|
+
if (value === input2.state.currentModelId) {
|
|
25795
|
+
return input2.state;
|
|
25796
|
+
}
|
|
25530
25797
|
if (input2.state.strategy === "config-option") {
|
|
25531
25798
|
await connection.request("session/set_config_option", {
|
|
25532
25799
|
sessionId: input2.acpSessionId,
|
|
25533
25800
|
configId: input2.state.modelConfigId,
|
|
25534
|
-
value
|
|
25801
|
+
value
|
|
25535
25802
|
});
|
|
25536
25803
|
} else {
|
|
25537
25804
|
await connection.request("session/set_model", {
|
|
25538
25805
|
sessionId: input2.acpSessionId,
|
|
25539
|
-
modelId:
|
|
25806
|
+
modelId: value
|
|
25540
25807
|
});
|
|
25541
25808
|
}
|
|
25542
25809
|
if (!isLive(input2.expectedGeneration)) {
|
|
25543
25810
|
throw new AcpExecutorDisposedError();
|
|
25544
25811
|
}
|
|
25545
|
-
return { ...input2.state, currentModelId:
|
|
25812
|
+
return { ...input2.state, currentModelId: value };
|
|
25813
|
+
};
|
|
25814
|
+
const applyRequestedEffort = async (input2) => {
|
|
25815
|
+
const requested = input2.requestedEffort?.trim();
|
|
25816
|
+
if (!requested) return;
|
|
25817
|
+
const configOptions = typeof input2.setup === "object" && input2.setup !== null ? input2.setup.configOptions : void 0;
|
|
25818
|
+
const effort = findAcpEffortConfig(configOptions);
|
|
25819
|
+
if (effort === void 0) return;
|
|
25820
|
+
const matched = effort.choices.find((choice) => choice.value === requested);
|
|
25821
|
+
if (matched === void 0) {
|
|
25822
|
+
options.log?.info("requested effort is not in the agent catalog; keeping its own", {
|
|
25823
|
+
requestedEffort: requested,
|
|
25824
|
+
advertised: effort.choices.map((choice) => choice.value)
|
|
25825
|
+
});
|
|
25826
|
+
return;
|
|
25827
|
+
}
|
|
25828
|
+
if (matched.isDefault === true) return;
|
|
25829
|
+
if (!isLive(input2.expectedGeneration)) return;
|
|
25830
|
+
try {
|
|
25831
|
+
await connection.request("session/set_config_option", {
|
|
25832
|
+
sessionId: input2.acpSessionId,
|
|
25833
|
+
configId: effort.configId,
|
|
25834
|
+
value: requested
|
|
25835
|
+
});
|
|
25836
|
+
} catch (error62) {
|
|
25837
|
+
options.log?.info("setting the effort level failed; the session keeps its own", {
|
|
25838
|
+
requestedEffort: requested,
|
|
25839
|
+
configId: effort.configId,
|
|
25840
|
+
error: error62 instanceof Error ? error62.message : String(error62)
|
|
25841
|
+
});
|
|
25842
|
+
}
|
|
25546
25843
|
};
|
|
25547
25844
|
const startOnce = async (expectedGeneration) => {
|
|
25548
|
-
const initializePayload =
|
|
25549
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
25550
|
-
clientCapabilities: {
|
|
25551
|
-
fs: {
|
|
25552
|
-
readTextFile: false,
|
|
25553
|
-
writeTextFile: false,
|
|
25554
|
-
...options.clientCapabilities?.fs
|
|
25555
|
-
},
|
|
25556
|
-
terminal: options.clientCapabilities?.terminal ?? false
|
|
25557
|
-
},
|
|
25558
|
-
clientInfo: options.clientInfo
|
|
25559
|
-
};
|
|
25845
|
+
const initializePayload = acpInitializePayload(options.clientInfo, options.clientCapabilities);
|
|
25560
25846
|
const initialized = await connection.request(
|
|
25561
25847
|
"initialize",
|
|
25562
25848
|
initializePayload
|
|
@@ -25600,12 +25886,27 @@ function createAcpExecutor(options) {
|
|
|
25600
25886
|
nextSessionId = created.sessionId;
|
|
25601
25887
|
setup = created;
|
|
25602
25888
|
}
|
|
25889
|
+
const unhandledCategories = unhandledConfigCategories(
|
|
25890
|
+
setup.configOptions
|
|
25891
|
+
);
|
|
25892
|
+
if (unhandledCategories.length > 0) {
|
|
25893
|
+
options.log?.info("acp session reported config option categories we do not handle", {
|
|
25894
|
+
sessionId: nextSessionId,
|
|
25895
|
+
categories: unhandledCategories
|
|
25896
|
+
});
|
|
25897
|
+
}
|
|
25603
25898
|
const nextModelSelectionState = await applyRequestedModel({
|
|
25604
25899
|
state: modelSelectionStateFromSetup(setup),
|
|
25605
25900
|
acpSessionId: nextSessionId,
|
|
25606
25901
|
requestedModelId: options.requestedModelId,
|
|
25607
25902
|
expectedGeneration
|
|
25608
25903
|
});
|
|
25904
|
+
await applyRequestedEffort({
|
|
25905
|
+
setup,
|
|
25906
|
+
acpSessionId: nextSessionId,
|
|
25907
|
+
requestedEffort: options.requestedEffort,
|
|
25908
|
+
expectedGeneration
|
|
25909
|
+
});
|
|
25609
25910
|
if (options.beforeApplyResult) {
|
|
25610
25911
|
await options.beforeApplyResult();
|
|
25611
25912
|
}
|
|
@@ -25970,6 +26271,26 @@ function createAcpExecutor(options) {
|
|
|
25970
26271
|
};
|
|
25971
26272
|
apply();
|
|
25972
26273
|
};
|
|
26274
|
+
const setNativeMode = async (modeId) => {
|
|
26275
|
+
failIfDisposed();
|
|
26276
|
+
const started = startResult;
|
|
26277
|
+
if (started === void 0) {
|
|
26278
|
+
throw new AcpExecutorRequestError("session/set_mode", "session has not started yet");
|
|
26279
|
+
}
|
|
26280
|
+
const configId = acpModeConfigId(started.sessionSetupResult);
|
|
26281
|
+
if (configId !== void 0) {
|
|
26282
|
+
await connection.request("session/set_config_option", {
|
|
26283
|
+
sessionId: started.sessionId,
|
|
26284
|
+
configId,
|
|
26285
|
+
value: modeId
|
|
26286
|
+
});
|
|
26287
|
+
return;
|
|
26288
|
+
}
|
|
26289
|
+
await connection.request("session/set_mode", {
|
|
26290
|
+
sessionId: started.sessionId,
|
|
26291
|
+
modeId
|
|
26292
|
+
});
|
|
26293
|
+
};
|
|
25973
26294
|
const respondToUserInput = async (requestId, answers) => {
|
|
25974
26295
|
failIfDisposed();
|
|
25975
26296
|
const pending = pendingUserInputs.get(requestId);
|
|
@@ -25986,7 +26307,7 @@ function createAcpExecutor(options) {
|
|
|
25986
26307
|
pendingUserInputs.delete(requestId);
|
|
25987
26308
|
pending.resolve({
|
|
25988
26309
|
kind: "answered",
|
|
25989
|
-
answers:
|
|
26310
|
+
answers: isRecord5(answers) ? answers : {}
|
|
25990
26311
|
});
|
|
25991
26312
|
};
|
|
25992
26313
|
const dispose = async () => {
|
|
@@ -26036,13 +26357,56 @@ function createAcpExecutor(options) {
|
|
|
26036
26357
|
cancel,
|
|
26037
26358
|
respondToRequest,
|
|
26038
26359
|
respondToUserInput,
|
|
26360
|
+
setNativeMode,
|
|
26039
26361
|
dispose
|
|
26040
26362
|
};
|
|
26041
26363
|
}
|
|
26042
26364
|
|
|
26365
|
+
// ../../packages/ycodium-acp-executor/src/probe.ts
|
|
26366
|
+
function withProbeTimeout(promise2, timeoutMs, method) {
|
|
26367
|
+
return new Promise((resolve2, reject) => {
|
|
26368
|
+
const timer = setTimeout(() => {
|
|
26369
|
+
reject(new Error(`ACP probe request '${method}' timed out after ${timeoutMs}ms`));
|
|
26370
|
+
}, timeoutMs);
|
|
26371
|
+
timer.unref?.();
|
|
26372
|
+
promise2.then(
|
|
26373
|
+
(value) => {
|
|
26374
|
+
clearTimeout(timer);
|
|
26375
|
+
resolve2(value);
|
|
26376
|
+
},
|
|
26377
|
+
(error62) => {
|
|
26378
|
+
clearTimeout(timer);
|
|
26379
|
+
reject(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
26380
|
+
}
|
|
26381
|
+
);
|
|
26382
|
+
});
|
|
26383
|
+
}
|
|
26384
|
+
async function openAcpProbeHandshake(input2) {
|
|
26385
|
+
const connection = createAcpConnection({
|
|
26386
|
+
readable: input2.readable,
|
|
26387
|
+
writable: input2.writable,
|
|
26388
|
+
onNotification: () => void 0
|
|
26389
|
+
});
|
|
26390
|
+
try {
|
|
26391
|
+
const initializeResult = await withProbeTimeout(
|
|
26392
|
+
connection.request("initialize", acpInitializePayload(input2.clientInfo)),
|
|
26393
|
+
input2.requestTimeoutMs,
|
|
26394
|
+
"initialize"
|
|
26395
|
+
);
|
|
26396
|
+
return {
|
|
26397
|
+
initializeResult,
|
|
26398
|
+
request: (method, params) => withProbeTimeout(connection.request(method, params), input2.requestTimeoutMs, method),
|
|
26399
|
+
close: () => connection.close()
|
|
26400
|
+
};
|
|
26401
|
+
} catch (error62) {
|
|
26402
|
+
await connection.close().catch(() => void 0);
|
|
26403
|
+
throw error62;
|
|
26404
|
+
}
|
|
26405
|
+
}
|
|
26406
|
+
|
|
26043
26407
|
// src/config.ts
|
|
26044
26408
|
var GROK_DEFAULT_LAUNCH_ARGS = "agent stdio";
|
|
26045
|
-
function
|
|
26409
|
+
function isRecord6(value) {
|
|
26046
26410
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26047
26411
|
}
|
|
26048
26412
|
function readString(value) {
|
|
@@ -26055,7 +26419,7 @@ function readEnvironment(value) {
|
|
|
26055
26419
|
if (!Array.isArray(value)) return {};
|
|
26056
26420
|
const env = {};
|
|
26057
26421
|
for (const entry of value) {
|
|
26058
|
-
if (!
|
|
26422
|
+
if (!isRecord6(entry)) continue;
|
|
26059
26423
|
const name = readTrimmed(entry["name"]);
|
|
26060
26424
|
if (name.length === 0) continue;
|
|
26061
26425
|
env[name] = readString(entry["value"]);
|
|
@@ -26063,7 +26427,7 @@ function readEnvironment(value) {
|
|
|
26063
26427
|
return env;
|
|
26064
26428
|
}
|
|
26065
26429
|
function parseGrokInstanceConfig(config2) {
|
|
26066
|
-
if (!
|
|
26430
|
+
if (!isRecord6(config2)) {
|
|
26067
26431
|
return {
|
|
26068
26432
|
binaryPath: "",
|
|
26069
26433
|
launchArgs: GROK_DEFAULT_LAUNCH_ARGS,
|
|
@@ -26073,7 +26437,7 @@ function parseGrokInstanceConfig(config2) {
|
|
|
26073
26437
|
envelopeDriver: void 0
|
|
26074
26438
|
};
|
|
26075
26439
|
}
|
|
26076
|
-
const nested =
|
|
26440
|
+
const nested = isRecord6(config2["config"]) ? config2["config"] : void 0;
|
|
26077
26441
|
const settings = nested ?? config2;
|
|
26078
26442
|
return {
|
|
26079
26443
|
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
@@ -26140,7 +26504,7 @@ function tokenizeLaunchArgs(value) {
|
|
|
26140
26504
|
import * as NodeFS from "node:fs";
|
|
26141
26505
|
import * as NodePath from "node:path";
|
|
26142
26506
|
var AUTH_FILE_NAME = "auth.json";
|
|
26143
|
-
var
|
|
26507
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26144
26508
|
var readString2 = (record2, key) => {
|
|
26145
26509
|
const value = record2[key];
|
|
26146
26510
|
if (typeof value !== "string") return void 0;
|
|
@@ -26154,7 +26518,7 @@ var parseJsonRecord = (raw) => {
|
|
|
26154
26518
|
} catch {
|
|
26155
26519
|
return void 0;
|
|
26156
26520
|
}
|
|
26157
|
-
return
|
|
26521
|
+
return isRecord7(parsed) ? parsed : void 0;
|
|
26158
26522
|
};
|
|
26159
26523
|
var directoryExists = (homePath) => {
|
|
26160
26524
|
try {
|
|
@@ -26192,7 +26556,7 @@ var joinName = (record2) => {
|
|
|
26192
26556
|
};
|
|
26193
26557
|
var findIdentityEntry = (parsed) => {
|
|
26194
26558
|
for (const value of Object.values(parsed)) {
|
|
26195
|
-
if (!
|
|
26559
|
+
if (!isRecord7(value)) continue;
|
|
26196
26560
|
if (readString2(value, "email") !== void 0 || readString2(value, "user_id") !== void 0) {
|
|
26197
26561
|
return value;
|
|
26198
26562
|
}
|
|
@@ -26222,7 +26586,8 @@ var readGrokAccount = (homePath) => {
|
|
|
26222
26586
|
};
|
|
26223
26587
|
|
|
26224
26588
|
// src/grokSupport.ts
|
|
26225
|
-
|
|
26589
|
+
import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
|
|
26590
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26226
26591
|
var trimmed = (value) => {
|
|
26227
26592
|
if (typeof value !== "string") return void 0;
|
|
26228
26593
|
const text = value.trim();
|
|
@@ -26232,51 +26597,153 @@ function grokReasoningEffortArgs(effort) {
|
|
|
26232
26597
|
const value = effort?.trim();
|
|
26233
26598
|
return value === void 0 || value.length === 0 ? [] : ["--reasoning-effort", value];
|
|
26234
26599
|
}
|
|
26235
|
-
var
|
|
26236
|
-
|
|
26237
|
-
|
|
26238
|
-
|
|
26239
|
-
|
|
26240
|
-
|
|
26241
|
-
|
|
26242
|
-
|
|
26243
|
-
|
|
26600
|
+
var GROK_NATIVE_MODE_BY_RUNTIME_MODE = {
|
|
26601
|
+
"approval-required": "default",
|
|
26602
|
+
"auto-accept-edits": "auto",
|
|
26603
|
+
auto: "auto",
|
|
26604
|
+
"full-access": "bypassPermissions"
|
|
26605
|
+
};
|
|
26606
|
+
var GROK_NATIVE_MODES = [
|
|
26607
|
+
{
|
|
26608
|
+
id: "default",
|
|
26609
|
+
name: "Ask every time",
|
|
26610
|
+
description: "Asks before writing files, running commands, or spawning subagents."
|
|
26611
|
+
},
|
|
26612
|
+
{
|
|
26613
|
+
id: "auto",
|
|
26614
|
+
name: "Auto",
|
|
26615
|
+
description: "Runs edits and subagents without asking; still asks for shell writes and monitor."
|
|
26616
|
+
},
|
|
26617
|
+
{
|
|
26618
|
+
id: "bypassPermissions",
|
|
26619
|
+
name: "Bypass permissions",
|
|
26620
|
+
description: "Never asks. Every tool runs immediately."
|
|
26244
26621
|
}
|
|
26245
|
-
|
|
26622
|
+
];
|
|
26623
|
+
var GROK_DEFAULT_NATIVE_MODE_ID = "default";
|
|
26624
|
+
var GROK_NATIVE_MODE_REPORT = {
|
|
26625
|
+
nativeModes: GROK_NATIVE_MODES.map((mode) => ({
|
|
26626
|
+
id: mode.id,
|
|
26627
|
+
name: mode.name,
|
|
26628
|
+
description: mode.description
|
|
26629
|
+
})),
|
|
26630
|
+
currentNativeModeId: GROK_DEFAULT_NATIVE_MODE_ID,
|
|
26631
|
+
nativeModeByRuntimeMode: GROK_NATIVE_MODE_BY_RUNTIME_MODE
|
|
26632
|
+
};
|
|
26633
|
+
function isGrokNativeModeId(value) {
|
|
26634
|
+
return GROK_NATIVE_MODES.some((mode) => mode.id === value);
|
|
26635
|
+
}
|
|
26636
|
+
function grokPermissionModeFor(runtimeMode, nativeModeId) {
|
|
26637
|
+
return nativeModeId !== void 0 && isGrokNativeModeId(nativeModeId) ? nativeModeId : GROK_NATIVE_MODE_BY_RUNTIME_MODE[runtimeMode];
|
|
26638
|
+
}
|
|
26639
|
+
function grokPermissionModeArgs(runtimeMode, nativeModeId) {
|
|
26640
|
+
return ["--permission-mode", grokPermissionModeFor(runtimeMode, nativeModeId)];
|
|
26641
|
+
}
|
|
26642
|
+
var GROK_AUTO_APPROVAL_COVERAGE = {
|
|
26643
|
+
asked: ["run_terminal_command", "monitor"],
|
|
26644
|
+
unasked: [
|
|
26645
|
+
"write",
|
|
26646
|
+
"search_replace",
|
|
26647
|
+
"read_file",
|
|
26648
|
+
"todo_write",
|
|
26649
|
+
"web_search",
|
|
26650
|
+
"scheduler_create",
|
|
26651
|
+
"spawn_subagent",
|
|
26652
|
+
"workflow",
|
|
26653
|
+
"use_tool",
|
|
26654
|
+
"send_feedback",
|
|
26655
|
+
"image_gen"
|
|
26656
|
+
]
|
|
26657
|
+
};
|
|
26658
|
+
var GROK_APPROVAL_COVERAGE = {
|
|
26659
|
+
default: {
|
|
26660
|
+
asked: [
|
|
26661
|
+
"write",
|
|
26662
|
+
"search_replace",
|
|
26663
|
+
"run_terminal_command",
|
|
26664
|
+
"monitor",
|
|
26665
|
+
"spawn_subagent",
|
|
26666
|
+
"workflow",
|
|
26667
|
+
"scheduler_create",
|
|
26668
|
+
"use_tool",
|
|
26669
|
+
"send_feedback",
|
|
26670
|
+
"image_gen"
|
|
26671
|
+
],
|
|
26672
|
+
unasked: ["read_file", "todo_write", "web_search"]
|
|
26673
|
+
},
|
|
26674
|
+
// 「编辑不问、命令仍问」的那一档,实测只剩 shell 写删与 monitor 会问——落差就是
|
|
26675
|
+
// 这条要说的。
|
|
26676
|
+
auto: GROK_AUTO_APPROVAL_COVERAGE,
|
|
26677
|
+
// 全放行:档位自己就说「不问」,没有落差可报。
|
|
26678
|
+
bypassPermissions: null
|
|
26679
|
+
};
|
|
26680
|
+
var GROK_EXTERNAL_PERMISSION_RULES_PATHS = [
|
|
26681
|
+
// 顺序无语义:**这不是优先级表**,只是文案里列出来的次序(碰巧按用户级 → 用户本地
|
|
26682
|
+
// → 机器级排,别读出别的意思)。三份同时给冲突规则时谁赢**没量过**,别照这个顺序
|
|
26683
|
+
// 推断;要用就先量。唯一量过的相邻关系是「`settings.local.json` 的 `deny` 赢过
|
|
26684
|
+
// `settings.json` 的 `allow`」(F13 `loc-local-deny`)。
|
|
26685
|
+
"~/.claude/settings.json",
|
|
26686
|
+
"~/.claude/settings.local.json",
|
|
26687
|
+
"/etc/claude-code/managed-settings.json"
|
|
26688
|
+
];
|
|
26689
|
+
var RUNTIME_MODE_APPROVAL_COVERAGE_CODE = "runtime-mode-approval-coverage";
|
|
26690
|
+
function grokRuntimeModeCaveat(nativeModeId) {
|
|
26691
|
+
const coverage = GROK_APPROVAL_COVERAGE[nativeModeId];
|
|
26692
|
+
if (coverage === null) return void 0;
|
|
26693
|
+
const message = `Approval prompts do not cover every Grok tool in this mode. No prompt, inside or outside the workspace: ${coverage.unasked.join(", ")}, plus shell commands Grok rates safe such as \`touch\`. Prompts: ${coverage.asked.join(", ")}. Permission rules in ${GROK_EXTERNAL_PERMISSION_RULES_PATHS.join(", ")} override this mode \u2014 a matching allow entry drops the prompt, a matching deny entry blocks the call outright.`;
|
|
26694
|
+
return {
|
|
26695
|
+
code: RUNTIME_MODE_APPROVAL_COVERAGE_CODE,
|
|
26696
|
+
nativeModeId,
|
|
26697
|
+
asked: coverage.asked,
|
|
26698
|
+
unasked: coverage.unasked,
|
|
26699
|
+
externalRulesPaths: GROK_EXTERNAL_PERMISSION_RULES_PATHS,
|
|
26700
|
+
message
|
|
26701
|
+
};
|
|
26246
26702
|
}
|
|
26703
|
+
var GROK_REASONING_OPTION_ID = "reasoningEffort";
|
|
26247
26704
|
function resolveGrokAuthMethodId(initializeResult) {
|
|
26248
|
-
const authMethods =
|
|
26705
|
+
const authMethods = isRecord8(initializeResult) ? initializeResult["authMethods"] : void 0;
|
|
26249
26706
|
if (!Array.isArray(authMethods)) return void 0;
|
|
26250
26707
|
for (const method of authMethods) {
|
|
26251
|
-
if (
|
|
26708
|
+
if (isRecord8(method) && method["id"] === "cached_token") return "cached_token";
|
|
26252
26709
|
}
|
|
26253
26710
|
return void 0;
|
|
26254
26711
|
}
|
|
26255
26712
|
var positive = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
26256
26713
|
function grokPromptUsage(promptResponse) {
|
|
26257
|
-
if (!
|
|
26714
|
+
if (!isRecord8(promptResponse)) return void 0;
|
|
26258
26715
|
const meta3 = promptResponse["_meta"];
|
|
26259
|
-
if (!
|
|
26716
|
+
if (!isRecord8(meta3)) return void 0;
|
|
26260
26717
|
const usedTokens = positive(meta3["totalTokens"]);
|
|
26261
26718
|
if (usedTokens === void 0) return void 0;
|
|
26262
26719
|
return { usedTokens, modelId: trimmed(meta3["modelId"]) };
|
|
26263
26720
|
}
|
|
26264
|
-
function
|
|
26265
|
-
if (!
|
|
26721
|
+
function grokModelState(initializeResult) {
|
|
26722
|
+
if (!isRecord8(initializeResult)) return void 0;
|
|
26266
26723
|
const meta3 = initializeResult["_meta"];
|
|
26267
|
-
if (!
|
|
26724
|
+
if (!isRecord8(meta3)) return void 0;
|
|
26268
26725
|
const modelState = meta3["modelState"];
|
|
26269
|
-
if (!
|
|
26726
|
+
if (!isRecord8(modelState)) return void 0;
|
|
26270
26727
|
const availableModels = modelState["availableModels"];
|
|
26271
|
-
if (!Array.isArray(availableModels)) return
|
|
26728
|
+
if (!Array.isArray(availableModels)) return void 0;
|
|
26729
|
+
return { currentModelId: trimmed(modelState["currentModelId"]), availableModels };
|
|
26730
|
+
}
|
|
26731
|
+
function grokAdvertisedModels(initializeResult) {
|
|
26732
|
+
const state = grokModelState(initializeResult);
|
|
26733
|
+
if (state === void 0) return [];
|
|
26272
26734
|
const models = [];
|
|
26273
|
-
for (const entry of availableModels) {
|
|
26274
|
-
if (!
|
|
26735
|
+
for (const entry of state.availableModels) {
|
|
26736
|
+
if (!isRecord8(entry)) continue;
|
|
26275
26737
|
const modelId = trimmed(entry["modelId"]);
|
|
26276
26738
|
if (modelId === void 0) continue;
|
|
26277
26739
|
const modelMeta = entry["_meta"];
|
|
26278
|
-
const contextWindow =
|
|
26279
|
-
models.push({
|
|
26740
|
+
const contextWindow = isRecord8(modelMeta) ? positive(modelMeta["totalContextTokens"]) : void 0;
|
|
26741
|
+
models.push({
|
|
26742
|
+
modelId,
|
|
26743
|
+
name: trimmed(entry["name"]),
|
|
26744
|
+
isDefault: state.currentModelId !== void 0 && modelId === state.currentModelId,
|
|
26745
|
+
contextWindow
|
|
26746
|
+
});
|
|
26280
26747
|
}
|
|
26281
26748
|
return models;
|
|
26282
26749
|
}
|
|
@@ -26285,7 +26752,7 @@ var XAI_ASK_USER_QUESTION_METHODS = [
|
|
|
26285
26752
|
"x.ai/ask_user_question"
|
|
26286
26753
|
];
|
|
26287
26754
|
var readOption = (value) => {
|
|
26288
|
-
if (!
|
|
26755
|
+
if (!isRecord8(value)) return void 0;
|
|
26289
26756
|
const label = typeof value["label"] === "string" ? value["label"] : void 0;
|
|
26290
26757
|
if (label === void 0) return void 0;
|
|
26291
26758
|
return {
|
|
@@ -26296,7 +26763,7 @@ var readOption = (value) => {
|
|
|
26296
26763
|
};
|
|
26297
26764
|
};
|
|
26298
26765
|
var readQuestion = (value) => {
|
|
26299
|
-
if (!
|
|
26766
|
+
if (!isRecord8(value)) return void 0;
|
|
26300
26767
|
const question = typeof value["question"] === "string" ? value["question"] : void 0;
|
|
26301
26768
|
if (question === void 0) return void 0;
|
|
26302
26769
|
const optionsRaw = value["options"];
|
|
@@ -26312,9 +26779,9 @@ var readQuestion = (value) => {
|
|
|
26312
26779
|
};
|
|
26313
26780
|
};
|
|
26314
26781
|
function parseXAiAskUserQuestionParams(params) {
|
|
26315
|
-
const candidates = [params, ...
|
|
26782
|
+
const candidates = [params, ...isRecord8(params) ? [params["params"]] : []];
|
|
26316
26783
|
for (const candidate of candidates) {
|
|
26317
|
-
if (!
|
|
26784
|
+
if (!isRecord8(candidate)) continue;
|
|
26318
26785
|
const questionsRaw = candidate["questions"];
|
|
26319
26786
|
if (!Array.isArray(questionsRaw)) continue;
|
|
26320
26787
|
const questions = questionsRaw.flatMap((entry) => {
|
|
@@ -26391,14 +26858,14 @@ var grokPromptSettlement = {
|
|
|
26391
26858
|
// agent 认回哪个键是它的事,两个都给才不猜版本。
|
|
26392
26859
|
requestFields: (promptKey) => ({ _meta: { promptId: promptKey, requestId: promptKey } }),
|
|
26393
26860
|
responseKey: (response) => {
|
|
26394
|
-
if (!
|
|
26861
|
+
if (!isRecord8(response)) return void 0;
|
|
26395
26862
|
const meta3 = response["_meta"];
|
|
26396
|
-
if (!
|
|
26863
|
+
if (!isRecord8(meta3)) return void 0;
|
|
26397
26864
|
return trimmed(meta3["promptId"]) ?? trimmed(meta3["requestId"]);
|
|
26398
26865
|
},
|
|
26399
26866
|
fromNotification: (method, params) => {
|
|
26400
26867
|
if (method !== XAI_PROMPT_COMPLETE_METHOD) return void 0;
|
|
26401
|
-
if (!
|
|
26868
|
+
if (!isRecord8(params)) return void 0;
|
|
26402
26869
|
const sessionId = params["sessionId"];
|
|
26403
26870
|
if (typeof sessionId !== "string") return void 0;
|
|
26404
26871
|
const stopReason = trimmed(params["stopReason"]);
|
|
@@ -26412,57 +26879,53 @@ var grokPromptSettlement = {
|
|
|
26412
26879
|
}
|
|
26413
26880
|
};
|
|
26414
26881
|
|
|
26415
|
-
// src/
|
|
26416
|
-
import
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
}
|
|
26439
|
-
|
|
26440
|
-
|
|
26441
|
-
|
|
26442
|
-
|
|
26443
|
-
|
|
26444
|
-
|
|
26445
|
-
|
|
26446
|
-
|
|
26447
|
-
|
|
26448
|
-
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26452
|
-
|
|
26453
|
-
|
|
26454
|
-
|
|
26455
|
-
|
|
26456
|
-
|
|
26457
|
-
|
|
26458
|
-
}
|
|
26459
|
-
});
|
|
26460
|
-
return { readable, writable };
|
|
26882
|
+
// src/probeModels.ts
|
|
26883
|
+
import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
|
|
26884
|
+
var PROBE_REQUEST_TIMEOUT_MS = 2e4;
|
|
26885
|
+
function grokProbeModels(initializeResult) {
|
|
26886
|
+
if (grokModelState(initializeResult) === void 0) return void 0;
|
|
26887
|
+
return grokAdvertisedModels(initializeResult).map((model) => ({
|
|
26888
|
+
slug: model.modelId,
|
|
26889
|
+
...model.name === void 0 ? {} : { name: model.name },
|
|
26890
|
+
...model.isDefault ? { isDefault: true } : {},
|
|
26891
|
+
...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow }
|
|
26892
|
+
}));
|
|
26893
|
+
}
|
|
26894
|
+
var failureDetail = (error62) => (error62 instanceof Error ? error62.message : String(error62)).trim() || void 0;
|
|
26895
|
+
async function probeGrokModels(input2) {
|
|
26896
|
+
const { recipe, host, env } = input2;
|
|
26897
|
+
let handle;
|
|
26898
|
+
try {
|
|
26899
|
+
handle = await host.process.spawn({
|
|
26900
|
+
program: recipe.binaryPath,
|
|
26901
|
+
args: tokenizeLaunchArgs(recipe.launchArgs),
|
|
26902
|
+
cwd: process.cwd(),
|
|
26903
|
+
owner: { bindingId: host.bindingId },
|
|
26904
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
26905
|
+
});
|
|
26906
|
+
} catch (error62) {
|
|
26907
|
+
return { kind: "not-started", detail: failureDetail(error62) };
|
|
26908
|
+
}
|
|
26909
|
+
let handshake;
|
|
26910
|
+
try {
|
|
26911
|
+
const { readable, writable } = nodeStreamsFromHandle(handle);
|
|
26912
|
+
handshake = await openAcpProbeHandshake({
|
|
26913
|
+
readable,
|
|
26914
|
+
writable,
|
|
26915
|
+
clientInfo: GROK_CLIENT_INFO,
|
|
26916
|
+
requestTimeoutMs: PROBE_REQUEST_TIMEOUT_MS
|
|
26917
|
+
});
|
|
26918
|
+
return { kind: "answered", models: grokProbeModels(handshake.initializeResult) };
|
|
26919
|
+
} catch (error62) {
|
|
26920
|
+
return { kind: "failed", detail: failureDetail(error62) };
|
|
26921
|
+
} finally {
|
|
26922
|
+
await handshake?.close().catch(() => void 0);
|
|
26923
|
+
await handle.kill("SIGTERM").catch(() => void 0);
|
|
26924
|
+
}
|
|
26461
26925
|
}
|
|
26462
26926
|
|
|
26463
26927
|
// src/grokInstance.ts
|
|
26464
26928
|
var RESUME_SCHEMA_VERSION = 1;
|
|
26465
|
-
var CLIENT_INFO = { name: "ycodium-agent-grok", version: "0.1.0" };
|
|
26466
26929
|
var yieldTick = () => new Promise((resolve2) => {
|
|
26467
26930
|
setImmediate(resolve2);
|
|
26468
26931
|
});
|
|
@@ -26522,21 +26985,15 @@ function resolveAccountHomePath(recipe, configuredHome) {
|
|
|
26522
26985
|
}
|
|
26523
26986
|
return resolveGrokHomePath(configuredHome);
|
|
26524
26987
|
}
|
|
26525
|
-
function
|
|
26526
|
-
const out = {};
|
|
26527
|
-
for (const [key, value] of Object.entries(env)) {
|
|
26528
|
-
if (value !== void 0) out[key] = value;
|
|
26529
|
-
}
|
|
26530
|
-
return out;
|
|
26531
|
-
}
|
|
26532
|
-
function buildSpawnEnv(recipe, launch, resolvedHomePath, homeConfigured) {
|
|
26988
|
+
function buildSpawnEnv(recipe, resolvedHomePath, homeConfigured, launchEnv = {}) {
|
|
26533
26989
|
const homeInjection = homeConfigured ? { [GROK_CARD.homeEnvVar]: resolvedHomePath } : {};
|
|
26534
|
-
return {
|
|
26535
|
-
|
|
26536
|
-
|
|
26537
|
-
|
|
26538
|
-
GROK_OAUTH2_REFERRER: "ycodium"
|
|
26539
|
-
|
|
26990
|
+
return mergeLaunchEnv({
|
|
26991
|
+
brainSlots: brainSlotEnvKeys(GROK_CARD),
|
|
26992
|
+
accountHome: homeInjection,
|
|
26993
|
+
instanceTable: recipe.environment,
|
|
26994
|
+
handOverrides: { GROK_OAUTH2_REFERRER: "ycodium" },
|
|
26995
|
+
launch: launchEnv
|
|
26996
|
+
});
|
|
26540
26997
|
}
|
|
26541
26998
|
function nowIso() {
|
|
26542
26999
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -26580,24 +27037,49 @@ var createGrokInstance = (config2, host) => {
|
|
|
26580
27037
|
return { status: "unknown" };
|
|
26581
27038
|
}
|
|
26582
27039
|
};
|
|
26583
|
-
const
|
|
26584
|
-
|
|
26585
|
-
if (recipe.binaryPath.length === 0) {
|
|
26586
|
-
return {
|
|
26587
|
-
installed: false,
|
|
26588
|
-
version: null,
|
|
26589
|
-
readiness: "error",
|
|
26590
|
-
auth: { status: "unknown" },
|
|
26591
|
-
detail: "Grok program path is not configured"
|
|
26592
|
-
};
|
|
26593
|
-
}
|
|
27040
|
+
const probe = async () => {
|
|
27041
|
+
if (recipe.binaryPath.length === 0) {
|
|
26594
27042
|
return {
|
|
26595
|
-
installed:
|
|
27043
|
+
installed: false,
|
|
26596
27044
|
version: null,
|
|
26597
|
-
readiness: "
|
|
26598
|
-
auth:
|
|
27045
|
+
readiness: "error",
|
|
27046
|
+
auth: { status: "unknown" },
|
|
27047
|
+
detail: "Grok program path is not configured"
|
|
26599
27048
|
};
|
|
26600
|
-
}
|
|
27049
|
+
}
|
|
27050
|
+
const configuredHome = recipe.homePath;
|
|
27051
|
+
const outcome = await probeGrokModels({
|
|
27052
|
+
recipe,
|
|
27053
|
+
host,
|
|
27054
|
+
env: buildSpawnEnv(
|
|
27055
|
+
recipe,
|
|
27056
|
+
resolveGrokHomePath(configuredHome),
|
|
27057
|
+
configuredHome.trim().length > 0
|
|
27058
|
+
)
|
|
27059
|
+
});
|
|
27060
|
+
if (outcome.kind !== "answered") {
|
|
27061
|
+
return {
|
|
27062
|
+
installed: outcome.kind === "failed",
|
|
27063
|
+
version: null,
|
|
27064
|
+
readiness: "error",
|
|
27065
|
+
auth: probeAuth(),
|
|
27066
|
+
...outcome.detail === void 0 ? {} : { detail: outcome.detail },
|
|
27067
|
+
// 装着但握不上手时,界面照样画权限格。不报档就退回宿主四档,而那四档对这双手
|
|
27068
|
+
// 是撒谎的——这台开发机的 grok 就长期停在这个出口上。
|
|
27069
|
+
...outcome.kind === "failed" ? GROK_NATIVE_MODE_REPORT : {}
|
|
27070
|
+
};
|
|
27071
|
+
}
|
|
27072
|
+
return {
|
|
27073
|
+
installed: true,
|
|
27074
|
+
version: null,
|
|
27075
|
+
readiness: "ready",
|
|
27076
|
+
auth: probeAuth(),
|
|
27077
|
+
...outcome.models === void 0 ? {} : { models: outcome.models },
|
|
27078
|
+
...GROK_NATIVE_MODE_REPORT
|
|
27079
|
+
};
|
|
27080
|
+
};
|
|
27081
|
+
const instance = {
|
|
27082
|
+
probe,
|
|
26601
27083
|
startSession: async (input2, signal) => {
|
|
26602
27084
|
if (disposed) throw new Error("instance disposed");
|
|
26603
27085
|
if (signal?.aborted) throw new Error("aborted");
|
|
@@ -26613,11 +27095,18 @@ var createGrokInstance = (config2, host) => {
|
|
|
26613
27095
|
}
|
|
26614
27096
|
const configuredHome = input2.launch.homePath?.trim() || recipe.homePath;
|
|
26615
27097
|
const resolvedHomePath = resolveGrokHomePath(configuredHome);
|
|
26616
|
-
const env = buildSpawnEnv(
|
|
27098
|
+
const env = buildSpawnEnv(
|
|
27099
|
+
recipe,
|
|
27100
|
+
resolvedHomePath,
|
|
27101
|
+
configuredHome.length > 0,
|
|
27102
|
+
input2.launch.processEnv
|
|
27103
|
+
);
|
|
26617
27104
|
const effort = modelSelectionStringOption(input2.modelSelection, GROK_REASONING_OPTION_ID);
|
|
26618
27105
|
const baseArgs = tokenizeLaunchArgs(recipe.launchArgs);
|
|
26619
27106
|
const insertAt = baseArgs.length <= 1 ? baseArgs.length : baseArgs.length - 1;
|
|
27107
|
+
const permissionMode = grokPermissionModeFor(input2.runtimeMode, input2.nativeModeId);
|
|
26620
27108
|
const args = [
|
|
27109
|
+
...grokPermissionModeArgs(input2.runtimeMode, permissionMode),
|
|
26621
27110
|
...baseArgs.slice(0, insertAt),
|
|
26622
27111
|
...grokReasoningEffortArgs(effort),
|
|
26623
27112
|
...baseArgs.slice(insertAt)
|
|
@@ -26629,7 +27118,7 @@ var createGrokInstance = (config2, host) => {
|
|
|
26629
27118
|
owner: { bindingId: host.bindingId },
|
|
26630
27119
|
...Object.keys(env).length > 0 ? { env } : {}
|
|
26631
27120
|
});
|
|
26632
|
-
const { readable, writable } =
|
|
27121
|
+
const { readable, writable } = nodeStreamsFromHandle2(handle);
|
|
26633
27122
|
const resume = input2.discardResumeCursor === true ? void 0 : parseAcpResumeCursor(input2.resumeCursor, RESUME_SCHEMA_VERSION);
|
|
26634
27123
|
const requestedModelId = input2.launch.requestedModelId?.trim() || modelIdFromSelection(input2.modelSelection);
|
|
26635
27124
|
let initializeResult;
|
|
@@ -26640,7 +27129,8 @@ var createGrokInstance = (config2, host) => {
|
|
|
26640
27129
|
threadId: input2.threadId,
|
|
26641
27130
|
provider: GROK_DRIVER_KIND,
|
|
26642
27131
|
providerInstanceId: host.instanceId,
|
|
26643
|
-
clientInfo:
|
|
27132
|
+
clientInfo: GROK_CLIENT_INFO,
|
|
27133
|
+
log: host.log,
|
|
26644
27134
|
// 等 `initialize` 回来再挑认证方式:能不能用 `cached_token`,只有 agent
|
|
26645
27135
|
// 播报的 `authMethods` 说了算(见 resolveGrokAuthMethodId)。
|
|
26646
27136
|
authMethodId: resolveGrokAuthMethodId,
|
|
@@ -26694,6 +27184,7 @@ var createGrokInstance = (config2, host) => {
|
|
|
26694
27184
|
providerInstanceId: host.instanceId,
|
|
26695
27185
|
status: "idle",
|
|
26696
27186
|
runtimeMode: input2.runtimeMode,
|
|
27187
|
+
nativeModeId: permissionMode,
|
|
26697
27188
|
cwd,
|
|
26698
27189
|
threadId: input2.threadId,
|
|
26699
27190
|
createdAt,
|
|
@@ -26713,6 +27204,27 @@ var createGrokInstance = (config2, host) => {
|
|
|
26713
27204
|
threadId: input2.threadId,
|
|
26714
27205
|
sessionId: started.sessionId
|
|
26715
27206
|
});
|
|
27207
|
+
const caveat = grokRuntimeModeCaveat(permissionMode);
|
|
27208
|
+
if (caveat !== void 0) {
|
|
27209
|
+
events.push({
|
|
27210
|
+
type: "runtime.warning",
|
|
27211
|
+
eventId: NodeCrypto2.randomUUID(),
|
|
27212
|
+
provider: GROK_DRIVER_KIND,
|
|
27213
|
+
providerInstanceId: host.instanceId,
|
|
27214
|
+
threadId: input2.threadId,
|
|
27215
|
+
createdAt: nowIso(),
|
|
27216
|
+
payload: {
|
|
27217
|
+
message: caveat.message,
|
|
27218
|
+
detail: {
|
|
27219
|
+
code: caveat.code,
|
|
27220
|
+
nativeModeId: caveat.nativeModeId,
|
|
27221
|
+
asked: caveat.asked,
|
|
27222
|
+
unasked: caveat.unasked,
|
|
27223
|
+
externalRulesPaths: caveat.externalRulesPaths
|
|
27224
|
+
}
|
|
27225
|
+
}
|
|
27226
|
+
});
|
|
27227
|
+
}
|
|
26716
27228
|
return session;
|
|
26717
27229
|
} catch (error62) {
|
|
26718
27230
|
await executor.dispose().catch(() => void 0);
|
|
@@ -26782,14 +27294,6 @@ var createGrokInstance = (config2, host) => {
|
|
|
26782
27294
|
const booked = requireThread(threadId);
|
|
26783
27295
|
await booked.executor.respondToUserInput(requestId, answers);
|
|
26784
27296
|
},
|
|
26785
|
-
setRuntimeMode: async (threadId, runtimeMode) => {
|
|
26786
|
-
const booked = requireThread(threadId);
|
|
26787
|
-
booked.session = {
|
|
26788
|
-
...booked.session,
|
|
26789
|
-
runtimeMode,
|
|
26790
|
-
updatedAt: nowIso()
|
|
26791
|
-
};
|
|
26792
|
-
},
|
|
26793
27297
|
stopSession: async (threadId) => {
|
|
26794
27298
|
const booked = threads.get(threadId);
|
|
26795
27299
|
if (booked === void 0) return;
|
|
@@ -26878,23 +27382,7 @@ var createGrokInstance = (config2, host) => {
|
|
|
26878
27382
|
await operation.handle.kill("SIGTERM").catch(() => void 0);
|
|
26879
27383
|
await operation.stdoutText.catch(() => void 0);
|
|
26880
27384
|
},
|
|
26881
|
-
verify:
|
|
26882
|
-
if (recipe.binaryPath.length === 0) {
|
|
26883
|
-
return {
|
|
26884
|
-
installed: false,
|
|
26885
|
-
version: null,
|
|
26886
|
-
readiness: "error",
|
|
26887
|
-
auth: { status: "unknown" },
|
|
26888
|
-
detail: "Grok program path is not configured"
|
|
26889
|
-
};
|
|
26890
|
-
}
|
|
26891
|
-
return {
|
|
26892
|
-
installed: true,
|
|
26893
|
-
version: null,
|
|
26894
|
-
readiness: "unchecked",
|
|
26895
|
-
auth: probeAuth()
|
|
26896
|
-
};
|
|
26897
|
-
}
|
|
27385
|
+
verify: () => probe()
|
|
26898
27386
|
}
|
|
26899
27387
|
};
|
|
26900
27388
|
return instance;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-grok",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2126",
|
|
4
4
|
"description": "Grok executor: grok CLI over Agent Client Protocol stdio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"@types/node": "24.12.4",
|
|
21
21
|
"esbuild": "0.28.1",
|
|
22
22
|
"vite-plus": "0.2.2",
|
|
23
|
-
"ycodium-
|
|
24
|
-
"
|
|
25
|
-
"ycodium-acp-
|
|
23
|
+
"@ycodium-ai/plugin-api": "0.2.2126",
|
|
24
|
+
"ycodium-acp-executor": "0.0.0",
|
|
25
|
+
"ycodium-acp-protocol": "0.0.0"
|
|
26
26
|
},
|
|
27
27
|
"ycodium": {
|
|
28
28
|
"plugin": "./dist/index.js",
|