@ycodium-ai/agent-claude 0.2.2106 → 0.2.2126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/dist/index.js +647 -97
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
# @ycodium-ai/agent-claude
|
|
2
2
|
|
|
3
3
|
Claude executor plugin. Talks to Claude Code through
|
|
4
|
-
`@anthropic-ai/claude-agent-sdk` (`query()`), not ACP.
|
|
5
|
-
|
|
4
|
+
`@anthropic-ai/claude-agent-sdk` (`query()`), not ACP.
|
|
5
|
+
|
|
6
|
+
Since 2026-09-19 this package **is** the Claude hand: the catalog row carries
|
|
7
|
+
`executorPlugin: "@ycodium-ai/agent-claude"`, the host `ClaudeDriver` /
|
|
8
|
+
`ClaudeAdapter` / `ClaudeProvider` / `ClaudeTextGeneration` are deleted, and the
|
|
9
|
+
built-in `claudeAgent` card no longer joins the catalog. The host keeps one copy
|
|
10
|
+
of the connectivity literal (`executorRegistry.ts` → `officialCardForDriver`)
|
|
11
|
+
because `compileBinding` is synchronous and cannot read the plugin registry;
|
|
12
|
+
`executorRegistry.test.ts` pins the two copies to be byte-identical.
|
|
6
13
|
|
|
7
14
|
Facts:
|
|
8
15
|
|
|
@@ -13,6 +20,13 @@ Facts:
|
|
|
13
20
|
- Manifest permission is `{ kind: "executor" }`.
|
|
14
21
|
- Card capabilities: `sessionModelSwitch: "in-session"`, `runtimeModeSwitch: "in-session"`,
|
|
15
22
|
`contextCompaction: "native"`, `turnSteering: true`.
|
|
23
|
+
- `modelConnectivity` carries `baseUrlEnvKey: ANTHROPIC_BASE_URL`,
|
|
24
|
+
`credentialEnvKey: ANTHROPIC_AUTH_TOKEN` and seven `extraEnv` rows pinning every
|
|
25
|
+
model-role variable to `$model`. It deliberately does **not** claim
|
|
26
|
+
`supportsNativeSubscription`: Ycodium has no Claude native-subscription login.
|
|
27
|
+
- Recordings: `test/fixtures/*.sdk.ndjson`, ten scenes captured from Claude Code
|
|
28
|
+
2.1.277 by `scripts/record-claude-sdk-session.ts`; `src/replay.test.ts` replays
|
|
29
|
+
them through the same `createQuery` seam the recorder tapped.
|
|
16
30
|
- Quota-probe dissolution: `credentialSources` lists the json-file and
|
|
17
31
|
macOS-keychain locations. `sessions.scan` / `sessions.read` take the Claude
|
|
18
32
|
half of session-import.
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,9 @@ import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
|
5
5
|
var CLAUDE_DRIVER_KIND = "claudeAgent";
|
|
6
6
|
var CLAUDE_CARD = {
|
|
7
7
|
driverKind: CLAUDE_DRIVER_KIND,
|
|
8
|
-
|
|
8
|
+
// 手叫 Claude Code,不叫 Claude——「Claude」会和脑(Anthropic · Claude Opus 5)混。
|
|
9
|
+
// 已有实例存的显示名不动,这里只影响新建实例与手脑拆分后的回填名。
|
|
10
|
+
displayName: "Claude Code",
|
|
9
11
|
iconUrl: "./assets/icon.svg",
|
|
10
12
|
commandName: "claude",
|
|
11
13
|
launchArgs: "",
|
|
@@ -60,9 +62,16 @@ var CLAUDE_CARD = {
|
|
|
60
62
|
verifiedSkills: true,
|
|
61
63
|
everydayHarness: true,
|
|
62
64
|
capabilities: {
|
|
65
|
+
// 会话中途换模型走 SDK 的 `setModel` 控制请求,不重开会话:`claudeInstance.ts` 的
|
|
66
|
+
// sendTurn 在 `currentApiModelId` 与本轮选择不一致时调它,`reconfigureSession` 复用
|
|
67
|
+
// 会话时也是同一条路。录像证据是 `test/fixtures/claudeModelSwitchTurn.sdk.ndjson`
|
|
68
|
+
// (同一会话两轮不同模型,中间一条 `setModel`)。宿主内置名片此前写 unsupported,
|
|
69
|
+
// 与 adapter 自己声明给编排的 `"in-session"` 相反——那边是真的,名片是错的。
|
|
63
70
|
sessionModelSwitch: "in-session",
|
|
64
71
|
sessionOptionSwitch: "unsupported",
|
|
65
72
|
runtimeModeSwitch: "in-session",
|
|
73
|
+
// SDK 的 `setPermissionMode` 会话中途就能改,所以这一位也是真的。
|
|
74
|
+
nativeModeSwitch: true,
|
|
66
75
|
contextCompaction: "native",
|
|
67
76
|
turnSteering: true
|
|
68
77
|
},
|
|
@@ -98,15 +107,34 @@ var CLAUDE_CARD = {
|
|
|
98
107
|
modelConnectivity: {
|
|
99
108
|
dialects: ["anthropic-messages"],
|
|
100
109
|
acceptsExternalEndpoints: true,
|
|
110
|
+
// claude 认 origin:CLI 自己在注入的 base 后追加 `/v1/messages`,所以后缀整条
|
|
111
|
+
// 就是路由,注进去的 base 是纯 origin(compileBinding 按这一栏算出该注什么)。
|
|
101
112
|
nativePathSuffix: "/v1/messages",
|
|
102
|
-
credentialEnvKey
|
|
103
|
-
|
|
113
|
+
// 与宿主内置名片逐字相同。credentialEnvKey 是宿主给绑定注入的那个变量;
|
|
114
|
+
// alternateCredentialEnvKeys 是 CLI 也认的备选凭据变量(手脑拆分线加的,用来识别捆绑)。
|
|
115
|
+
baseUrlEnvKey: "ANTHROPIC_BASE_URL",
|
|
116
|
+
credentialEnvKey: "ANTHROPIC_AUTH_TOKEN",
|
|
117
|
+
alternateCredentialEnvKeys: ["ANTHROPIC_API_KEY"],
|
|
118
|
+
supportsNativeSubscription: true,
|
|
119
|
+
// 七个档位变量一起钉成这次的模型:claude 的 opus / sonnet / haiku / fable 档与
|
|
120
|
+
// 子代理、小快模型各读一个变量,只钉 `ANTHROPIC_MODEL` 的话子代理会跑回默认档。
|
|
121
|
+
// 名单与旧 `CLAUDE_SETTINGS_MODEL_ENV_KEYS` 逐字相同(含 2026-09-09 从 2.1.265
|
|
122
|
+
// 二进制核实出来的 fable 那一条)。`$model` 由 compileBinding 替换。
|
|
123
|
+
extraEnv: [
|
|
124
|
+
{ name: "ANTHROPIC_MODEL", value: "$model" },
|
|
125
|
+
{ name: "ANTHROPIC_DEFAULT_OPUS_MODEL", value: "$model" },
|
|
126
|
+
{ name: "ANTHROPIC_DEFAULT_SONNET_MODEL", value: "$model" },
|
|
127
|
+
{ name: "ANTHROPIC_DEFAULT_HAIKU_MODEL", value: "$model" },
|
|
128
|
+
{ name: "ANTHROPIC_DEFAULT_FABLE_MODEL", value: "$model" },
|
|
129
|
+
{ name: "ANTHROPIC_SMALL_FAST_MODEL", value: "$model" },
|
|
130
|
+
{ name: "CLAUDE_CODE_SUBAGENT_MODEL", value: "$model" }
|
|
131
|
+
]
|
|
104
132
|
}
|
|
105
133
|
};
|
|
106
134
|
|
|
107
135
|
// src/claudeInstance.ts
|
|
108
136
|
import * as NodeOS6 from "node:os";
|
|
109
|
-
import * as
|
|
137
|
+
import * as NodePath7 from "node:path";
|
|
110
138
|
|
|
111
139
|
// ../../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.3.170_@anthropic-ai+sdk@0.93.0_zod@4.6.5__@modelcontex_64204813d4dba2ebc464c3aa751485a4/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
112
140
|
import { createRequire as xz } from "node:module";
|
|
@@ -19538,6 +19566,13 @@ function HU(e, t) {
|
|
|
19538
19566
|
return null;
|
|
19539
19567
|
}
|
|
19540
19568
|
|
|
19569
|
+
// src/claudeInstance.ts
|
|
19570
|
+
import {
|
|
19571
|
+
mergeLaunchEnv as mergeLaunchEnv2,
|
|
19572
|
+
withoutBrainSlots,
|
|
19573
|
+
brainSlotEnvKeys as brainSlotEnvKeys3
|
|
19574
|
+
} from "@ycodium-ai/plugin-api/executor";
|
|
19575
|
+
|
|
19541
19576
|
// src/claudeAccount.ts
|
|
19542
19577
|
import * as NodeFS from "node:fs";
|
|
19543
19578
|
import * as NodeOS from "node:os";
|
|
@@ -19694,6 +19729,10 @@ function expandHomePath(value) {
|
|
|
19694
19729
|
|
|
19695
19730
|
// src/claudeHome.ts
|
|
19696
19731
|
var CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE = "CLAUDE_SECURESTORAGE_CONFIG_DIR";
|
|
19732
|
+
var CLAUDE_ROUTED_HOME_DIR_NAME = "claude-home";
|
|
19733
|
+
function claudeRoutedHomePath(pluginDataDirPath) {
|
|
19734
|
+
return NodePath4.join(pluginDataDirPath, CLAUDE_ROUTED_HOME_DIR_NAME);
|
|
19735
|
+
}
|
|
19697
19736
|
function resolveClaudeHomePath(homePath) {
|
|
19698
19737
|
const trimmed = homePath.trim();
|
|
19699
19738
|
return NodePath4.resolve(trimmed.length > 0 ? expandHomePath(trimmed) : NodeOS4.homedir());
|
|
@@ -19714,18 +19753,47 @@ function resolveClaudeCredentialsDirPath(credentialsPath) {
|
|
|
19714
19753
|
if (trimmed.length === 0) return null;
|
|
19715
19754
|
return NodePath4.resolve(expandHomePath(trimmed));
|
|
19716
19755
|
}
|
|
19717
|
-
function
|
|
19718
|
-
const
|
|
19719
|
-
const
|
|
19720
|
-
const
|
|
19721
|
-
|
|
19722
|
-
|
|
19756
|
+
function resolveClaudeHomeLayout(input) {
|
|
19757
|
+
const userConfigDirPath = resolveClaudeConfigDirPath(input.homePath, input.environment ?? {});
|
|
19758
|
+
const instanceConfigDirPath = input.homePath.trim().length > 0 ? resolveClaudeHomePath(input.homePath) : void 0;
|
|
19759
|
+
const instanceCredentialsDirPath = resolveClaudeCredentialsDirPath(input.credentialsPath);
|
|
19760
|
+
const routedHomePath = input.routedHomePath?.trim() ?? "";
|
|
19761
|
+
if (routedHomePath.length === 0 || instanceConfigDirPath !== void 0 || instanceCredentialsDirPath !== null) {
|
|
19762
|
+
return {
|
|
19763
|
+
mode: "instance",
|
|
19764
|
+
userConfigDirPath,
|
|
19765
|
+
configDirPath: instanceConfigDirPath,
|
|
19766
|
+
credentialsDirPath: instanceCredentialsDirPath ?? void 0
|
|
19767
|
+
};
|
|
19768
|
+
}
|
|
19769
|
+
const resolvedRoutedHomePath = NodePath4.resolve(expandHomePath(routedHomePath));
|
|
19770
|
+
return {
|
|
19771
|
+
mode: "routed",
|
|
19772
|
+
userConfigDirPath,
|
|
19773
|
+
configDirPath: resolvedRoutedHomePath,
|
|
19774
|
+
// 登录目录显式钉成影子目录本身。不设这个变量时 CLI 本来就把凭据放配置目录,但
|
|
19775
|
+
// 「登录去哪」正是这次要修的东西,不靠默认值。
|
|
19776
|
+
credentialsDirPath: resolvedRoutedHomePath
|
|
19777
|
+
};
|
|
19778
|
+
}
|
|
19779
|
+
function claudeHomeVariables(layout) {
|
|
19723
19780
|
return {
|
|
19724
|
-
...
|
|
19725
|
-
...
|
|
19726
|
-
...credentialsDirPath === null ? {} : { [CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE]: credentialsDirPath }
|
|
19781
|
+
...layout.configDirPath === void 0 ? {} : { CLAUDE_CONFIG_DIR: layout.configDirPath },
|
|
19782
|
+
...layout.credentialsDirPath === void 0 ? {} : { [CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE]: layout.credentialsDirPath }
|
|
19727
19783
|
};
|
|
19728
19784
|
}
|
|
19785
|
+
function makeClaudeEnvironment(config, baseEnv) {
|
|
19786
|
+
const resolvedBaseEnv = { ...baseEnv ?? process.env };
|
|
19787
|
+
const variables = claudeHomeVariables(
|
|
19788
|
+
resolveClaudeHomeLayout({
|
|
19789
|
+
homePath: config.homePath,
|
|
19790
|
+
credentialsPath: config.credentialsPath,
|
|
19791
|
+
environment: resolvedBaseEnv
|
|
19792
|
+
})
|
|
19793
|
+
);
|
|
19794
|
+
if (Object.keys(variables).length === 0) return resolvedBaseEnv;
|
|
19795
|
+
return { ...resolvedBaseEnv, ...variables };
|
|
19796
|
+
}
|
|
19729
19797
|
|
|
19730
19798
|
// src/claudeSignIn.ts
|
|
19731
19799
|
var POSIX_BARE_VALUE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
@@ -19953,8 +20021,8 @@ var EventBus = class {
|
|
|
19953
20021
|
const queued = this.#queued.shift();
|
|
19954
20022
|
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
19955
20023
|
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
19956
|
-
return new Promise((
|
|
19957
|
-
this.#waiters.push(
|
|
20024
|
+
return new Promise((resolve3) => {
|
|
20025
|
+
this.#waiters.push(resolve3);
|
|
19958
20026
|
});
|
|
19959
20027
|
}
|
|
19960
20028
|
};
|
|
@@ -19962,6 +20030,7 @@ var EventBus = class {
|
|
|
19962
20030
|
};
|
|
19963
20031
|
|
|
19964
20032
|
// src/model.ts
|
|
20033
|
+
import { matchCatalogModel } from "@ycodium-ai/plugin-api/executor";
|
|
19965
20034
|
var DEFAULT_CLAUDE_MODEL_CAPABILITIES = {
|
|
19966
20035
|
optionDescriptors: []
|
|
19967
20036
|
};
|
|
@@ -19969,6 +20038,10 @@ var CLAUDE_CUSTOM_MODEL_THINKING_SELECT = {
|
|
|
19969
20038
|
id: "effort",
|
|
19970
20039
|
label: "Reasoning"
|
|
19971
20040
|
};
|
|
20041
|
+
var MINIMUM_CLAUDE_OPUS_5_VERSION = "2.1.219";
|
|
20042
|
+
var MINIMUM_CLAUDE_FABLE_5_VERSION = "2.1.169";
|
|
20043
|
+
var MINIMUM_CLAUDE_OPUS_4_8_VERSION = "2.1.154";
|
|
20044
|
+
var MINIMUM_CLAUDE_OPUS_4_7_VERSION = "2.1.111";
|
|
19972
20045
|
var CURRENT_CLAUDE_MODELS = /* @__PURE__ */ new Set(["claude-fable-5", "claude-opus-5", "claude-sonnet-5"]);
|
|
19973
20046
|
function isLegacyClaudeModel(model) {
|
|
19974
20047
|
return !CURRENT_CLAUDE_MODELS.has(model);
|
|
@@ -20209,6 +20282,35 @@ var CLAUDE_XHIGH_SLUGS = /* @__PURE__ */ new Set([
|
|
|
20209
20282
|
"claude-opus-4-8",
|
|
20210
20283
|
"claude-sonnet-5"
|
|
20211
20284
|
]);
|
|
20285
|
+
function compareSemverVersions(left, right) {
|
|
20286
|
+
const parse = (value) => {
|
|
20287
|
+
const match = value.trim().replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
20288
|
+
if (!match) return null;
|
|
20289
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
20290
|
+
};
|
|
20291
|
+
const a = parse(left);
|
|
20292
|
+
const b3 = parse(right);
|
|
20293
|
+
if (!a || !b3) return left.localeCompare(right);
|
|
20294
|
+
if (a[0] !== b3[0]) return a[0] - b3[0];
|
|
20295
|
+
if (a[1] !== b3[1]) return a[1] - b3[1];
|
|
20296
|
+
return a[2] - b3[2];
|
|
20297
|
+
}
|
|
20298
|
+
function supportsVersion(version, minimum) {
|
|
20299
|
+
return version ? compareSemverVersions(version, minimum) >= 0 : false;
|
|
20300
|
+
}
|
|
20301
|
+
function getBuiltInClaudeModelsForVersion(version) {
|
|
20302
|
+
return BUILT_IN_MODELS.filter((model) => {
|
|
20303
|
+
if (model.slug === "claude-opus-5")
|
|
20304
|
+
return supportsVersion(version, MINIMUM_CLAUDE_OPUS_5_VERSION);
|
|
20305
|
+
if (model.slug === "claude-fable-5")
|
|
20306
|
+
return supportsVersion(version, MINIMUM_CLAUDE_FABLE_5_VERSION);
|
|
20307
|
+
if (model.slug === "claude-opus-4-8")
|
|
20308
|
+
return supportsVersion(version, MINIMUM_CLAUDE_OPUS_4_8_VERSION);
|
|
20309
|
+
if (model.slug === "claude-opus-4-7")
|
|
20310
|
+
return supportsVersion(version, MINIMUM_CLAUDE_OPUS_4_7_VERSION);
|
|
20311
|
+
return true;
|
|
20312
|
+
});
|
|
20313
|
+
}
|
|
20212
20314
|
function parseGenericCliVersion(output) {
|
|
20213
20315
|
const match = output.match(/\b(\d+\.\d+\.\d+)\b/);
|
|
20214
20316
|
return match?.[1] ?? null;
|
|
@@ -20316,6 +20418,13 @@ function resolveClaudeContextWindow(caps, modelSelection) {
|
|
|
20316
20418
|
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20317
20419
|
return currentSelectValue(descriptor, raw);
|
|
20318
20420
|
}
|
|
20421
|
+
function claudeCliModelId(input) {
|
|
20422
|
+
const catalog = [
|
|
20423
|
+
...BUILT_IN_MODELS.map((model) => model.slug),
|
|
20424
|
+
...(input.customModels ?? []).map((model) => normalizeCustomModelSlug(model.slug))
|
|
20425
|
+
];
|
|
20426
|
+
return matchCatalogModel(input.boundModelId, catalog) ?? input.placeholder;
|
|
20427
|
+
}
|
|
20319
20428
|
function resolveClaudeApiModelId(caps, modelSelection) {
|
|
20320
20429
|
switch (resolveClaudeContextWindow(caps, modelSelection)) {
|
|
20321
20430
|
case "1m":
|
|
@@ -20386,6 +20495,15 @@ function toMessage(cause, fallback) {
|
|
|
20386
20495
|
}
|
|
20387
20496
|
return fallback;
|
|
20388
20497
|
}
|
|
20498
|
+
function createOutputTail(maxChars) {
|
|
20499
|
+
let buffered = "";
|
|
20500
|
+
return {
|
|
20501
|
+
append: (chunk) => {
|
|
20502
|
+
buffered = (buffered + chunk).slice(-maxChars);
|
|
20503
|
+
},
|
|
20504
|
+
read: () => buffered.trim()
|
|
20505
|
+
};
|
|
20506
|
+
}
|
|
20389
20507
|
function asRuntimeItemId(value) {
|
|
20390
20508
|
return value;
|
|
20391
20509
|
}
|
|
@@ -20533,10 +20651,10 @@ function inputDiffStat(input) {
|
|
|
20533
20651
|
let deletions = 0;
|
|
20534
20652
|
for (const edit of input.edits) {
|
|
20535
20653
|
if (edit === null || typeof edit !== "object" || Array.isArray(edit)) return void 0;
|
|
20536
|
-
const
|
|
20537
|
-
if (!
|
|
20538
|
-
additions +=
|
|
20539
|
-
deletions +=
|
|
20654
|
+
const stat2 = replacementDiffStat(edit, budget);
|
|
20655
|
+
if (!stat2) return void 0;
|
|
20656
|
+
additions += stat2.additions;
|
|
20657
|
+
deletions += stat2.deletions;
|
|
20540
20658
|
}
|
|
20541
20659
|
return { additions, deletions };
|
|
20542
20660
|
}
|
|
@@ -21071,11 +21189,40 @@ function diffClaudeSessionSettings(previous, next) {
|
|
|
21071
21189
|
}
|
|
21072
21190
|
return changed ? patch : void 0;
|
|
21073
21191
|
}
|
|
21074
|
-
var
|
|
21192
|
+
var CLAUDE_NATIVE_MODES = [
|
|
21193
|
+
{ id: "default", name: "Manual", description: "Always ask before making changes" },
|
|
21194
|
+
{ id: "acceptEdits", name: "Accept edits", description: "Automatically accept all file edits" },
|
|
21195
|
+
{ id: "plan", name: "Plan", description: "Create a plan before making changes" },
|
|
21196
|
+
{ id: "auto", name: "Auto", description: "Claude handles permission decisions" },
|
|
21197
|
+
{
|
|
21198
|
+
id: "bypassPermissions",
|
|
21199
|
+
name: "Bypass permissions",
|
|
21200
|
+
description: "Accepts all permissions"
|
|
21201
|
+
}
|
|
21202
|
+
];
|
|
21203
|
+
var CLAUDE_DEFAULT_NATIVE_MODE_ID = "default";
|
|
21204
|
+
var CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE = {
|
|
21205
|
+
"approval-required": "default",
|
|
21075
21206
|
"auto-accept-edits": "acceptEdits",
|
|
21076
21207
|
auto: "auto",
|
|
21077
21208
|
"full-access": "bypassPermissions"
|
|
21078
21209
|
};
|
|
21210
|
+
var CLAUDE_NATIVE_MODE_REPORT = {
|
|
21211
|
+
nativeModes: CLAUDE_NATIVE_MODES.map((mode) => ({
|
|
21212
|
+
id: mode.id,
|
|
21213
|
+
name: mode.name,
|
|
21214
|
+
description: mode.description
|
|
21215
|
+
})),
|
|
21216
|
+
currentNativeModeId: CLAUDE_DEFAULT_NATIVE_MODE_ID,
|
|
21217
|
+
nativeModeByRuntimeMode: CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE
|
|
21218
|
+
};
|
|
21219
|
+
function isClaudeNativeModeId(value) {
|
|
21220
|
+
return CLAUDE_NATIVE_MODES.some((mode) => mode.id === value);
|
|
21221
|
+
}
|
|
21222
|
+
function claudePermissionModeFor(runtimeMode, nativeModeId) {
|
|
21223
|
+
if (nativeModeId !== void 0 && isClaudeNativeModeId(nativeModeId)) return nativeModeId;
|
|
21224
|
+
return CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE[runtimeMode];
|
|
21225
|
+
}
|
|
21079
21226
|
var CLAUDE_SETTING_SOURCES = [
|
|
21080
21227
|
"user",
|
|
21081
21228
|
"project",
|
|
@@ -21213,17 +21360,17 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
21213
21360
|
continue;
|
|
21214
21361
|
}
|
|
21215
21362
|
for (const name of names) {
|
|
21216
|
-
let
|
|
21363
|
+
let stat2;
|
|
21217
21364
|
try {
|
|
21218
|
-
|
|
21365
|
+
stat2 = NodeFS3.statSync(NodePath5.join(projectDir, name));
|
|
21219
21366
|
} catch {
|
|
21220
21367
|
continue;
|
|
21221
21368
|
}
|
|
21222
21369
|
found.push({
|
|
21223
21370
|
path: NodePath5.join(projectDir, name),
|
|
21224
21371
|
sessionId: name.slice(0, -TRANSCRIPT_SUFFIX.length),
|
|
21225
|
-
size:
|
|
21226
|
-
mtimeMs: Number.isFinite(
|
|
21372
|
+
size: stat2.size,
|
|
21373
|
+
mtimeMs: Number.isFinite(stat2.mtimeMs) ? stat2.mtimeMs : 0
|
|
21227
21374
|
});
|
|
21228
21375
|
}
|
|
21229
21376
|
}
|
|
@@ -21787,6 +21934,305 @@ function normalizeClaudeTaskProgressTokenUsage(value, memory) {
|
|
|
21787
21934
|
};
|
|
21788
21935
|
}
|
|
21789
21936
|
|
|
21937
|
+
// src/probeModels.ts
|
|
21938
|
+
var CONTEXT_WINDOW_TOKENS = {
|
|
21939
|
+
"200k": 2e5,
|
|
21940
|
+
"1m": 1e6
|
|
21941
|
+
};
|
|
21942
|
+
var defaultContextWindowOf = (caps) => {
|
|
21943
|
+
const descriptor = caps.optionDescriptors.find(
|
|
21944
|
+
(entry) => entry.type === "select" && entry.id === "contextWindow"
|
|
21945
|
+
);
|
|
21946
|
+
if (descriptor === void 0) return void 0;
|
|
21947
|
+
const chosen = descriptor.options.find((option) => option.isDefault === true);
|
|
21948
|
+
return chosen === void 0 ? void 0 : CONTEXT_WINDOW_TOKENS[chosen.id];
|
|
21949
|
+
};
|
|
21950
|
+
var toProbeCapabilities = (caps) => ({
|
|
21951
|
+
optionDescriptors: caps.optionDescriptors.map(
|
|
21952
|
+
(descriptor) => descriptor.type === "select" ? {
|
|
21953
|
+
id: descriptor.id,
|
|
21954
|
+
label: descriptor.label,
|
|
21955
|
+
type: "select",
|
|
21956
|
+
options: descriptor.options.map((option) => ({
|
|
21957
|
+
id: option.id,
|
|
21958
|
+
label: option.label,
|
|
21959
|
+
...option.description === void 0 ? {} : { description: option.description },
|
|
21960
|
+
...option.isDefault === void 0 ? {} : { isDefault: option.isDefault }
|
|
21961
|
+
}))
|
|
21962
|
+
} : {
|
|
21963
|
+
id: descriptor.id,
|
|
21964
|
+
label: descriptor.label,
|
|
21965
|
+
type: "boolean"
|
|
21966
|
+
}
|
|
21967
|
+
)
|
|
21968
|
+
});
|
|
21969
|
+
var claudeProbeModels = (input) => {
|
|
21970
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21971
|
+
const out = [];
|
|
21972
|
+
for (const model of input.builtIn) {
|
|
21973
|
+
if (seen.has(model.slug)) continue;
|
|
21974
|
+
seen.add(model.slug);
|
|
21975
|
+
const userLabel = input.customModels.find((entry) => entry.slug === model.slug)?.label;
|
|
21976
|
+
const contextWindow = defaultContextWindowOf(model.capabilities);
|
|
21977
|
+
out.push({
|
|
21978
|
+
slug: model.slug,
|
|
21979
|
+
name: userLabel?.trim() || model.name,
|
|
21980
|
+
...model.isLegacy === void 0 ? {} : { isLegacy: model.isLegacy },
|
|
21981
|
+
capabilities: toProbeCapabilities(model.capabilities),
|
|
21982
|
+
...contextWindow === void 0 ? {} : { contextWindow }
|
|
21983
|
+
});
|
|
21984
|
+
}
|
|
21985
|
+
for (const model of input.customModels) {
|
|
21986
|
+
if (model.slug.trim().length === 0 || seen.has(model.slug)) continue;
|
|
21987
|
+
seen.add(model.slug);
|
|
21988
|
+
out.push({ slug: model.slug, name: model.label?.trim() || model.slug });
|
|
21989
|
+
}
|
|
21990
|
+
for (const model of input.discovered ?? []) {
|
|
21991
|
+
if (seen.has(model.slug)) continue;
|
|
21992
|
+
seen.add(model.slug);
|
|
21993
|
+
out.push(model);
|
|
21994
|
+
}
|
|
21995
|
+
return out;
|
|
21996
|
+
};
|
|
21997
|
+
|
|
21998
|
+
// src/routedHome.ts
|
|
21999
|
+
import * as NodeFSP from "node:fs/promises";
|
|
22000
|
+
import * as NodePath6 from "node:path";
|
|
22001
|
+
|
|
22002
|
+
// src/routedSettings.ts
|
|
22003
|
+
import { brainSlotEnvKeys } from "@ycodium-ai/plugin-api";
|
|
22004
|
+
var PROXY_ENV_KEYS = [
|
|
22005
|
+
"HTTP_PROXY",
|
|
22006
|
+
"HTTPS_PROXY",
|
|
22007
|
+
"NO_PROXY",
|
|
22008
|
+
"ALL_PROXY",
|
|
22009
|
+
"http_proxy",
|
|
22010
|
+
"https_proxy",
|
|
22011
|
+
"no_proxy",
|
|
22012
|
+
"all_proxy"
|
|
22013
|
+
];
|
|
22014
|
+
function isRoutedLaunch(launchProcessEnv) {
|
|
22015
|
+
const baseUrlKey = CLAUDE_CARD.modelConnectivity.baseUrlEnvKey;
|
|
22016
|
+
if (baseUrlKey === void 0) return false;
|
|
22017
|
+
return (launchProcessEnv?.[baseUrlKey] ?? "").trim().length > 0;
|
|
22018
|
+
}
|
|
22019
|
+
function routedEnvOverride(input) {
|
|
22020
|
+
if (!isRoutedLaunch(input.launchProcessEnv)) return void 0;
|
|
22021
|
+
const valueOf = (key) => input.mergedEnv[key] ?? "";
|
|
22022
|
+
const override = {};
|
|
22023
|
+
for (const key of brainSlotEnvKeys(CLAUDE_CARD)) override[key] = valueOf(key);
|
|
22024
|
+
for (const { name } of CLAUDE_CARD.modelConnectivity.extraEnv ?? []) {
|
|
22025
|
+
const bound = valueOf(name);
|
|
22026
|
+
override[name] = bound.length === 0 ? "" : claudeCliModelId({
|
|
22027
|
+
boundModelId: bound,
|
|
22028
|
+
placeholder: CLAUDE_CARD.defaultModel,
|
|
22029
|
+
...input.customModels === void 0 ? {} : { customModels: input.customModels }
|
|
22030
|
+
});
|
|
22031
|
+
}
|
|
22032
|
+
for (const key of PROXY_ENV_KEYS) override[key] = valueOf(key);
|
|
22033
|
+
return override;
|
|
22034
|
+
}
|
|
22035
|
+
|
|
22036
|
+
// src/routedHome.ts
|
|
22037
|
+
var BORROWED_ENTRY_NAMES = [
|
|
22038
|
+
"projects",
|
|
22039
|
+
"plugins",
|
|
22040
|
+
"skills",
|
|
22041
|
+
"agents",
|
|
22042
|
+
"commands",
|
|
22043
|
+
"CLAUDE.md"
|
|
22044
|
+
];
|
|
22045
|
+
var GLOBAL_CONFIG_FILE_NAME = ".claude.json";
|
|
22046
|
+
var USER_SETTINGS_FILE_NAME = "settings.json";
|
|
22047
|
+
var ROUTING_AND_IDENTITY_SETTING_KEYS = [
|
|
22048
|
+
"env",
|
|
22049
|
+
"apiKeyHelper",
|
|
22050
|
+
"awsAuthRefresh",
|
|
22051
|
+
"awsCredentialExport"
|
|
22052
|
+
];
|
|
22053
|
+
var FIRST_RUN_FLAG_KEYS = ["hasCompletedOnboarding", "bypassPermissionsModeAccepted"];
|
|
22054
|
+
function isRecord5(value) {
|
|
22055
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22056
|
+
}
|
|
22057
|
+
async function readTextFile(filePath) {
|
|
22058
|
+
try {
|
|
22059
|
+
return await NodeFSP.readFile(filePath, "utf8");
|
|
22060
|
+
} catch {
|
|
22061
|
+
return null;
|
|
22062
|
+
}
|
|
22063
|
+
}
|
|
22064
|
+
function parseJsonObject(raw) {
|
|
22065
|
+
try {
|
|
22066
|
+
const parsed = JSON.parse(raw);
|
|
22067
|
+
return isRecord5(parsed) ? parsed : null;
|
|
22068
|
+
} catch {
|
|
22069
|
+
return null;
|
|
22070
|
+
}
|
|
22071
|
+
}
|
|
22072
|
+
async function writeFileAtomic(filePath, contents) {
|
|
22073
|
+
const tempPath = `${filePath}.${crypto.randomUUID()}.tmp`;
|
|
22074
|
+
await NodeFSP.writeFile(tempPath, contents, { encoding: "utf8", mode: 384 });
|
|
22075
|
+
await NodeFSP.rename(tempPath, filePath);
|
|
22076
|
+
}
|
|
22077
|
+
async function readLinkState(linkPath) {
|
|
22078
|
+
try {
|
|
22079
|
+
return { _tag: "Symlink", target: await NodeFSP.readlink(linkPath) };
|
|
22080
|
+
} catch (error) {
|
|
22081
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
22082
|
+
if (code === "ENOENT") return { _tag: "Missing" };
|
|
22083
|
+
return { _tag: "NotSymlink" };
|
|
22084
|
+
}
|
|
22085
|
+
}
|
|
22086
|
+
async function isEmptyDirectory(path) {
|
|
22087
|
+
try {
|
|
22088
|
+
return (await NodeFSP.readdir(path)).length === 0;
|
|
22089
|
+
} catch {
|
|
22090
|
+
return false;
|
|
22091
|
+
}
|
|
22092
|
+
}
|
|
22093
|
+
async function borrowEntry(input) {
|
|
22094
|
+
const target = NodePath6.join(input.userConfigDirPath, input.entryName);
|
|
22095
|
+
const targetInfo = await NodeFSP.stat(target).then(
|
|
22096
|
+
(info) => info,
|
|
22097
|
+
() => null
|
|
22098
|
+
);
|
|
22099
|
+
if (targetInfo === null) return;
|
|
22100
|
+
const link = NodePath6.join(input.configDirPath, input.entryName);
|
|
22101
|
+
const state = await readLinkState(link);
|
|
22102
|
+
if (state._tag === "NotSymlink") {
|
|
22103
|
+
if (!await isEmptyDirectory(link)) {
|
|
22104
|
+
input.log?.warn("Claude routed home entry left unlinked: a real entry is already there.", {
|
|
22105
|
+
entryName: input.entryName,
|
|
22106
|
+
link
|
|
22107
|
+
});
|
|
22108
|
+
return;
|
|
22109
|
+
}
|
|
22110
|
+
await NodeFSP.rm(link, { recursive: true, force: true });
|
|
22111
|
+
await NodeFSP.symlink(target, link, targetInfo.isDirectory() ? "junction" : "file");
|
|
22112
|
+
return;
|
|
22113
|
+
}
|
|
22114
|
+
if (state._tag === "Symlink") {
|
|
22115
|
+
if (NodePath6.resolve(NodePath6.dirname(link), state.target) === target) return;
|
|
22116
|
+
await NodeFSP.rm(link, { force: true });
|
|
22117
|
+
}
|
|
22118
|
+
await NodeFSP.symlink(target, link, targetInfo.isDirectory() ? "junction" : "file");
|
|
22119
|
+
}
|
|
22120
|
+
async function mirrorUserSettings(input) {
|
|
22121
|
+
const sourcePath = NodePath6.join(input.userConfigDirPath, USER_SETTINGS_FILE_NAME);
|
|
22122
|
+
const raw = await readTextFile(sourcePath);
|
|
22123
|
+
if (raw === null) return;
|
|
22124
|
+
const parsed = parseJsonObject(raw);
|
|
22125
|
+
if (parsed === null) {
|
|
22126
|
+
input.log?.warn(
|
|
22127
|
+
"Claude routed home settings mirror skipped: the source is not a JSON object.",
|
|
22128
|
+
{
|
|
22129
|
+
sourcePath
|
|
22130
|
+
}
|
|
22131
|
+
);
|
|
22132
|
+
return;
|
|
22133
|
+
}
|
|
22134
|
+
const mirrored = { ...parsed };
|
|
22135
|
+
for (const key of ROUTING_AND_IDENTITY_SETTING_KEYS) delete mirrored[key];
|
|
22136
|
+
const targetPath = NodePath6.join(input.configDirPath, USER_SETTINGS_FILE_NAME);
|
|
22137
|
+
const desired = `${JSON.stringify(mirrored, null, 2)}
|
|
22138
|
+
`;
|
|
22139
|
+
if (await readTextFile(targetPath) === desired) return;
|
|
22140
|
+
await writeFileAtomic(targetPath, desired);
|
|
22141
|
+
}
|
|
22142
|
+
async function seedFirstRun(input) {
|
|
22143
|
+
const filePath = NodePath6.join(input.configDirPath, GLOBAL_CONFIG_FILE_NAME);
|
|
22144
|
+
const raw = await readTextFile(filePath);
|
|
22145
|
+
const parsed = raw === null ? {} : parseJsonObject(raw);
|
|
22146
|
+
if (parsed === null) {
|
|
22147
|
+
input.log?.warn("Claude routed home first-run seed skipped: the config file is not readable.", {
|
|
22148
|
+
filePath
|
|
22149
|
+
});
|
|
22150
|
+
return;
|
|
22151
|
+
}
|
|
22152
|
+
const next = { ...parsed };
|
|
22153
|
+
let changed = false;
|
|
22154
|
+
if (raw === null) {
|
|
22155
|
+
for (const key of FIRST_RUN_FLAG_KEYS) next[key] = true;
|
|
22156
|
+
changed = true;
|
|
22157
|
+
}
|
|
22158
|
+
const existingProjects = next["projects"];
|
|
22159
|
+
const projects = isRecord5(existingProjects) ? { ...existingProjects } : {};
|
|
22160
|
+
for (const trustedPath of input.trustedPaths) {
|
|
22161
|
+
const resolved = NodePath6.resolve(trustedPath);
|
|
22162
|
+
const entry = projects[resolved];
|
|
22163
|
+
const project = isRecord5(entry) ? { ...entry } : {};
|
|
22164
|
+
if (project["hasTrustDialogAccepted"] === true) continue;
|
|
22165
|
+
project["hasTrustDialogAccepted"] = true;
|
|
22166
|
+
projects[resolved] = project;
|
|
22167
|
+
changed = true;
|
|
22168
|
+
}
|
|
22169
|
+
if (Object.keys(projects).length > 0) next["projects"] = projects;
|
|
22170
|
+
if (!changed) return;
|
|
22171
|
+
await writeFileAtomic(filePath, `${JSON.stringify(next, null, 2)}
|
|
22172
|
+
`);
|
|
22173
|
+
}
|
|
22174
|
+
function resolveClaudeLaunchHome(input) {
|
|
22175
|
+
const routed = isRoutedLaunch(input.launchProcessEnv);
|
|
22176
|
+
const dataDirPath = input.pluginDataDirPath?.trim() ?? "";
|
|
22177
|
+
if (routed && dataDirPath.length === 0) {
|
|
22178
|
+
input.log?.warn(
|
|
22179
|
+
"Ycodium is routing this turn but has no directory of its own to hand the CLI; it will read the user's."
|
|
22180
|
+
);
|
|
22181
|
+
}
|
|
22182
|
+
return resolveClaudeHomeLayout({
|
|
22183
|
+
homePath: input.homePath,
|
|
22184
|
+
credentialsPath: input.credentialsPath,
|
|
22185
|
+
...routed && dataDirPath.length > 0 ? { routedHomePath: claudeRoutedHomePath(dataDirPath) } : {},
|
|
22186
|
+
...input.environment === void 0 ? {} : { environment: input.environment }
|
|
22187
|
+
});
|
|
22188
|
+
}
|
|
22189
|
+
async function materializeClaudeRoutedHome(layout, options) {
|
|
22190
|
+
if (layout.mode !== "routed") return;
|
|
22191
|
+
const configDirPath = layout.configDirPath;
|
|
22192
|
+
if (configDirPath === void 0) return;
|
|
22193
|
+
if (configDirPath === layout.userConfigDirPath) {
|
|
22194
|
+
throw new Error(
|
|
22195
|
+
`Ycodium's Claude configuration directory '${configDirPath}' must differ from the user's.`
|
|
22196
|
+
);
|
|
22197
|
+
}
|
|
22198
|
+
await NodeFSP.mkdir(configDirPath, { recursive: true });
|
|
22199
|
+
await NodeFSP.chmod(configDirPath, 448);
|
|
22200
|
+
const credentialsDirPath = layout.credentialsDirPath;
|
|
22201
|
+
if (credentialsDirPath !== void 0 && credentialsDirPath !== configDirPath) {
|
|
22202
|
+
await NodeFSP.mkdir(credentialsDirPath, { recursive: true });
|
|
22203
|
+
await NodeFSP.chmod(credentialsDirPath, 448);
|
|
22204
|
+
}
|
|
22205
|
+
const log = options?.log;
|
|
22206
|
+
for (const entryName of BORROWED_ENTRY_NAMES) {
|
|
22207
|
+
try {
|
|
22208
|
+
await borrowEntry({
|
|
22209
|
+
userConfigDirPath: layout.userConfigDirPath,
|
|
22210
|
+
configDirPath,
|
|
22211
|
+
entryName,
|
|
22212
|
+
log
|
|
22213
|
+
});
|
|
22214
|
+
} catch (error) {
|
|
22215
|
+
log?.warn("Claude routed home entry left unlinked.", {
|
|
22216
|
+
entryName,
|
|
22217
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
22218
|
+
});
|
|
22219
|
+
}
|
|
22220
|
+
}
|
|
22221
|
+
await mirrorUserSettings({
|
|
22222
|
+
userConfigDirPath: layout.userConfigDirPath,
|
|
22223
|
+
configDirPath,
|
|
22224
|
+
log
|
|
22225
|
+
});
|
|
22226
|
+
await seedFirstRun({
|
|
22227
|
+
configDirPath,
|
|
22228
|
+
trustedPaths: options?.trustedPaths ?? [],
|
|
22229
|
+
log
|
|
22230
|
+
});
|
|
22231
|
+
}
|
|
22232
|
+
|
|
22233
|
+
// src/textGeneration.ts
|
|
22234
|
+
import { mergeLaunchEnv, brainSlotEnvKeys as brainSlotEnvKeys2 } from "@ycodium-ai/plugin-api/executor";
|
|
22235
|
+
|
|
21790
22236
|
// src/textGenerationUtils.ts
|
|
21791
22237
|
function limitSection(value, maxChars) {
|
|
21792
22238
|
if (value.length <= maxChars) return value;
|
|
@@ -22134,7 +22580,7 @@ function buildHandoverSummaryPrompt(input) {
|
|
|
22134
22580
|
|
|
22135
22581
|
// src/textGeneration.ts
|
|
22136
22582
|
var CLAUDE_TIMEOUT_MS = 18e4;
|
|
22137
|
-
function
|
|
22583
|
+
function isRecord6(value) {
|
|
22138
22584
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22139
22585
|
}
|
|
22140
22586
|
function readString3(value) {
|
|
@@ -22156,18 +22602,31 @@ function decodeStructuredOutput(stdout, operation) {
|
|
|
22156
22602
|
cause: error
|
|
22157
22603
|
});
|
|
22158
22604
|
}
|
|
22159
|
-
if (!
|
|
22605
|
+
if (!isRecord6(parsed) || !("structured_output" in parsed)) {
|
|
22160
22606
|
throw new Error(`${operation}: Claude CLI returned unexpected output format.`);
|
|
22161
22607
|
}
|
|
22162
22608
|
return parsed.structured_output;
|
|
22163
22609
|
}
|
|
22164
|
-
function createClaudeTextGeneration(recipe, host) {
|
|
22610
|
+
function createClaudeTextGeneration(recipe, host, pluginDataDirPath) {
|
|
22165
22611
|
const runClaudeJson = async (input) => {
|
|
22166
|
-
const
|
|
22167
|
-
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
|
|
22612
|
+
const homeLayout = resolveClaudeLaunchHome({
|
|
22613
|
+
homePath: recipe.homePath,
|
|
22614
|
+
credentialsPath: recipe.credentialsPath,
|
|
22615
|
+
launchProcessEnv: input.launch?.processEnv,
|
|
22616
|
+
pluginDataDirPath,
|
|
22617
|
+
log: host.log
|
|
22618
|
+
});
|
|
22619
|
+
await materializeClaudeRoutedHome(homeLayout, {
|
|
22620
|
+
trustedPaths: [input.cwd],
|
|
22621
|
+
log: host.log
|
|
22622
|
+
});
|
|
22623
|
+
const processEnv = mergeLaunchEnv({
|
|
22624
|
+
brainSlots: brainSlotEnvKeys2(CLAUDE_CARD),
|
|
22625
|
+
instanceTable: recipe.environment,
|
|
22626
|
+
handOverrides: claudeHomeVariables(homeLayout),
|
|
22627
|
+
launch: input.launch?.processEnv
|
|
22628
|
+
});
|
|
22629
|
+
const modelSelection = isRecord6(input.modelSelection) ? input.modelSelection : {};
|
|
22171
22630
|
const requestedModel = input.launch?.requestedModelId ?? modelIdFromSelection(modelSelection) ?? "claude-haiku-4-5";
|
|
22172
22631
|
const caps = claudeModelCapabilities(requestedModel, recipe.customModels);
|
|
22173
22632
|
const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort");
|
|
@@ -22200,7 +22659,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22200
22659
|
program,
|
|
22201
22660
|
args,
|
|
22202
22661
|
cwd: input.cwd,
|
|
22203
|
-
env:
|
|
22662
|
+
env: processEnv,
|
|
22204
22663
|
owner: { bindingId: host.bindingId }
|
|
22205
22664
|
});
|
|
22206
22665
|
const timeout = AbortSignal.timeout(CLAUDE_TIMEOUT_MS);
|
|
@@ -22229,7 +22688,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22229
22688
|
return decodeStructuredOutput(stdout, input.operation);
|
|
22230
22689
|
};
|
|
22231
22690
|
const asRecord = (value, operation) => {
|
|
22232
|
-
if (!
|
|
22691
|
+
if (!isRecord6(value))
|
|
22233
22692
|
throw new Error(`${operation}: Claude returned invalid structured output.`);
|
|
22234
22693
|
return value;
|
|
22235
22694
|
};
|
|
@@ -22243,7 +22702,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22243
22702
|
stagedSummary: readString3(input["stagedSummary"]),
|
|
22244
22703
|
stagedPatch: readString3(input["stagedPatch"]),
|
|
22245
22704
|
includeBranch,
|
|
22246
|
-
...
|
|
22705
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
22247
22706
|
});
|
|
22248
22707
|
const generated = asRecord(
|
|
22249
22708
|
await runClaudeJson({
|
|
@@ -22252,7 +22711,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22252
22711
|
prompt,
|
|
22253
22712
|
outputSchema,
|
|
22254
22713
|
modelSelection: input["modelSelection"],
|
|
22255
|
-
...
|
|
22714
|
+
...isRecord6(input["launch"]) ? { launch: input["launch"] } : {},
|
|
22256
22715
|
...signal === void 0 ? {} : { signal }
|
|
22257
22716
|
}),
|
|
22258
22717
|
"generateCommitMessage"
|
|
@@ -22276,7 +22735,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22276
22735
|
diffSummary: readString3(input["diffSummary"]),
|
|
22277
22736
|
diffPatch: readString3(input["diffPatch"]),
|
|
22278
22737
|
...typeof input["changeRequestTemplate"] === "string" ? { changeRequestTemplate: input["changeRequestTemplate"] } : {},
|
|
22279
|
-
...
|
|
22738
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
22280
22739
|
});
|
|
22281
22740
|
const generated = asRecord(
|
|
22282
22741
|
await runClaudeJson({
|
|
@@ -22285,7 +22744,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22285
22744
|
prompt,
|
|
22286
22745
|
outputSchema,
|
|
22287
22746
|
modelSelection: input["modelSelection"],
|
|
22288
|
-
...
|
|
22747
|
+
...isRecord6(input["launch"]) ? { launch: input["launch"] } : {},
|
|
22289
22748
|
...signal === void 0 ? {} : { signal }
|
|
22290
22749
|
}),
|
|
22291
22750
|
"generatePrContent"
|
|
@@ -22304,7 +22763,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22304
22763
|
const { prompt, outputSchema } = buildBranchNamePrompt({
|
|
22305
22764
|
message: readString3(input["message"]),
|
|
22306
22765
|
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
22307
|
-
...
|
|
22766
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
22308
22767
|
});
|
|
22309
22768
|
const generated = asRecord(
|
|
22310
22769
|
await runClaudeJson({
|
|
@@ -22313,7 +22772,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22313
22772
|
prompt,
|
|
22314
22773
|
outputSchema,
|
|
22315
22774
|
modelSelection: input["modelSelection"],
|
|
22316
|
-
...
|
|
22775
|
+
...isRecord6(input["launch"]) ? { launch: input["launch"] } : {},
|
|
22317
22776
|
...signal === void 0 ? {} : { signal }
|
|
22318
22777
|
}),
|
|
22319
22778
|
"generateBranchName"
|
|
@@ -22330,7 +22789,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22330
22789
|
message: readString3(input["message"]),
|
|
22331
22790
|
...typeof input["previousTitle"] === "string" ? { previousTitle: input["previousTitle"] } : {},
|
|
22332
22791
|
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
22333
|
-
...
|
|
22792
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
22334
22793
|
});
|
|
22335
22794
|
const generated = asRecord(
|
|
22336
22795
|
await runClaudeJson({
|
|
@@ -22339,7 +22798,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22339
22798
|
prompt,
|
|
22340
22799
|
outputSchema,
|
|
22341
22800
|
modelSelection: input["modelSelection"],
|
|
22342
|
-
...
|
|
22801
|
+
...isRecord6(input["launch"]) ? { launch: input["launch"] } : {},
|
|
22343
22802
|
...signal === void 0 ? {} : { signal }
|
|
22344
22803
|
}),
|
|
22345
22804
|
"generateThreadTitle"
|
|
@@ -22362,7 +22821,7 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22362
22821
|
prompt,
|
|
22363
22822
|
outputSchema,
|
|
22364
22823
|
modelSelection: input["modelSelection"],
|
|
22365
|
-
...
|
|
22824
|
+
...isRecord6(input["launch"]) ? { launch: input["launch"] } : {},
|
|
22366
22825
|
...signal === void 0 ? {} : { signal }
|
|
22367
22826
|
}),
|
|
22368
22827
|
"summarizeHandover"
|
|
@@ -22374,14 +22833,6 @@ function createClaudeTextGeneration(recipe, host) {
|
|
|
22374
22833
|
}
|
|
22375
22834
|
};
|
|
22376
22835
|
}
|
|
22377
|
-
function compactEnv(env) {
|
|
22378
|
-
const out = {};
|
|
22379
|
-
if (!env) return out;
|
|
22380
|
-
for (const [key, value] of Object.entries(env)) {
|
|
22381
|
-
if (value !== void 0) out[key] = value;
|
|
22382
|
-
}
|
|
22383
|
-
return out;
|
|
22384
|
-
}
|
|
22385
22836
|
|
|
22386
22837
|
// src/imageMime.ts
|
|
22387
22838
|
var IMAGE_EXTENSION_BY_MIME_TYPE = {
|
|
@@ -22463,9 +22914,9 @@ var PromptQueue = class {
|
|
|
22463
22914
|
const queued = this.#queued.shift();
|
|
22464
22915
|
if (queued !== void 0) return Promise.resolve(queued);
|
|
22465
22916
|
if (this.#closed) return Promise.resolve(void 0);
|
|
22466
|
-
return new Promise((
|
|
22917
|
+
return new Promise((resolve3) => {
|
|
22467
22918
|
this.#waiters.push((result) => {
|
|
22468
|
-
|
|
22919
|
+
resolve3(result.done ? void 0 : result.value);
|
|
22469
22920
|
});
|
|
22470
22921
|
});
|
|
22471
22922
|
}
|
|
@@ -22496,6 +22947,7 @@ var SUPPORTED_CLAUDE_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
22496
22947
|
]);
|
|
22497
22948
|
var CLAUDE_INTERRUPT_GRACE_MS = 5e3;
|
|
22498
22949
|
var CLAUDE_SESSION_CONTEXT_WAIT_MS = 1e4;
|
|
22950
|
+
var CLAUDE_STDERR_TAIL_CHARS = 4e3;
|
|
22499
22951
|
function asClaudeModelSelection(value) {
|
|
22500
22952
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
22501
22953
|
return value;
|
|
@@ -22583,7 +23035,7 @@ async function persistProducedImage(input) {
|
|
|
22583
23035
|
}
|
|
22584
23036
|
|
|
22585
23037
|
// src/claudeInstance.ts
|
|
22586
|
-
function
|
|
23038
|
+
function compactEnv(env) {
|
|
22587
23039
|
const out = {};
|
|
22588
23040
|
if (!env) return out;
|
|
22589
23041
|
for (const [key, value] of Object.entries(env)) {
|
|
@@ -22591,10 +23043,26 @@ function compactEnv2(env) {
|
|
|
22591
23043
|
}
|
|
22592
23044
|
return out;
|
|
22593
23045
|
}
|
|
23046
|
+
function toClaudeMcpServers(entries) {
|
|
23047
|
+
if (entries === void 0 || entries.length === 0) return void 0;
|
|
23048
|
+
const servers = {};
|
|
23049
|
+
for (const entry of entries) {
|
|
23050
|
+
servers[entry.name] = entry.transport.type === "stdio" ? {
|
|
23051
|
+
type: "stdio",
|
|
23052
|
+
command: entry.transport.command,
|
|
23053
|
+
...entry.transport.args === void 0 ? {} : { args: [...entry.transport.args] },
|
|
23054
|
+
...entry.transport.env === void 0 ? {} : { env: { ...entry.transport.env } }
|
|
23055
|
+
} : {
|
|
23056
|
+
type: entry.transport.type,
|
|
23057
|
+
url: entry.transport.url,
|
|
23058
|
+
...entry.transport.headers === void 0 ? {} : { headers: { ...entry.transport.headers } }
|
|
23059
|
+
};
|
|
23060
|
+
}
|
|
23061
|
+
return servers;
|
|
23062
|
+
}
|
|
22594
23063
|
function createClaudeAdapter(recipe, host, options) {
|
|
22595
23064
|
const boundInstanceId = options?.instanceId ?? host.instanceId ?? "claudeAgent";
|
|
22596
23065
|
const claudeHomeEnvironment = makeClaudeEnvironment(recipe, options?.environment);
|
|
22597
|
-
const sessionLaunchEnv = /* @__PURE__ */ new Map();
|
|
22598
23066
|
const claudeSdkExecutablePath = resolveClaudeSdkExecutablePath(
|
|
22599
23067
|
recipe.binaryPath,
|
|
22600
23068
|
claudeHomeEnvironment
|
|
@@ -22886,8 +23354,8 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
22886
23354
|
try {
|
|
22887
23355
|
usage = await Promise.race([
|
|
22888
23356
|
context.query.getContextUsage(),
|
|
22889
|
-
new Promise((
|
|
22890
|
-
setTimeout(() =>
|
|
23357
|
+
new Promise((resolve3) => {
|
|
23358
|
+
setTimeout(() => resolve3(void 0), 1e3);
|
|
22891
23359
|
})
|
|
22892
23360
|
]);
|
|
22893
23361
|
} catch {
|
|
@@ -24180,7 +24648,9 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24180
24648
|
await completeTurn(context, "interrupted", "Claude runtime interrupted.");
|
|
24181
24649
|
}
|
|
24182
24650
|
} else {
|
|
24183
|
-
const
|
|
24651
|
+
const cliSaid = context.stderrTail.read();
|
|
24652
|
+
const reason = cause instanceof Error ? cause.message : "Claude runtime stream failed.";
|
|
24653
|
+
const message = cliSaid.length > 0 ? `${reason}: ${cliSaid}` : reason;
|
|
24184
24654
|
await emitRuntimeError(context, message, { cause: String(cause) });
|
|
24185
24655
|
await completeTurn(context, "failed", message);
|
|
24186
24656
|
}
|
|
@@ -24256,7 +24726,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24256
24726
|
if (streamFiber) {
|
|
24257
24727
|
await Promise.race([
|
|
24258
24728
|
streamFiber.catch(() => void 0),
|
|
24259
|
-
new Promise((
|
|
24729
|
+
new Promise((resolve3) => setTimeout(resolve3, 1e3))
|
|
24260
24730
|
]);
|
|
24261
24731
|
}
|
|
24262
24732
|
const updatedAt = nowIso();
|
|
@@ -24283,9 +24753,6 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24283
24753
|
}
|
|
24284
24754
|
if (sessions.get(context.session.threadId) === context) {
|
|
24285
24755
|
sessions.delete(context.session.threadId);
|
|
24286
|
-
if (stopOptions?.keepLaunch !== true) {
|
|
24287
|
-
sessionLaunchEnv.delete(context.session.threadId);
|
|
24288
|
-
}
|
|
24289
24756
|
}
|
|
24290
24757
|
})();
|
|
24291
24758
|
context.stopWork = work;
|
|
@@ -24365,7 +24832,13 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24365
24832
|
const modelSelection = boundModelSelection(input.modelSelection, boundInstanceId);
|
|
24366
24833
|
const caps = claudeModelCapabilities(modelSelection?.model, recipe.customModels);
|
|
24367
24834
|
const descriptors = caps.optionDescriptors;
|
|
24368
|
-
const apiModelId = modelSelection?.model ? resolveClaudeApiModelId(caps, {
|
|
24835
|
+
const apiModelId = modelSelection?.model ? resolveClaudeApiModelId(caps, {
|
|
24836
|
+
model: claudeCliModelId({
|
|
24837
|
+
boundModelId: modelSelection.model,
|
|
24838
|
+
placeholder: CLAUDE_CARD.defaultModel,
|
|
24839
|
+
customModels: recipe.customModels
|
|
24840
|
+
})
|
|
24841
|
+
}) : void 0;
|
|
24369
24842
|
const initialContextWindow = selectedClaudeContextWindow(caps, modelSelection);
|
|
24370
24843
|
const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort");
|
|
24371
24844
|
const effort = resolveClaudeEffort(caps, rawEffort) ?? null;
|
|
@@ -24379,16 +24852,13 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24379
24852
|
const thinking = thinkingSupported ? getModelSelectionBooleanOptionValue(modelSelection, "thinking") : void 0;
|
|
24380
24853
|
const ultracode = isClaudeUltracodeEffort(effort);
|
|
24381
24854
|
const effectiveEffort = getEffectiveClaudeAgentEffort(effort, modelSelection?.model, caps);
|
|
24382
|
-
const permissionMode =
|
|
24855
|
+
const permissionMode = claudePermissionModeFor(input.runtimeMode, input.nativeModeId);
|
|
24383
24856
|
const settings = buildClaudeSessionSettings({
|
|
24384
24857
|
thinking,
|
|
24385
24858
|
fastMode,
|
|
24386
24859
|
ultracode,
|
|
24387
24860
|
autoCompactWindow: recipe.autoCompactWindow
|
|
24388
24861
|
});
|
|
24389
|
-
if (input.launch.processEnv) {
|
|
24390
|
-
sessionLaunchEnv.set(input.threadId, input.launch.processEnv);
|
|
24391
|
-
}
|
|
24392
24862
|
const existingContext = sessions.get(input.threadId);
|
|
24393
24863
|
if (existingContext) {
|
|
24394
24864
|
const reconfigured = await reconfigureSession(existingContext, input, {
|
|
@@ -24407,10 +24877,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24407
24877
|
existingSessionStatus: existingContext.session.status,
|
|
24408
24878
|
reason: "startSession called with existing active session"
|
|
24409
24879
|
});
|
|
24410
|
-
await stopSessionInternal(existingContext, {
|
|
24411
|
-
emitExitEvent: false,
|
|
24412
|
-
keepLaunch: true
|
|
24413
|
-
});
|
|
24880
|
+
await stopSessionInternal(existingContext, { emitExitEvent: false });
|
|
24414
24881
|
}
|
|
24415
24882
|
const startedAt = nowIso();
|
|
24416
24883
|
const resumeState = input.discardResumeCursor === true ? void 0 : readClaudeResumeState(input.resumeCursor);
|
|
@@ -24433,7 +24900,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24433
24900
|
return await Promise.race([
|
|
24434
24901
|
contextDeferred.promise,
|
|
24435
24902
|
new Promise(
|
|
24436
|
-
(
|
|
24903
|
+
(resolve3) => setTimeout(() => resolve3(void 0), CLAUDE_SESSION_CONTEXT_WAIT_MS)
|
|
24437
24904
|
)
|
|
24438
24905
|
]);
|
|
24439
24906
|
} catch {
|
|
@@ -24575,7 +25042,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24575
25042
|
message: "The client captured your proposed plan. Stop here and wait for the user's feedback or implementation request in a later turn."
|
|
24576
25043
|
};
|
|
24577
25044
|
}
|
|
24578
|
-
if (context2.
|
|
25045
|
+
if (context2.currentPermissionMode === "bypassPermissions") {
|
|
24579
25046
|
return {
|
|
24580
25047
|
behavior: "allow",
|
|
24581
25048
|
updatedInput: toolInput
|
|
@@ -24716,16 +25183,33 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24716
25183
|
};
|
|
24717
25184
|
const onUserDialog = (request, callbackOptions) => handleResumeDialog(request, callbackOptions);
|
|
24718
25185
|
const additionalDirectories = input.cwd ? [input.cwd] : [];
|
|
24719
|
-
const
|
|
24720
|
-
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
...
|
|
24727
|
-
};
|
|
24728
|
-
|
|
25186
|
+
const mcpServers = toClaudeMcpServers(input.mcpServers);
|
|
25187
|
+
const homeLayout = resolveClaudeLaunchHome({
|
|
25188
|
+
homePath: recipe.homePath,
|
|
25189
|
+
credentialsPath: recipe.credentialsPath,
|
|
25190
|
+
launchProcessEnv: input.launch.processEnv,
|
|
25191
|
+
pluginDataDirPath: options?.pluginDataDirPath,
|
|
25192
|
+
environment: claudeHomeEnvironment,
|
|
25193
|
+
...options?.log === void 0 ? {} : { log: options.log }
|
|
25194
|
+
});
|
|
25195
|
+
await materializeClaudeRoutedHome(homeLayout, {
|
|
25196
|
+
...input.cwd ? { trustedPaths: [input.cwd] } : {},
|
|
25197
|
+
...options?.log === void 0 ? {} : { log: options.log }
|
|
25198
|
+
});
|
|
25199
|
+
const launchEnvironment = mergeLaunchEnv2({
|
|
25200
|
+
brainSlots: brainSlotEnvKeys3(CLAUDE_CARD),
|
|
25201
|
+
inherited: { ...process.env, ...options?.environment },
|
|
25202
|
+
instanceTable: recipe.environment,
|
|
25203
|
+
handOverrides: claudeHomeVariables(homeLayout),
|
|
25204
|
+
launch: input.launch.processEnv
|
|
25205
|
+
});
|
|
25206
|
+
const envOverride = routedEnvOverride({
|
|
25207
|
+
launchProcessEnv: input.launch.processEnv,
|
|
25208
|
+
mergedEnv: launchEnvironment,
|
|
25209
|
+
...recipe.customModels === void 0 ? {} : { customModels: recipe.customModels }
|
|
25210
|
+
});
|
|
25211
|
+
const querySettings = envOverride === void 0 ? { ...settings } : { ...settings, env: envOverride };
|
|
25212
|
+
const stderrTail = createOutputTail(CLAUDE_STDERR_TAIL_CHARS);
|
|
24729
25213
|
const queryOptions = {
|
|
24730
25214
|
...input.cwd ? { cwd: input.cwd } : {},
|
|
24731
25215
|
...apiModelId ? { model: apiModelId } : {},
|
|
@@ -24741,6 +25225,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24741
25225
|
...existingResumeSessionId ? { resume: existingResumeSessionId } : {},
|
|
24742
25226
|
...newSessionId ? { sessionId: newSessionId } : {},
|
|
24743
25227
|
includePartialMessages: true,
|
|
25228
|
+
stderr: stderrTail.append,
|
|
24744
25229
|
canUseTool,
|
|
24745
25230
|
onUserDialog,
|
|
24746
25231
|
hooks: {
|
|
@@ -24758,9 +25243,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24758
25243
|
]
|
|
24759
25244
|
},
|
|
24760
25245
|
supportedDialogKinds: ["resume_return"],
|
|
24761
|
-
env:
|
|
25246
|
+
env: compactEnv(launchEnvironment),
|
|
24762
25247
|
additionalDirectories,
|
|
24763
|
-
...Object.keys(extraArgs).length > 0 ? { extraArgs } : {}
|
|
25248
|
+
...Object.keys(extraArgs).length > 0 ? { extraArgs } : {},
|
|
25249
|
+
...mcpServers === void 0 ? {} : { mcpServers }
|
|
24764
25250
|
};
|
|
24765
25251
|
let queryRuntime;
|
|
24766
25252
|
try {
|
|
@@ -24777,6 +25263,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24777
25263
|
providerInstanceId: boundInstanceId,
|
|
24778
25264
|
status: "ready",
|
|
24779
25265
|
runtimeMode: input.runtimeMode,
|
|
25266
|
+
nativeModeId: permissionMode,
|
|
24780
25267
|
...input.cwd ? { cwd: input.cwd } : {},
|
|
24781
25268
|
...modelSelection?.model ? { model: modelSelection.model } : {},
|
|
24782
25269
|
resumeCursor: {
|
|
@@ -24796,6 +25283,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24796
25283
|
},
|
|
24797
25284
|
promptQueue,
|
|
24798
25285
|
query: queryRuntime,
|
|
25286
|
+
stderrTail,
|
|
24799
25287
|
streamFiber: void 0,
|
|
24800
25288
|
startedAt,
|
|
24801
25289
|
basePermissionMode: permissionMode,
|
|
@@ -24904,7 +25392,13 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24904
25392
|
}
|
|
24905
25393
|
if (modelSelection?.model) {
|
|
24906
25394
|
const turnCaps = claudeModelCapabilities(modelSelection.model, recipe.customModels);
|
|
24907
|
-
const apiModelId = resolveClaudeApiModelId(turnCaps, {
|
|
25395
|
+
const apiModelId = resolveClaudeApiModelId(turnCaps, {
|
|
25396
|
+
model: claudeCliModelId({
|
|
25397
|
+
boundModelId: modelSelection.model,
|
|
25398
|
+
placeholder: CLAUDE_CARD.defaultModel,
|
|
25399
|
+
customModels: recipe.customModels
|
|
25400
|
+
})
|
|
25401
|
+
});
|
|
24908
25402
|
if (context.currentApiModelId !== apiModelId) {
|
|
24909
25403
|
try {
|
|
24910
25404
|
await context.query.setModel(apiModelId);
|
|
@@ -25002,7 +25496,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25002
25496
|
context.query.interrupt().then(() => settled.promise).then(() => {
|
|
25003
25497
|
acknowledged = true;
|
|
25004
25498
|
}),
|
|
25005
|
-
new Promise((
|
|
25499
|
+
new Promise((resolve3) => setTimeout(resolve3, CLAUDE_INTERRUPT_GRACE_MS))
|
|
25006
25500
|
]);
|
|
25007
25501
|
} catch (cause) {
|
|
25008
25502
|
throw toRequestError(threadId, "turn/interrupt", cause);
|
|
@@ -25037,22 +25531,49 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25037
25531
|
if (context.session.runtimeMode === runtimeMode) {
|
|
25038
25532
|
return;
|
|
25039
25533
|
}
|
|
25040
|
-
const permissionMode =
|
|
25534
|
+
const permissionMode = claudePermissionModeFor(runtimeMode);
|
|
25041
25535
|
context.basePermissionMode = permissionMode;
|
|
25042
25536
|
context.session = {
|
|
25043
25537
|
...context.session,
|
|
25044
25538
|
runtimeMode,
|
|
25539
|
+
nativeModeId: permissionMode,
|
|
25045
25540
|
updatedAt: nowIso()
|
|
25046
25541
|
};
|
|
25047
25542
|
if (context.currentPermissionMode !== "plan") {
|
|
25048
25543
|
try {
|
|
25049
|
-
await context.query.setPermissionMode(permissionMode
|
|
25544
|
+
await context.query.setPermissionMode(permissionMode);
|
|
25050
25545
|
} catch (cause) {
|
|
25051
25546
|
throw toRequestError(threadId, "session/setPermissionMode", cause);
|
|
25052
25547
|
}
|
|
25053
25548
|
context.currentPermissionMode = permissionMode;
|
|
25054
25549
|
}
|
|
25055
|
-
if (
|
|
25550
|
+
if (permissionMode !== "bypassPermissions") {
|
|
25551
|
+
return;
|
|
25552
|
+
}
|
|
25553
|
+
for (const [requestId, pending] of context.pendingApprovals) {
|
|
25554
|
+
context.pendingApprovals.delete(requestId);
|
|
25555
|
+
pending.decision.resolve({ decision: "accept" });
|
|
25556
|
+
}
|
|
25557
|
+
};
|
|
25558
|
+
const setNativeMode = async (threadId, nativeModeId) => {
|
|
25559
|
+
const context = requireSession(threadId);
|
|
25560
|
+
if (!isClaudeNativeModeId(nativeModeId)) return;
|
|
25561
|
+
if (context.currentPermissionMode === nativeModeId) return;
|
|
25562
|
+
context.basePermissionMode = nativeModeId;
|
|
25563
|
+
context.session = {
|
|
25564
|
+
...context.session,
|
|
25565
|
+
nativeModeId,
|
|
25566
|
+
updatedAt: nowIso()
|
|
25567
|
+
};
|
|
25568
|
+
if (context.currentPermissionMode !== "plan" || nativeModeId === "plan") {
|
|
25569
|
+
try {
|
|
25570
|
+
await context.query.setPermissionMode(nativeModeId);
|
|
25571
|
+
} catch (cause) {
|
|
25572
|
+
throw toRequestError(threadId, "session/setPermissionMode", cause);
|
|
25573
|
+
}
|
|
25574
|
+
context.currentPermissionMode = nativeModeId;
|
|
25575
|
+
}
|
|
25576
|
+
if (nativeModeId !== "bypassPermissions") {
|
|
25056
25577
|
return;
|
|
25057
25578
|
}
|
|
25058
25579
|
for (const [requestId, pending] of context.pendingApprovals) {
|
|
@@ -25085,6 +25606,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25085
25606
|
respondToRequest,
|
|
25086
25607
|
respondToUserInput,
|
|
25087
25608
|
setRuntimeMode,
|
|
25609
|
+
setNativeMode,
|
|
25088
25610
|
stopSession,
|
|
25089
25611
|
events: runtimeEventQueue,
|
|
25090
25612
|
dispose: async () => {
|
|
@@ -25095,12 +25617,19 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25095
25617
|
}
|
|
25096
25618
|
};
|
|
25097
25619
|
}
|
|
25098
|
-
function
|
|
25620
|
+
function claudeAdapterBaseEnvironment(recipe) {
|
|
25621
|
+
return {
|
|
25622
|
+
...process.env,
|
|
25623
|
+
...withoutBrainSlots(recipe.environment, brainSlotEnvKeys3(CLAUDE_CARD))
|
|
25624
|
+
};
|
|
25625
|
+
}
|
|
25626
|
+
function createClaudeInstance(config, host, attachments, pluginDataDirPath) {
|
|
25099
25627
|
const recipe = parseClaudeInstanceConfig(config);
|
|
25100
25628
|
const adapter = createClaudeAdapter(recipe, host, {
|
|
25101
25629
|
instanceId: host.instanceId,
|
|
25102
25630
|
...attachments === void 0 ? {} : { attachments },
|
|
25103
|
-
|
|
25631
|
+
...pluginDataDirPath === void 0 ? {} : { pluginDataDirPath },
|
|
25632
|
+
environment: claudeAdapterBaseEnvironment(recipe),
|
|
25104
25633
|
log: host.log
|
|
25105
25634
|
});
|
|
25106
25635
|
const collectProcessText = async (stream) => {
|
|
@@ -25111,6 +25640,15 @@ function createClaudeInstance(config, host, attachments) {
|
|
|
25111
25640
|
return Buffer.concat(chunks).toString("utf8");
|
|
25112
25641
|
};
|
|
25113
25642
|
const probeAuth = () => {
|
|
25643
|
+
const hasEnvToken = (recipe.environment.ANTHROPIC_AUTH_TOKEN ?? "").trim().length > 0;
|
|
25644
|
+
const hasEnvApiKey = (recipe.environment.ANTHROPIC_API_KEY ?? "").trim().length > 0;
|
|
25645
|
+
if (hasEnvToken || hasEnvApiKey) {
|
|
25646
|
+
return {
|
|
25647
|
+
status: "authenticated",
|
|
25648
|
+
type: hasEnvToken ? "env-token" : "api-key",
|
|
25649
|
+
label: hasEnvToken ? "ANTHROPIC_AUTH_TOKEN" : "ANTHROPIC_API_KEY"
|
|
25650
|
+
};
|
|
25651
|
+
}
|
|
25114
25652
|
const account = readClaudeAccount(resolveClaudeCredentialsDirPath(recipe.credentialsPath));
|
|
25115
25653
|
switch (account.state) {
|
|
25116
25654
|
case "signed-in":
|
|
@@ -25147,6 +25685,10 @@ function createClaudeInstance(config, host, attachments) {
|
|
|
25147
25685
|
]);
|
|
25148
25686
|
const version = parseGenericCliVersion(`${stdout}
|
|
25149
25687
|
${stderr}`);
|
|
25688
|
+
const models = claudeProbeModels({
|
|
25689
|
+
builtIn: getBuiltInClaudeModelsForVersion(version),
|
|
25690
|
+
customModels: recipe.customModels
|
|
25691
|
+
});
|
|
25150
25692
|
const auth = probeAuth();
|
|
25151
25693
|
if (exitCode !== 0 && version === null) {
|
|
25152
25694
|
const detail = (stderr || stdout || "claude --version failed").trim();
|
|
@@ -25164,14 +25706,19 @@ ${stderr}`);
|
|
|
25164
25706
|
version,
|
|
25165
25707
|
readiness: "error",
|
|
25166
25708
|
auth,
|
|
25167
|
-
|
|
25709
|
+
models,
|
|
25710
|
+
detail: "Claude is signed out",
|
|
25711
|
+
// 退出登录了档位照样是那五档。不报就退回宿主四档,而那份映射少了 `plan`。
|
|
25712
|
+
...CLAUDE_NATIVE_MODE_REPORT
|
|
25168
25713
|
};
|
|
25169
25714
|
}
|
|
25170
25715
|
return {
|
|
25171
25716
|
installed: true,
|
|
25172
25717
|
version,
|
|
25173
25718
|
readiness: "ready",
|
|
25174
|
-
auth
|
|
25719
|
+
auth,
|
|
25720
|
+
models,
|
|
25721
|
+
...CLAUDE_NATIVE_MODE_REPORT
|
|
25175
25722
|
};
|
|
25176
25723
|
};
|
|
25177
25724
|
const resolveTranscriptRoots = (directory) => {
|
|
@@ -25182,7 +25729,7 @@ ${stderr}`);
|
|
|
25182
25729
|
);
|
|
25183
25730
|
return {
|
|
25184
25731
|
configDir,
|
|
25185
|
-
transcriptDir:
|
|
25732
|
+
transcriptDir: NodePath7.join(configDir, "projects")
|
|
25186
25733
|
};
|
|
25187
25734
|
};
|
|
25188
25735
|
return {
|
|
@@ -25193,12 +25740,13 @@ ${stderr}`);
|
|
|
25193
25740
|
respondToRequest: adapter.respondToRequest,
|
|
25194
25741
|
respondToUserInput: adapter.respondToUserInput,
|
|
25195
25742
|
setRuntimeMode: adapter.setRuntimeMode,
|
|
25743
|
+
setNativeMode: adapter.setNativeMode,
|
|
25196
25744
|
compactContext: adapter.compactContext,
|
|
25197
25745
|
stopSession: adapter.stopSession,
|
|
25198
25746
|
readThread: adapter.readThread,
|
|
25199
25747
|
events: adapter.events,
|
|
25200
25748
|
dispose: adapter.dispose,
|
|
25201
|
-
textGeneration: createClaudeTextGeneration(recipe, host),
|
|
25749
|
+
textGeneration: createClaudeTextGeneration(recipe, host, pluginDataDirPath),
|
|
25202
25750
|
sessions: {
|
|
25203
25751
|
scan: async (input) => {
|
|
25204
25752
|
const roots = resolveTranscriptRoots(input.directory);
|
|
@@ -25239,12 +25787,13 @@ ${stderr}`);
|
|
|
25239
25787
|
|
|
25240
25788
|
// src/index.ts
|
|
25241
25789
|
var capturedAttachments;
|
|
25790
|
+
var capturedDataDirPath;
|
|
25242
25791
|
var executors = [
|
|
25243
25792
|
{
|
|
25244
25793
|
card: CLAUDE_CARD,
|
|
25245
25794
|
createInstance: async (config, host) => {
|
|
25246
25795
|
host.log.info("createInstance");
|
|
25247
|
-
return createClaudeInstance(config, host, capturedAttachments);
|
|
25796
|
+
return createClaudeInstance(config, host, capturedAttachments, capturedDataDirPath);
|
|
25248
25797
|
}
|
|
25249
25798
|
}
|
|
25250
25799
|
];
|
|
@@ -25254,6 +25803,7 @@ var index_default = definePlugin({
|
|
|
25254
25803
|
executors,
|
|
25255
25804
|
activate(ctx) {
|
|
25256
25805
|
capturedAttachments = ctx.attachments;
|
|
25806
|
+
capturedDataDirPath = ctx.paths.dataDir;
|
|
25257
25807
|
ctx.log.info("claude executor ready");
|
|
25258
25808
|
}
|
|
25259
25809
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-claude",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2126",
|
|
4
4
|
"description": "Claude executor: Claude Code CLI via @anthropic-ai/claude-agent-sdk.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"@types/node": "24.12.4",
|
|
24
24
|
"esbuild": "0.28.1",
|
|
25
25
|
"vite-plus": "0.2.2",
|
|
26
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
26
|
+
"@ycodium-ai/plugin-api": "0.2.2126"
|
|
27
27
|
},
|
|
28
28
|
"ycodium": {
|
|
29
29
|
"plugin": "./dist/index.js",
|
|
30
|
-
"displayName": "Claude",
|
|
30
|
+
"displayName": "Claude Code",
|
|
31
31
|
"description": "Run Claude Code with in-session model and runtime-mode switching, native compaction, and session import.",
|
|
32
32
|
"icon": "./assets/icon.svg",
|
|
33
33
|
"permissions": [
|