@ycodium-ai/agent-claude 0.2.2678 → 0.2.2694
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 +1894 -797
- package/locales/en.json +6 -0
- package/locales/zh-CN.json +6 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -217,7 +217,7 @@ var CLAUDE_CARD = {
|
|
|
217
217
|
|
|
218
218
|
// src/claudeInstance.ts
|
|
219
219
|
import * as NodeOS8 from "node:os";
|
|
220
|
-
import * as
|
|
220
|
+
import * as NodePath13 from "node:path";
|
|
221
221
|
|
|
222
222
|
// ../../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
|
|
223
223
|
import { createRequire as xz } from "node:module";
|
|
@@ -19650,10 +19650,12 @@ function HU(e, t) {
|
|
|
19650
19650
|
}
|
|
19651
19651
|
|
|
19652
19652
|
// src/claudeInstance.ts
|
|
19653
|
+
import { mergeLaunchEnv as mergeLaunchEnv3 } from "@ycodium-ai/plugin-api/executor";
|
|
19654
|
+
|
|
19655
|
+
// src/claudeProbe.ts
|
|
19653
19656
|
import {
|
|
19654
19657
|
describeExecutorSpawnFailure,
|
|
19655
|
-
ExecutorSpawnRefusedError
|
|
19656
|
-
mergeLaunchEnv as mergeLaunchEnv2
|
|
19658
|
+
ExecutorSpawnRefusedError
|
|
19657
19659
|
} from "@ycodium-ai/plugin-api/executor";
|
|
19658
19660
|
|
|
19659
19661
|
// src/claudeAccount.ts
|
|
@@ -19743,78 +19745,73 @@ function readClaudeAccount(credentialsDirPath) {
|
|
|
19743
19745
|
};
|
|
19744
19746
|
}
|
|
19745
19747
|
|
|
19746
|
-
// src/claudeExecutable.ts
|
|
19747
|
-
import * as NodeFS2 from "node:fs";
|
|
19748
|
-
import * as NodeOS2 from "node:os";
|
|
19749
|
-
import * as NodePath2 from "node:path";
|
|
19750
|
-
var WINDOWS_SHIM_EXTENSIONS = /* @__PURE__ */ new Set([".cmd", ".bat", ".ps1"]);
|
|
19751
|
-
var NPM_PACKAGE_ENTRY_CANDIDATES = [
|
|
19752
|
-
["node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe"],
|
|
19753
|
-
["node_modules", "@anthropic-ai", "claude-code", "cli.js"]
|
|
19754
|
-
];
|
|
19755
|
-
function isExistingFile(filePath) {
|
|
19756
|
-
try {
|
|
19757
|
-
return NodeFS2.statSync(filePath).isFile();
|
|
19758
|
-
} catch {
|
|
19759
|
-
return false;
|
|
19760
|
-
}
|
|
19761
|
-
}
|
|
19762
|
-
function resolveClaudeSdkExecutablePath(binaryPath, environment = process.env, isFile = isExistingFile, isWindows = NodeOS2.type() === "Windows_NT") {
|
|
19763
|
-
if (!isWindows) {
|
|
19764
|
-
return binaryPath;
|
|
19765
|
-
}
|
|
19766
|
-
const resolved = resolveWindowsExecutable(binaryPath, environment) ?? binaryPath;
|
|
19767
|
-
const extension = NodePath2.win32.extname(resolved).toLowerCase();
|
|
19768
|
-
if (!WINDOWS_SHIM_EXTENSIONS.has(extension)) {
|
|
19769
|
-
return resolved;
|
|
19770
|
-
}
|
|
19771
|
-
const shimDirectory = NodePath2.win32.dirname(resolved);
|
|
19772
|
-
for (const entrySegments of NPM_PACKAGE_ENTRY_CANDIDATES) {
|
|
19773
|
-
const candidate = NodePath2.win32.join(shimDirectory, ...entrySegments);
|
|
19774
|
-
if (isFile(candidate)) {
|
|
19775
|
-
return candidate;
|
|
19776
|
-
}
|
|
19777
|
-
}
|
|
19778
|
-
return binaryPath;
|
|
19779
|
-
}
|
|
19780
|
-
function resolveWindowsExecutable(binaryPath, environment) {
|
|
19781
|
-
const trimmed = binaryPath.trim();
|
|
19782
|
-
if (trimmed.length === 0) return void 0;
|
|
19783
|
-
if (NodePath2.win32.isAbsolute(trimmed) && isExistingFile(trimmed)) return trimmed;
|
|
19784
|
-
const pathValue = environment.PATH ?? environment.Path ?? "";
|
|
19785
|
-
const pathext = environment.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
19786
|
-
const extensions = pathext.split(";").filter((ext) => ext.length > 0);
|
|
19787
|
-
const hasExt = NodePath2.win32.extname(trimmed).length > 0;
|
|
19788
|
-
for (const dir of pathValue.split(";")) {
|
|
19789
|
-
if (dir.trim().length === 0) continue;
|
|
19790
|
-
const candidates = hasExt ? [NodePath2.win32.join(dir, trimmed)] : extensions.map((ext) => NodePath2.win32.join(dir, `${trimmed}${ext}`));
|
|
19791
|
-
for (const candidate of candidates) {
|
|
19792
|
-
if (isExistingFile(candidate)) return candidate;
|
|
19793
|
-
}
|
|
19794
|
-
}
|
|
19795
|
-
return void 0;
|
|
19796
|
-
}
|
|
19797
|
-
|
|
19798
19748
|
// src/claudeHome.ts
|
|
19799
|
-
import * as NodeOS4 from "node:os";
|
|
19800
|
-
import * as NodePath4 from "node:path";
|
|
19801
|
-
|
|
19802
|
-
// src/pathExpansion.ts
|
|
19803
19749
|
import * as NodeOS3 from "node:os";
|
|
19804
19750
|
import * as NodePath3 from "node:path";
|
|
19751
|
+
|
|
19752
|
+
// src/pathExpansion.ts
|
|
19753
|
+
import * as NodeOS2 from "node:os";
|
|
19754
|
+
import * as NodePath2 from "node:path";
|
|
19805
19755
|
function expandHomePath(value) {
|
|
19806
|
-
if (value === "~") return
|
|
19756
|
+
if (value === "~") return NodeOS2.homedir();
|
|
19807
19757
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
19808
|
-
return
|
|
19758
|
+
return NodePath2.join(NodeOS2.homedir(), value.slice(2));
|
|
19809
19759
|
}
|
|
19810
19760
|
return value;
|
|
19811
19761
|
}
|
|
19812
19762
|
|
|
19763
|
+
// src/usageLimit.ts
|
|
19764
|
+
var WINDOW_NAMES = {
|
|
19765
|
+
five_hour: "5-hour",
|
|
19766
|
+
seven_day: "7-day",
|
|
19767
|
+
seven_day_opus: "7-day Opus",
|
|
19768
|
+
seven_day_sonnet: "7-day Sonnet",
|
|
19769
|
+
overage: "overage"
|
|
19770
|
+
};
|
|
19771
|
+
var MAX_CREDIBLE_WAIT_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
19772
|
+
var isBlockingRateLimit = (info) => info.status === "rejected" && info.overageStatus !== "allowed" && info.overageStatus !== "allowed_warning" && info.isUsingOverage !== true && info.overageInUse !== true;
|
|
19773
|
+
var isClearingRateLimit = (info) => info.status === "allowed" || info.status === "allowed_warning" || info.overageStatus === "allowed" || info.overageStatus === "allowed_warning" || info.isUsingOverage === true || info.overageInUse === true;
|
|
19774
|
+
var rateLimitKey = (info) => `${info.rateLimitType ?? "unknown"}:${String(info.resetsAt ?? "unknown")}`;
|
|
19775
|
+
var formatLimitWait = (waitMs) => {
|
|
19776
|
+
const totalMinutes = Math.max(1, Math.ceil(waitMs / 6e4));
|
|
19777
|
+
const days = Math.floor(totalMinutes / (24 * 60));
|
|
19778
|
+
const hours = Math.floor(totalMinutes % (24 * 60) / 60);
|
|
19779
|
+
const minutes = totalMinutes % 60;
|
|
19780
|
+
if (days > 0) return hours === 0 ? `${String(days)}d` : `${String(days)}d ${String(hours)}h`;
|
|
19781
|
+
if (hours === 0) return `${String(totalMinutes)}m`;
|
|
19782
|
+
return minutes === 0 ? `${String(hours)}h` : `${String(hours)}h ${String(minutes)}m`;
|
|
19783
|
+
};
|
|
19784
|
+
var waitUntil = (resetsAtSeconds, nowMs) => {
|
|
19785
|
+
if (resetsAtSeconds === void 0 || !Number.isFinite(nowMs)) return void 0;
|
|
19786
|
+
const waitMs = resetsAtSeconds * 1e3 - nowMs;
|
|
19787
|
+
return waitMs > 0 && waitMs <= MAX_CREDIBLE_WAIT_MS ? formatLimitWait(waitMs) : void 0;
|
|
19788
|
+
};
|
|
19789
|
+
var describeUsageLimitPause = (info, nowMs) => {
|
|
19790
|
+
const name = info.rateLimitType === void 0 ? void 0 : WINDOW_NAMES[info.rateLimitType];
|
|
19791
|
+
const wait = waitUntil(info.resetsAt, nowMs);
|
|
19792
|
+
return `Claude usage limit reached. This turn is paused until the ${name === void 0 ? "" : `${name} `}limit resets${wait === void 0 ? "" : ` in ${wait}`}.`;
|
|
19793
|
+
};
|
|
19794
|
+
var describeUsageLimitFailure = (rejected, nowMs) => {
|
|
19795
|
+
let name;
|
|
19796
|
+
let wait;
|
|
19797
|
+
let latestResetSeconds = Number.NEGATIVE_INFINITY;
|
|
19798
|
+
for (const [type4, resetsAt] of rejected) {
|
|
19799
|
+
const label = WINDOW_NAMES[type4];
|
|
19800
|
+
const reachable = waitUntil(resetsAt, nowMs);
|
|
19801
|
+
if (label === void 0 || reachable === void 0 || resetsAt === void 0) continue;
|
|
19802
|
+
if (resetsAt <= latestResetSeconds) continue;
|
|
19803
|
+
latestResetSeconds = resetsAt;
|
|
19804
|
+
name = label;
|
|
19805
|
+
wait = reachable;
|
|
19806
|
+
}
|
|
19807
|
+
return name === void 0 ? "Claude usage limit reached. Send the message again once the limit resets." : `Claude usage limit reached. The ${name} limit resets in ${wait}. Send the message again once it resets.`;
|
|
19808
|
+
};
|
|
19809
|
+
|
|
19813
19810
|
// src/claudeHome.ts
|
|
19814
19811
|
var CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE = "CLAUDE_SECURESTORAGE_CONFIG_DIR";
|
|
19815
19812
|
function resolveClaudeHomePath(homePath) {
|
|
19816
19813
|
const trimmed = homePath.trim();
|
|
19817
|
-
return
|
|
19814
|
+
return NodePath3.resolve(trimmed.length > 0 ? expandHomePath(trimmed) : NodeOS3.homedir());
|
|
19818
19815
|
}
|
|
19819
19816
|
function claudeContinuationKey(homePath) {
|
|
19820
19817
|
return `claude:home:${resolveClaudeHomePath(homePath)}`;
|
|
@@ -19822,18 +19819,18 @@ function claudeContinuationKey(homePath) {
|
|
|
19822
19819
|
function resolveClaudeConfigDirPath(homePath, environment, cwd) {
|
|
19823
19820
|
const trimmed = homePath.trim();
|
|
19824
19821
|
if (trimmed.length > 0) {
|
|
19825
|
-
return
|
|
19822
|
+
return NodePath3.resolve(expandHomePath(trimmed));
|
|
19826
19823
|
}
|
|
19827
19824
|
const environmentConfigDir = environment.CLAUDE_CONFIG_DIR?.trim() ?? "";
|
|
19828
19825
|
if (environmentConfigDir.length > 0) {
|
|
19829
|
-
return cwd ?
|
|
19826
|
+
return cwd ? NodePath3.resolve(cwd, environmentConfigDir) : NodePath3.resolve(environmentConfigDir);
|
|
19830
19827
|
}
|
|
19831
|
-
return
|
|
19828
|
+
return NodePath3.join(NodeOS3.homedir(), ".claude");
|
|
19832
19829
|
}
|
|
19833
19830
|
function resolveClaudeCredentialsDirPath(credentialsPath) {
|
|
19834
19831
|
const trimmed = credentialsPath.trim();
|
|
19835
19832
|
if (trimmed.length === 0) return null;
|
|
19836
|
-
return
|
|
19833
|
+
return NodePath3.resolve(expandHomePath(trimmed));
|
|
19837
19834
|
}
|
|
19838
19835
|
function resolveClaudeHomeLayout(input) {
|
|
19839
19836
|
return {
|
|
@@ -19864,13 +19861,13 @@ function claudeSignedOutMessage(input) {
|
|
|
19864
19861
|
const configDir = input.configDir?.trim() ?? "";
|
|
19865
19862
|
if (configDir.length > 0) {
|
|
19866
19863
|
variables.push(
|
|
19867
|
-
`CLAUDE_CONFIG_DIR set to ${quoteLiteral(
|
|
19864
|
+
`CLAUDE_CONFIG_DIR set to ${quoteLiteral(NodePath3.resolve(input.cwd, configDir))}`
|
|
19868
19865
|
);
|
|
19869
19866
|
}
|
|
19870
19867
|
const credentialsDir = input.credentialsDir?.trim() ?? "";
|
|
19871
19868
|
if (credentialsDir.length > 0) {
|
|
19872
19869
|
variables.push(
|
|
19873
|
-
`${CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE} set to ${quoteLiteral(
|
|
19870
|
+
`${CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE} set to ${quoteLiteral(NodePath3.resolve(input.cwd, credentialsDir))}`
|
|
19874
19871
|
);
|
|
19875
19872
|
}
|
|
19876
19873
|
const withVariables = variables.length > 0 ? `, with ${variables.join(" and ")}` : "";
|
|
@@ -19884,34 +19881,37 @@ function claudeFailureHint(input) {
|
|
|
19884
19881
|
cwd: input.cwd
|
|
19885
19882
|
});
|
|
19886
19883
|
}
|
|
19884
|
+
const limit = input.usageLimit;
|
|
19885
|
+
if (limit !== void 0 && (limit.rejected.size > 0 || limit.latestAssistantRateLimited)) {
|
|
19886
|
+
return describeUsageLimitFailure(limit.rejected, limit.nowMs);
|
|
19887
|
+
}
|
|
19887
19888
|
return void 0;
|
|
19888
19889
|
}
|
|
19889
19890
|
|
|
19890
|
-
// src/claudeSignIn.ts
|
|
19891
|
-
var POSIX_BARE_VALUE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
19892
|
-
function quotePosixShellValue(value) {
|
|
19893
|
-
if (POSIX_BARE_VALUE.test(value)) return value;
|
|
19894
|
-
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
19895
|
-
}
|
|
19896
|
-
function quotePowerShellValue(value) {
|
|
19897
|
-
return `'${value.replaceAll("'", "''")}'`;
|
|
19898
|
-
}
|
|
19899
|
-
function withClaudeCredentialsDir(input) {
|
|
19900
|
-
const variable = CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE;
|
|
19901
|
-
return input.platform === "win32" ? `$env:${variable}=${quotePowerShellValue(input.credentialsDirPath)}; ${input.command}` : `${variable}=${quotePosixShellValue(input.credentialsDirPath)} ${input.command}`;
|
|
19902
|
-
}
|
|
19903
|
-
function claudeSignInCommand(credentialsPath, platform) {
|
|
19904
|
-
const command = "claude auth login";
|
|
19905
|
-
const credentialsDirPath = resolveClaudeCredentialsDirPath(credentialsPath);
|
|
19906
|
-
if (credentialsDirPath === null) return command;
|
|
19907
|
-
return withClaudeCredentialsDir({ command, credentialsDirPath, platform });
|
|
19908
|
-
}
|
|
19909
|
-
|
|
19910
19891
|
// src/claudeSkills.ts
|
|
19911
19892
|
import * as NodeFSP from "node:fs/promises";
|
|
19912
|
-
import * as
|
|
19913
|
-
|
|
19893
|
+
import * as NodePath4 from "node:path";
|
|
19894
|
+
import * as NodeProcess from "node:process";
|
|
19895
|
+
var FRONT_MATTER_KEY = /^(description|disable-model-invocation|user-invocable|argument-hint):[ \t]*(.*)$/;
|
|
19914
19896
|
var BLOCK_SCALAR = /^[|>][+-]?$/;
|
|
19897
|
+
function parseFrontMatterBoolean(value) {
|
|
19898
|
+
switch (value?.trim().toLowerCase()) {
|
|
19899
|
+
case "true":
|
|
19900
|
+
case "yes":
|
|
19901
|
+
case "on":
|
|
19902
|
+
case "y":
|
|
19903
|
+
case "1":
|
|
19904
|
+
return true;
|
|
19905
|
+
case "false":
|
|
19906
|
+
case "no":
|
|
19907
|
+
case "off":
|
|
19908
|
+
case "n":
|
|
19909
|
+
case "0":
|
|
19910
|
+
return false;
|
|
19911
|
+
default:
|
|
19912
|
+
return void 0;
|
|
19913
|
+
}
|
|
19914
|
+
}
|
|
19915
19915
|
function parseSkillFrontMatter(contents) {
|
|
19916
19916
|
const lines = contents.split(/\r?\n/);
|
|
19917
19917
|
if (lines[0]?.trim() !== "---") return {};
|
|
@@ -19933,149 +19933,852 @@ function parseSkillFrontMatter(contents) {
|
|
|
19933
19933
|
}
|
|
19934
19934
|
value = block.join(value.startsWith("|") ? "\n" : " ");
|
|
19935
19935
|
} else {
|
|
19936
|
+
if (key !== "description" && key !== "argument-hint") value = value.replace(/\s+#.*$/, "");
|
|
19936
19937
|
value = value.replace(/^(["'])(.*)\1$/, "$2").trim();
|
|
19937
19938
|
}
|
|
19938
19939
|
if (value.length > 0 && values[key] === void 0) values[key] = value;
|
|
19939
19940
|
}
|
|
19940
|
-
|
|
19941
|
+
const description = values["description"];
|
|
19942
|
+
const argumentHint = values["argument-hint"];
|
|
19943
|
+
return {
|
|
19944
|
+
...description === void 0 ? {} : { description },
|
|
19945
|
+
...argumentHint === void 0 ? {} : { argumentHint },
|
|
19946
|
+
...parseFrontMatterBoolean(values["disable-model-invocation"]) === true ? { userInvocationOnly: true } : {},
|
|
19947
|
+
...parseFrontMatterBoolean(values["user-invocable"]) === false ? { userInvocable: false } : {}
|
|
19948
|
+
};
|
|
19941
19949
|
}
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
const skills = /* @__PURE__ */ new Map();
|
|
19946
|
-
for (const entry of entries.toSorted()) {
|
|
19947
|
-
const skillPath = NodePath5.join(root, entry, "SKILL.md");
|
|
19948
|
-
const contents = await NodeFSP.readFile(skillPath, "utf8").catch(() => void 0);
|
|
19949
|
-
if (contents === void 0) continue;
|
|
19950
|
-
const frontMatter = parseSkillFrontMatter(contents);
|
|
19951
|
-
const name = frontMatter.name ?? entry.trim();
|
|
19952
|
-
if (name.length === 0) continue;
|
|
19953
|
-
skills.set(name, {
|
|
19954
|
-
name,
|
|
19955
|
-
path: skillPath,
|
|
19956
|
-
enabled: true,
|
|
19957
|
-
scope: "user",
|
|
19958
|
-
...frontMatter.description === void 0 ? {} : { description: frontMatter.description }
|
|
19959
|
-
});
|
|
19950
|
+
function claudeManagedSettingsPath(platform2, environment) {
|
|
19951
|
+
if (platform2 === "darwin") {
|
|
19952
|
+
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
19960
19953
|
}
|
|
19961
|
-
|
|
19954
|
+
if (platform2 === "win32") {
|
|
19955
|
+
const programData = environment["PROGRAMDATA"]?.trim();
|
|
19956
|
+
return programData ? NodePath4.join(programData, "ClaudeCode", "managed-settings.json") : void 0;
|
|
19957
|
+
}
|
|
19958
|
+
return "/etc/claude-code/managed-settings.json";
|
|
19962
19959
|
}
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
|
|
19967
|
-
|
|
19960
|
+
function skillOverrideSettingsPaths(configDirPath, cwd, platform2, environment, repositoryRoot) {
|
|
19961
|
+
const managedPath = claudeManagedSettingsPath(platform2, environment);
|
|
19962
|
+
const root = repositoryRoot !== void 0 && repositoryRoot !== cwd ? repositoryRoot : void 0;
|
|
19963
|
+
return [
|
|
19964
|
+
NodePath4.join(configDirPath, "settings.json"),
|
|
19965
|
+
...cwd ? [
|
|
19966
|
+
NodePath4.join(cwd, ".claude", "settings.json"),
|
|
19967
|
+
NodePath4.join(cwd, ".claude", "settings.local.json")
|
|
19968
|
+
] : [],
|
|
19969
|
+
...root ? [NodePath4.join(root, ".claude", "settings.local.json")] : [],
|
|
19970
|
+
...managedPath ? [managedPath] : []
|
|
19971
|
+
];
|
|
19968
19972
|
}
|
|
19969
|
-
function
|
|
19970
|
-
|
|
19973
|
+
async function findRepositoryRoot(cwd) {
|
|
19974
|
+
let current = NodePath4.resolve(cwd);
|
|
19975
|
+
for (; ; ) {
|
|
19976
|
+
const found = await NodeFSP.stat(NodePath4.join(current, ".git")).then(
|
|
19977
|
+
() => true,
|
|
19978
|
+
() => false
|
|
19979
|
+
);
|
|
19980
|
+
if (found) return current;
|
|
19981
|
+
const parent = NodePath4.dirname(current);
|
|
19982
|
+
if (parent === current) return void 0;
|
|
19983
|
+
current = parent;
|
|
19984
|
+
}
|
|
19985
|
+
}
|
|
19986
|
+
function parseLenientJson(text) {
|
|
19987
|
+
let output = "";
|
|
19988
|
+
let index = 0;
|
|
19989
|
+
while (index < text.length) {
|
|
19990
|
+
const char = text[index];
|
|
19991
|
+
const next = text[index + 1];
|
|
19992
|
+
if (char === '"') {
|
|
19993
|
+
let end = index + 1;
|
|
19994
|
+
while (end < text.length && text[end] !== '"') end += text[end] === "\\" ? 2 : 1;
|
|
19995
|
+
output += text.slice(index, end + 1);
|
|
19996
|
+
index = end + 1;
|
|
19997
|
+
} else if (char === "/" && next === "/") {
|
|
19998
|
+
while (index < text.length && text[index] !== "\n") index += 1;
|
|
19999
|
+
} else if (char === "/" && next === "*") {
|
|
20000
|
+
const end = text.indexOf("*/", index + 2);
|
|
20001
|
+
index = end === -1 ? text.length : end + 2;
|
|
20002
|
+
} else {
|
|
20003
|
+
output += char;
|
|
20004
|
+
index += 1;
|
|
20005
|
+
}
|
|
20006
|
+
}
|
|
20007
|
+
return JSON.parse(output.replace(/,(\s*[}\]])/g, "$1"));
|
|
19971
20008
|
}
|
|
19972
|
-
|
|
19973
|
-
|
|
20009
|
+
var SKILL_OVERRIDE_BY_VALUE = {
|
|
20010
|
+
off: { enabled: false, userInvocationOnly: false },
|
|
20011
|
+
// 与 `disable-model-invocation` 一样对 agent 隐藏,所以与普通开关分开记。
|
|
20012
|
+
"user-invocable-only": { enabled: true, userInvocationOnly: true },
|
|
20013
|
+
on: { enabled: true, userInvocationOnly: false },
|
|
20014
|
+
"name-only": { enabled: true, userInvocationOnly: false }
|
|
20015
|
+
};
|
|
20016
|
+
function readOverridesFromSettings(text) {
|
|
20017
|
+
let parsed;
|
|
20018
|
+
try {
|
|
20019
|
+
parsed = parseLenientJson(text);
|
|
20020
|
+
} catch {
|
|
20021
|
+
return void 0;
|
|
20022
|
+
}
|
|
20023
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
20024
|
+
const overrides = parsed["skillOverrides"];
|
|
20025
|
+
if (typeof overrides !== "object" || overrides === null || Array.isArray(overrides)) {
|
|
20026
|
+
return void 0;
|
|
20027
|
+
}
|
|
20028
|
+
const result = /* @__PURE__ */ new Map();
|
|
20029
|
+
for (const [name, value] of Object.entries(overrides)) {
|
|
20030
|
+
const override = typeof value === "string" ? SKILL_OVERRIDE_BY_VALUE[value] : void 0;
|
|
20031
|
+
if (override === void 0) return void 0;
|
|
20032
|
+
result.set(name, override);
|
|
20033
|
+
}
|
|
20034
|
+
return result;
|
|
19974
20035
|
}
|
|
19975
|
-
function
|
|
19976
|
-
|
|
19977
|
-
const
|
|
19978
|
-
for (const
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
20036
|
+
async function readSkillOverrides(configDirPath, cwd, platform2, environment) {
|
|
20037
|
+
const repositoryRoot = cwd === void 0 ? void 0 : await findRepositoryRoot(cwd);
|
|
20038
|
+
const merged = /* @__PURE__ */ new Map();
|
|
20039
|
+
for (const settingsPath of skillOverrideSettingsPaths(
|
|
20040
|
+
configDirPath,
|
|
20041
|
+
cwd,
|
|
20042
|
+
platform2,
|
|
20043
|
+
environment,
|
|
20044
|
+
repositoryRoot
|
|
20045
|
+
)) {
|
|
20046
|
+
const contents = await NodeFSP.readFile(settingsPath, "utf8").catch(() => void 0);
|
|
20047
|
+
if (contents === void 0) continue;
|
|
20048
|
+
for (const [name, override] of readOverridesFromSettings(contents) ?? []) {
|
|
20049
|
+
merged.set(name, override);
|
|
20050
|
+
}
|
|
19983
20051
|
}
|
|
19984
|
-
return
|
|
20052
|
+
return merged;
|
|
19985
20053
|
}
|
|
19986
|
-
function
|
|
19987
|
-
|
|
19988
|
-
const
|
|
19989
|
-
|
|
19990
|
-
|
|
19991
|
-
|
|
19992
|
-
|
|
19993
|
-
|
|
20054
|
+
async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
20055
|
+
const { cwd } = options;
|
|
20056
|
+
const overrides = await readSkillOverrides(
|
|
20057
|
+
configDirPath,
|
|
20058
|
+
cwd,
|
|
20059
|
+
options.platform ?? NodeProcess.platform,
|
|
20060
|
+
options.environment ?? NodeProcess.env
|
|
20061
|
+
);
|
|
20062
|
+
const roots = [
|
|
20063
|
+
{ directory: NodePath4.join(configDirPath, "skills"), scope: "user" },
|
|
20064
|
+
...cwd ? [{ directory: NodePath4.join(cwd, ".claude", "skills"), scope: "project" }] : []
|
|
20065
|
+
];
|
|
20066
|
+
const skills = /* @__PURE__ */ new Map();
|
|
20067
|
+
for (const root of roots) {
|
|
20068
|
+
const entries = await NodeFSP.readdir(root.directory).catch(() => []);
|
|
20069
|
+
for (const entry of entries.toSorted()) {
|
|
20070
|
+
const name = entry.trim();
|
|
20071
|
+
if (name.length === 0 || skills.has(name)) continue;
|
|
20072
|
+
const skillPath = NodePath4.join(root.directory, entry, "SKILL.md");
|
|
20073
|
+
const contents = await NodeFSP.readFile(skillPath, "utf8").catch(() => void 0);
|
|
20074
|
+
if (contents === void 0) continue;
|
|
20075
|
+
const frontMatter = parseSkillFrontMatter(contents);
|
|
20076
|
+
const override = overrides.get(name);
|
|
20077
|
+
const userInvocationOnly = frontMatter.userInvocationOnly === true || override?.userInvocationOnly === true;
|
|
20078
|
+
skills.set(name, {
|
|
20079
|
+
name,
|
|
20080
|
+
path: skillPath,
|
|
20081
|
+
enabled: override?.enabled ?? true,
|
|
20082
|
+
scope: root.scope,
|
|
20083
|
+
...frontMatter.description === void 0 ? {} : { description: frontMatter.description },
|
|
20084
|
+
...userInvocationOnly ? { userInvocationOnly: true } : {},
|
|
20085
|
+
...frontMatter.userInvocable === false ? { userInvocable: false } : {}
|
|
20086
|
+
});
|
|
19994
20087
|
}
|
|
19995
|
-
if (!isRecord2(entry)) continue;
|
|
19996
|
-
const slug = readTrimmed(entry["slug"]);
|
|
19997
|
-
if (slug.length === 0) continue;
|
|
19998
|
-
const thinkingRaw = entry["thinkingOptions"];
|
|
19999
|
-
const thinkingOptions = Array.isArray(thinkingRaw) ? thinkingRaw.flatMap((option) => {
|
|
20000
|
-
if (!isRecord2(option)) return [];
|
|
20001
|
-
const id2 = readTrimmed(option["id"]) || readTrimmed(option["value"]);
|
|
20002
|
-
const label = readTrimmed(option["label"]) || id2;
|
|
20003
|
-
if (id2.length === 0) return [];
|
|
20004
|
-
return [
|
|
20005
|
-
{
|
|
20006
|
-
id: id2,
|
|
20007
|
-
label,
|
|
20008
|
-
...typeof option["description"] === "string" ? { description: option["description"] } : {},
|
|
20009
|
-
...option["isDefault"] === true ? { isDefault: true } : {}
|
|
20010
|
-
}
|
|
20011
|
-
];
|
|
20012
|
-
}) : void 0;
|
|
20013
|
-
const aliasesRaw = entry["aliases"];
|
|
20014
|
-
const aliases = Array.isArray(aliasesRaw) ? aliasesRaw.filter(
|
|
20015
|
-
(alias) => typeof alias === "string" && alias.trim().length > 0
|
|
20016
|
-
) : void 0;
|
|
20017
|
-
const contextWindow = typeof entry["contextWindow"] === "number" && Number.isFinite(entry["contextWindow"]) && entry["contextWindow"] > 0 ? Math.round(entry["contextWindow"]) : void 0;
|
|
20018
|
-
models.push({
|
|
20019
|
-
slug,
|
|
20020
|
-
...readTrimmed(entry["label"]) ? { label: readTrimmed(entry["label"]) } : {},
|
|
20021
|
-
...thinkingOptions && thinkingOptions.length > 0 ? { thinkingOptions } : {},
|
|
20022
|
-
...contextWindow !== void 0 ? { contextWindow } : {},
|
|
20023
|
-
...aliases && aliases.length > 0 ? { aliases } : {}
|
|
20024
|
-
});
|
|
20025
20088
|
}
|
|
20026
|
-
return
|
|
20089
|
+
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
20027
20090
|
}
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20091
|
+
|
|
20092
|
+
// src/model.ts
|
|
20093
|
+
import { matchCatalogModel } from "@ycodium-ai/plugin-api/executor";
|
|
20094
|
+
var DEFAULT_CLAUDE_MODEL_CAPABILITIES = {
|
|
20095
|
+
optionDescriptors: []
|
|
20096
|
+
};
|
|
20097
|
+
var CLAUDE_CUSTOM_MODEL_THINKING_SELECT = {
|
|
20098
|
+
id: "effort",
|
|
20099
|
+
label: "Reasoning"
|
|
20100
|
+
};
|
|
20101
|
+
function parseGenericCliVersion(output) {
|
|
20102
|
+
const match = output.match(/\bv?(\d+\.\d+\.\d+)\b/);
|
|
20103
|
+
return match?.[1] ?? null;
|
|
20031
20104
|
}
|
|
20032
|
-
function
|
|
20033
|
-
|
|
20105
|
+
function normalizeCustomModelSlug(slug) {
|
|
20106
|
+
return slug.trim();
|
|
20107
|
+
}
|
|
20108
|
+
function knownClaudeModelCapabilities(model, catalog, customModels) {
|
|
20109
|
+
const slug = model?.trim();
|
|
20110
|
+
const fromCatalog = catalog.find((candidate) => candidate.slug === slug)?.capabilities;
|
|
20111
|
+
if (fromCatalog) return fromCatalog;
|
|
20112
|
+
const custom = customModels?.find(
|
|
20113
|
+
(candidate) => normalizeCustomModelSlug(candidate.slug) === slug
|
|
20114
|
+
);
|
|
20115
|
+
if (custom?.thinkingOptions !== void 0 && custom.thinkingOptions.length > 0) {
|
|
20116
|
+
const currentValue = custom.thinkingOptions.find((option) => option.isDefault)?.id;
|
|
20034
20117
|
return {
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20038
|
-
|
|
20039
|
-
|
|
20040
|
-
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20118
|
+
optionDescriptors: [
|
|
20119
|
+
{
|
|
20120
|
+
type: "select",
|
|
20121
|
+
id: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.id,
|
|
20122
|
+
label: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.label,
|
|
20123
|
+
options: custom.thinkingOptions,
|
|
20124
|
+
...currentValue !== void 0 ? {} : {}
|
|
20125
|
+
}
|
|
20126
|
+
]
|
|
20044
20127
|
};
|
|
20045
20128
|
}
|
|
20046
|
-
|
|
20047
|
-
const settings = nested ?? config;
|
|
20048
|
-
return {
|
|
20049
|
-
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
20050
|
-
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
|
|
20051
|
-
credentialsPath: readTrimmed(settings["credentialsPath"]) || readTrimmed(config["credentialsPath"]),
|
|
20052
|
-
launchArgs: readString(settings["launchArgs"]),
|
|
20053
|
-
autoCompactWindow: readAutoCompactWindow(settings["autoCompactWindow"]),
|
|
20054
|
-
customModels: readCustomModels(settings["customModels"]),
|
|
20055
|
-
enabled: settings["enabled"] !== false,
|
|
20056
|
-
environment: readEnvironment(config["environment"]),
|
|
20057
|
-
envelopeDriver: readTrimmed(config["driver"]) || void 0
|
|
20058
|
-
};
|
|
20129
|
+
return void 0;
|
|
20059
20130
|
}
|
|
20060
|
-
function
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
|
|
20066
|
-
|
|
20067
|
-
|
|
20068
|
-
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
20072
|
-
|
|
20073
|
-
|
|
20074
|
-
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
|
|
20131
|
+
function claudeModelCapabilities(model, catalog, customModels) {
|
|
20132
|
+
return knownClaudeModelCapabilities(model, catalog, customModels) ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES;
|
|
20133
|
+
}
|
|
20134
|
+
function isRecord2(value) {
|
|
20135
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20136
|
+
}
|
|
20137
|
+
function getModelSelectionStringOptionValue(modelSelection, optionId) {
|
|
20138
|
+
if (!isRecord2(modelSelection)) return void 0;
|
|
20139
|
+
const options = modelSelection["options"];
|
|
20140
|
+
if (!Array.isArray(options)) return void 0;
|
|
20141
|
+
for (const entry of options) {
|
|
20142
|
+
if (!isRecord2(entry)) continue;
|
|
20143
|
+
if (entry["id"] === optionId && typeof entry["value"] === "string") {
|
|
20144
|
+
const trimmed = entry["value"].trim();
|
|
20145
|
+
if (trimmed.length > 0) return trimmed;
|
|
20146
|
+
}
|
|
20147
|
+
}
|
|
20148
|
+
return void 0;
|
|
20149
|
+
}
|
|
20150
|
+
function getModelSelectionBooleanOptionValue(modelSelection, optionId) {
|
|
20151
|
+
if (!isRecord2(modelSelection)) return void 0;
|
|
20152
|
+
const options = modelSelection["options"];
|
|
20153
|
+
if (!Array.isArray(options)) return void 0;
|
|
20154
|
+
for (const entry of options) {
|
|
20155
|
+
if (!isRecord2(entry)) continue;
|
|
20156
|
+
if (entry["id"] === optionId && typeof entry["value"] === "boolean") {
|
|
20157
|
+
return entry["value"];
|
|
20158
|
+
}
|
|
20159
|
+
}
|
|
20160
|
+
return void 0;
|
|
20161
|
+
}
|
|
20162
|
+
function modelIdFromSelection(selection) {
|
|
20163
|
+
if (!isRecord2(selection)) return void 0;
|
|
20164
|
+
const model = selection["model"];
|
|
20165
|
+
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
20166
|
+
}
|
|
20167
|
+
function currentSelectValue(descriptor, raw) {
|
|
20168
|
+
if (raw && descriptor.options.some((option) => option.id === raw)) return raw;
|
|
20169
|
+
return descriptor.options.find((option) => option.isDefault)?.id;
|
|
20170
|
+
}
|
|
20171
|
+
function resolveClaudeEffort(caps, raw) {
|
|
20172
|
+
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20173
|
+
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20174
|
+
return currentSelectValue(descriptor, raw);
|
|
20175
|
+
}
|
|
20176
|
+
function normalizeClaudeCliEffort(effort) {
|
|
20177
|
+
if (!effort || effort === "ultrathink") {
|
|
20178
|
+
return void 0;
|
|
20179
|
+
}
|
|
20180
|
+
if (effort === "ultracode") {
|
|
20181
|
+
return "xhigh";
|
|
20182
|
+
}
|
|
20183
|
+
return effort;
|
|
20184
|
+
}
|
|
20185
|
+
function isClaudeUltracodeEffort(effort) {
|
|
20186
|
+
return effort === "ultracode";
|
|
20187
|
+
}
|
|
20188
|
+
function claudeCliModelId(input) {
|
|
20189
|
+
const requested = input.requestedModelId.trim();
|
|
20190
|
+
if (requested.length > 0 && (input.catalog ?? []).length === 0) return requested;
|
|
20191
|
+
const known = [
|
|
20192
|
+
...(input.catalog ?? []).map((model) => model.slug),
|
|
20193
|
+
...input.declared ?? [],
|
|
20194
|
+
...(input.customModels ?? []).map((model) => normalizeCustomModelSlug(model.slug))
|
|
20195
|
+
];
|
|
20196
|
+
return matchCatalogModel(input.requestedModelId, known) ?? input.placeholder;
|
|
20197
|
+
}
|
|
20198
|
+
function resolvePromptInjectedEffort(caps, rawEffort) {
|
|
20199
|
+
const trimmed = rawEffort?.trim();
|
|
20200
|
+
if (!trimmed) return void 0;
|
|
20201
|
+
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20202
|
+
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20203
|
+
if (!descriptor.promptInjectedValues?.includes(trimmed)) return void 0;
|
|
20204
|
+
return trimmed;
|
|
20205
|
+
}
|
|
20206
|
+
function applyClaudePromptEffortPrefix(text, effort) {
|
|
20207
|
+
const trimmed = text.trim();
|
|
20208
|
+
if (!trimmed) {
|
|
20209
|
+
return trimmed;
|
|
20210
|
+
}
|
|
20211
|
+
if (effort !== "ultrathink" || /^\/[^\s/]+(?:\s|$)/u.test(trimmed)) {
|
|
20212
|
+
return trimmed;
|
|
20213
|
+
}
|
|
20214
|
+
if (trimmed.startsWith("Ultrathink:")) {
|
|
20215
|
+
return trimmed;
|
|
20216
|
+
}
|
|
20217
|
+
return `Ultrathink:
|
|
20218
|
+
${trimmed}`;
|
|
20219
|
+
}
|
|
20220
|
+
function getEffectiveClaudeAgentEffort(effort) {
|
|
20221
|
+
const normalized = normalizeClaudeCliEffort(effort);
|
|
20222
|
+
return normalized ? normalized : null;
|
|
20223
|
+
}
|
|
20224
|
+
|
|
20225
|
+
// src/probeModels.ts
|
|
20226
|
+
var toProbeCapabilities = (caps) => ({
|
|
20227
|
+
optionDescriptors: caps.optionDescriptors.map(
|
|
20228
|
+
(descriptor) => descriptor.type === "select" ? {
|
|
20229
|
+
id: descriptor.id,
|
|
20230
|
+
label: descriptor.label,
|
|
20231
|
+
type: "select",
|
|
20232
|
+
options: descriptor.options.map((option) => ({
|
|
20233
|
+
id: option.id,
|
|
20234
|
+
label: option.label,
|
|
20235
|
+
...option.description === void 0 ? {} : { description: option.description },
|
|
20236
|
+
...option.isDefault === void 0 ? {} : { isDefault: option.isDefault }
|
|
20237
|
+
}))
|
|
20238
|
+
} : {
|
|
20239
|
+
id: descriptor.id,
|
|
20240
|
+
label: descriptor.label,
|
|
20241
|
+
type: "boolean"
|
|
20242
|
+
}
|
|
20243
|
+
)
|
|
20244
|
+
});
|
|
20245
|
+
var claudeProbeModels = (input) => {
|
|
20246
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20247
|
+
const out = [];
|
|
20248
|
+
for (const model of input.catalog) {
|
|
20249
|
+
if (seen.has(model.slug)) continue;
|
|
20250
|
+
seen.add(model.slug);
|
|
20251
|
+
const userLabel = input.customModels.find((entry) => entry.slug === model.slug)?.label;
|
|
20252
|
+
out.push({
|
|
20253
|
+
slug: model.slug,
|
|
20254
|
+
name: userLabel?.trim() || model.name,
|
|
20255
|
+
capabilities: toProbeCapabilities(model.capabilities)
|
|
20256
|
+
});
|
|
20257
|
+
}
|
|
20258
|
+
for (const model of input.customModels) {
|
|
20259
|
+
if (model.slug.trim().length === 0 || seen.has(model.slug)) continue;
|
|
20260
|
+
seen.add(model.slug);
|
|
20261
|
+
out.push({ slug: model.slug, name: model.label?.trim() || model.slug });
|
|
20262
|
+
}
|
|
20263
|
+
return out;
|
|
20264
|
+
};
|
|
20265
|
+
|
|
20266
|
+
// src/sessionSettings.ts
|
|
20267
|
+
function toSessionPermissionUpdates(toolName, suggestions) {
|
|
20268
|
+
const sessionScoped = (suggestions ?? []).map(
|
|
20269
|
+
(suggestion) => ({ ...suggestion, destination: "session" })
|
|
20270
|
+
);
|
|
20271
|
+
if (sessionScoped.length > 0) {
|
|
20272
|
+
return sessionScoped;
|
|
20273
|
+
}
|
|
20274
|
+
return [
|
|
20275
|
+
{
|
|
20276
|
+
type: "addRules",
|
|
20277
|
+
rules: [{ toolName }],
|
|
20278
|
+
behavior: "allow",
|
|
20279
|
+
destination: "session"
|
|
20280
|
+
}
|
|
20281
|
+
];
|
|
20282
|
+
}
|
|
20283
|
+
var CLAUDE_SESSION_SETTING_KEYS = [
|
|
20284
|
+
"alwaysThinkingEnabled",
|
|
20285
|
+
"fastMode",
|
|
20286
|
+
"ultracode",
|
|
20287
|
+
"autoCompactWindow"
|
|
20288
|
+
];
|
|
20289
|
+
function buildClaudeSessionSettings(input) {
|
|
20290
|
+
return {
|
|
20291
|
+
...typeof input.thinking === "boolean" ? { alwaysThinkingEnabled: input.thinking } : {},
|
|
20292
|
+
...input.fastMode ? { fastMode: true } : {},
|
|
20293
|
+
...input.ultracode ? { ultracode: true } : {},
|
|
20294
|
+
...input.autoCompactWindow ? { autoCompactWindow: Number(input.autoCompactWindow) } : {}
|
|
20295
|
+
};
|
|
20296
|
+
}
|
|
20297
|
+
function diffClaudeSessionSettings(previous, next) {
|
|
20298
|
+
const patch = {};
|
|
20299
|
+
let changed = false;
|
|
20300
|
+
const track = (key) => {
|
|
20301
|
+
if (previous[key] === next[key]) {
|
|
20302
|
+
return;
|
|
20303
|
+
}
|
|
20304
|
+
changed = true;
|
|
20305
|
+
patch[key] = next[key] ?? null;
|
|
20306
|
+
};
|
|
20307
|
+
for (const key of CLAUDE_SESSION_SETTING_KEYS) {
|
|
20308
|
+
track(key);
|
|
20309
|
+
}
|
|
20310
|
+
return changed ? patch : void 0;
|
|
20311
|
+
}
|
|
20312
|
+
var CLAUDE_NATIVE_MODES = [
|
|
20313
|
+
{ id: "default", name: "Manual", description: "Always ask before making changes" },
|
|
20314
|
+
{ id: "acceptEdits", name: "Accept edits", description: "Automatically accept all file edits" },
|
|
20315
|
+
{ id: "plan", name: "Plan", description: "Create a plan before making changes" },
|
|
20316
|
+
{ id: "auto", name: "Auto", description: "Claude handles permission decisions" },
|
|
20317
|
+
{
|
|
20318
|
+
id: "bypassPermissions",
|
|
20319
|
+
name: "Bypass permissions",
|
|
20320
|
+
description: "Accepts all permissions"
|
|
20321
|
+
}
|
|
20322
|
+
];
|
|
20323
|
+
var CLAUDE_DEFAULT_NATIVE_MODE_ID = "default";
|
|
20324
|
+
var CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE = {
|
|
20325
|
+
"approval-required": "default",
|
|
20326
|
+
"auto-accept-edits": "acceptEdits",
|
|
20327
|
+
auto: "auto",
|
|
20328
|
+
"full-access": "bypassPermissions"
|
|
20329
|
+
};
|
|
20330
|
+
var CLAUDE_NATIVE_MODE_REPORT = {
|
|
20331
|
+
nativeModes: CLAUDE_NATIVE_MODES.map((mode) => ({
|
|
20332
|
+
id: mode.id,
|
|
20333
|
+
name: mode.name,
|
|
20334
|
+
description: mode.description
|
|
20335
|
+
})),
|
|
20336
|
+
currentNativeModeId: CLAUDE_DEFAULT_NATIVE_MODE_ID,
|
|
20337
|
+
nativeModeByRuntimeMode: CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE
|
|
20338
|
+
};
|
|
20339
|
+
function isClaudeNativeModeId(value) {
|
|
20340
|
+
return CLAUDE_NATIVE_MODES.some((mode) => mode.id === value);
|
|
20341
|
+
}
|
|
20342
|
+
function claudePermissionModeFor(runtimeMode, nativeModeId) {
|
|
20343
|
+
if (nativeModeId !== void 0 && isClaudeNativeModeId(nativeModeId)) return nativeModeId;
|
|
20344
|
+
return CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE[runtimeMode];
|
|
20345
|
+
}
|
|
20346
|
+
var CLAUDE_SETTING_SOURCES = [
|
|
20347
|
+
"user",
|
|
20348
|
+
"project",
|
|
20349
|
+
"local"
|
|
20350
|
+
];
|
|
20351
|
+
|
|
20352
|
+
// src/claudeProbe.ts
|
|
20353
|
+
var CLAUDE_PROGRAM_NOT_CONFIGURED = "Claude program path is not configured";
|
|
20354
|
+
function createClaudeProbe(input) {
|
|
20355
|
+
const { recipe, host, modelCatalog } = input;
|
|
20356
|
+
const collectProcessText = async (stream) => {
|
|
20357
|
+
const chunks = [];
|
|
20358
|
+
for await (const chunk of stream) {
|
|
20359
|
+
chunks.push(Buffer.from(chunk));
|
|
20360
|
+
}
|
|
20361
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
20362
|
+
};
|
|
20363
|
+
const probeAuth = () => {
|
|
20364
|
+
const hasEnvToken = (recipe.environment.ANTHROPIC_AUTH_TOKEN ?? "").trim().length > 0;
|
|
20365
|
+
const hasEnvApiKey = (recipe.environment.ANTHROPIC_API_KEY ?? "").trim().length > 0;
|
|
20366
|
+
if (hasEnvToken || hasEnvApiKey) {
|
|
20367
|
+
return {
|
|
20368
|
+
status: "authenticated",
|
|
20369
|
+
type: hasEnvToken ? "env-token" : "api-key",
|
|
20370
|
+
label: hasEnvToken ? "ANTHROPIC_AUTH_TOKEN" : "ANTHROPIC_API_KEY"
|
|
20371
|
+
};
|
|
20372
|
+
}
|
|
20373
|
+
const account = readClaudeAccount(resolveClaudeCredentialsDirPath(recipe.credentialsPath));
|
|
20374
|
+
switch (account.state) {
|
|
20375
|
+
case "signed-in":
|
|
20376
|
+
case "expired":
|
|
20377
|
+
return { status: "authenticated" };
|
|
20378
|
+
case "signed-out":
|
|
20379
|
+
return { status: "unauthenticated" };
|
|
20380
|
+
case "unreadable":
|
|
20381
|
+
return { status: "unknown" };
|
|
20382
|
+
}
|
|
20383
|
+
};
|
|
20384
|
+
let lastProbedVersion;
|
|
20385
|
+
const probe = async (signal) => {
|
|
20386
|
+
if (recipe.binaryPath.length === 0) {
|
|
20387
|
+
return {
|
|
20388
|
+
installed: false,
|
|
20389
|
+
version: null,
|
|
20390
|
+
readiness: "not-installed",
|
|
20391
|
+
auth: { status: "unknown" },
|
|
20392
|
+
detail: CLAUDE_PROGRAM_NOT_CONFIGURED
|
|
20393
|
+
};
|
|
20394
|
+
}
|
|
20395
|
+
if (signal?.aborted) {
|
|
20396
|
+
throw new Error("aborted");
|
|
20397
|
+
}
|
|
20398
|
+
let handle;
|
|
20399
|
+
try {
|
|
20400
|
+
handle = await host.process.spawn({
|
|
20401
|
+
program: recipe.binaryPath,
|
|
20402
|
+
args: ["--version"],
|
|
20403
|
+
owner: { bindingId: host.bindingId }
|
|
20404
|
+
});
|
|
20405
|
+
} catch (error) {
|
|
20406
|
+
if (error instanceof ExecutorSpawnRefusedError) throw error;
|
|
20407
|
+
const failure = describeExecutorSpawnFailure(error);
|
|
20408
|
+
return {
|
|
20409
|
+
installed: false,
|
|
20410
|
+
version: null,
|
|
20411
|
+
readiness: failure.readiness,
|
|
20412
|
+
auth: { status: "unknown" },
|
|
20413
|
+
detail: failure.detail
|
|
20414
|
+
};
|
|
20415
|
+
}
|
|
20416
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
20417
|
+
collectProcessText(handle.stdout),
|
|
20418
|
+
collectProcessText(handle.stderr),
|
|
20419
|
+
handle.exited
|
|
20420
|
+
]);
|
|
20421
|
+
const version = parseGenericCliVersion(`${stdout}
|
|
20422
|
+
${stderr}`);
|
|
20423
|
+
if (version !== null || exitCode === 0) {
|
|
20424
|
+
await modelCatalog.refresh({ signal, force: version !== lastProbedVersion });
|
|
20425
|
+
lastProbedVersion = version;
|
|
20426
|
+
}
|
|
20427
|
+
const models = claudeProbeModels({
|
|
20428
|
+
catalog: modelCatalog.current(),
|
|
20429
|
+
customModels: recipe.customModels
|
|
20430
|
+
});
|
|
20431
|
+
const auth = probeAuth();
|
|
20432
|
+
const skills = await discoverClaudeSkills(
|
|
20433
|
+
resolveClaudeConfigDirPath(recipe.homePath, { ...process.env, ...recipe.environment })
|
|
20434
|
+
);
|
|
20435
|
+
if (exitCode !== 0 && version === null) {
|
|
20436
|
+
const detail = (stderr || stdout || "claude --version failed").trim();
|
|
20437
|
+
return {
|
|
20438
|
+
installed: false,
|
|
20439
|
+
version: null,
|
|
20440
|
+
readiness: "error",
|
|
20441
|
+
auth,
|
|
20442
|
+
...detail.length > 0 ? { detail } : {}
|
|
20443
|
+
};
|
|
20444
|
+
}
|
|
20445
|
+
if (auth.status === "unauthenticated") {
|
|
20446
|
+
return {
|
|
20447
|
+
installed: true,
|
|
20448
|
+
version,
|
|
20449
|
+
readiness: "error",
|
|
20450
|
+
auth,
|
|
20451
|
+
models,
|
|
20452
|
+
skills,
|
|
20453
|
+
detail: "Claude is signed out",
|
|
20454
|
+
// 退出登录了档位照样是那五档。不报就退回宿主四档,而那份映射少了 `plan`。
|
|
20455
|
+
...CLAUDE_NATIVE_MODE_REPORT
|
|
20456
|
+
};
|
|
20457
|
+
}
|
|
20458
|
+
return {
|
|
20459
|
+
installed: true,
|
|
20460
|
+
version,
|
|
20461
|
+
readiness: "ready",
|
|
20462
|
+
auth,
|
|
20463
|
+
models,
|
|
20464
|
+
skills,
|
|
20465
|
+
...CLAUDE_NATIVE_MODE_REPORT
|
|
20466
|
+
};
|
|
20467
|
+
};
|
|
20468
|
+
return probe;
|
|
20469
|
+
}
|
|
20470
|
+
|
|
20471
|
+
// src/claudeExecutable.ts
|
|
20472
|
+
import * as NodeFS2 from "node:fs";
|
|
20473
|
+
import * as NodeOS4 from "node:os";
|
|
20474
|
+
import * as NodePath5 from "node:path";
|
|
20475
|
+
var WINDOWS_SHIM_EXTENSIONS = /* @__PURE__ */ new Set([".cmd", ".bat", ".ps1"]);
|
|
20476
|
+
var NPM_PACKAGE_ENTRY_CANDIDATES = [
|
|
20477
|
+
["node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe"],
|
|
20478
|
+
["node_modules", "@anthropic-ai", "claude-code", "cli.js"]
|
|
20479
|
+
];
|
|
20480
|
+
function isExistingFile(filePath) {
|
|
20481
|
+
try {
|
|
20482
|
+
return NodeFS2.statSync(filePath).isFile();
|
|
20483
|
+
} catch {
|
|
20484
|
+
return false;
|
|
20485
|
+
}
|
|
20486
|
+
}
|
|
20487
|
+
function resolveClaudeSdkExecutablePath(binaryPath, environment = process.env, isFile = isExistingFile, isWindows = NodeOS4.type() === "Windows_NT") {
|
|
20488
|
+
if (!isWindows) {
|
|
20489
|
+
return binaryPath;
|
|
20490
|
+
}
|
|
20491
|
+
const resolved = resolveWindowsExecutable(binaryPath, environment) ?? binaryPath;
|
|
20492
|
+
const extension = NodePath5.win32.extname(resolved).toLowerCase();
|
|
20493
|
+
if (!WINDOWS_SHIM_EXTENSIONS.has(extension)) {
|
|
20494
|
+
return resolved;
|
|
20495
|
+
}
|
|
20496
|
+
const shimDirectory = NodePath5.win32.dirname(resolved);
|
|
20497
|
+
for (const entrySegments of NPM_PACKAGE_ENTRY_CANDIDATES) {
|
|
20498
|
+
const candidate = NodePath5.win32.join(shimDirectory, ...entrySegments);
|
|
20499
|
+
if (isFile(candidate)) {
|
|
20500
|
+
return candidate;
|
|
20501
|
+
}
|
|
20502
|
+
}
|
|
20503
|
+
return binaryPath;
|
|
20504
|
+
}
|
|
20505
|
+
function resolveWindowsExecutable(binaryPath, environment) {
|
|
20506
|
+
const trimmed = binaryPath.trim();
|
|
20507
|
+
if (trimmed.length === 0) return void 0;
|
|
20508
|
+
if (NodePath5.win32.isAbsolute(trimmed) && isExistingFile(trimmed)) return trimmed;
|
|
20509
|
+
const pathValue = environment.PATH ?? environment.Path ?? "";
|
|
20510
|
+
const pathext = environment.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
20511
|
+
const extensions = pathext.split(";").filter((ext) => ext.length > 0);
|
|
20512
|
+
const hasExt = NodePath5.win32.extname(trimmed).length > 0;
|
|
20513
|
+
for (const dir of pathValue.split(";")) {
|
|
20514
|
+
if (dir.trim().length === 0) continue;
|
|
20515
|
+
const candidates = hasExt ? [NodePath5.win32.join(dir, trimmed)] : extensions.map((ext) => NodePath5.win32.join(dir, `${trimmed}${ext}`));
|
|
20516
|
+
for (const candidate of candidates) {
|
|
20517
|
+
if (isExistingFile(candidate)) return candidate;
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
20520
|
+
return void 0;
|
|
20521
|
+
}
|
|
20522
|
+
|
|
20523
|
+
// src/claudeSignIn.ts
|
|
20524
|
+
var POSIX_BARE_VALUE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
20525
|
+
function quotePosixShellValue(value) {
|
|
20526
|
+
if (POSIX_BARE_VALUE.test(value)) return value;
|
|
20527
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
20528
|
+
}
|
|
20529
|
+
function quotePowerShellValue(value) {
|
|
20530
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
20531
|
+
}
|
|
20532
|
+
function withClaudeCredentialsDir(input) {
|
|
20533
|
+
const variable = CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE;
|
|
20534
|
+
return input.platform === "win32" ? `$env:${variable}=${quotePowerShellValue(input.credentialsDirPath)}; ${input.command}` : `${variable}=${quotePosixShellValue(input.credentialsDirPath)} ${input.command}`;
|
|
20535
|
+
}
|
|
20536
|
+
function claudeSignInCommand(credentialsPath, platform2) {
|
|
20537
|
+
const command = "claude auth login";
|
|
20538
|
+
const credentialsDirPath = resolveClaudeCredentialsDirPath(credentialsPath);
|
|
20539
|
+
if (credentialsDirPath === null) return command;
|
|
20540
|
+
return withClaudeCredentialsDir({ command, credentialsDirPath, platform: platform2 });
|
|
20541
|
+
}
|
|
20542
|
+
|
|
20543
|
+
// src/claudeWorkspaceInventory.ts
|
|
20544
|
+
import * as NodeFSP2 from "node:fs/promises";
|
|
20545
|
+
import * as NodePath6 from "node:path";
|
|
20546
|
+
var MAX_COMMAND_DEPTH = 5;
|
|
20547
|
+
var MAX_COMMAND_FILES = 500;
|
|
20548
|
+
var MAX_DESCRIPTION_LENGTH = 200;
|
|
20549
|
+
var firstBodyLine = (contents) => {
|
|
20550
|
+
const lines = contents.split(/\r?\n/);
|
|
20551
|
+
let index = 0;
|
|
20552
|
+
if (lines[0]?.trim() === "---") {
|
|
20553
|
+
const close = lines.findIndex((line, position) => position > 0 && line.trim() === "---");
|
|
20554
|
+
index = close === -1 ? lines.length : close + 1;
|
|
20555
|
+
}
|
|
20556
|
+
for (; index < lines.length; index += 1) {
|
|
20557
|
+
const line = (lines[index] ?? "").trim().replace(/^#+\s*/, "");
|
|
20558
|
+
if (line.length > 0) return line.slice(0, MAX_DESCRIPTION_LENGTH);
|
|
20559
|
+
}
|
|
20560
|
+
return void 0;
|
|
20561
|
+
};
|
|
20562
|
+
var scanCommands = async (claudeDir) => {
|
|
20563
|
+
const root = NodePath6.join(claudeDir, "commands");
|
|
20564
|
+
const commands = /* @__PURE__ */ new Map();
|
|
20565
|
+
const watched = [root];
|
|
20566
|
+
let level = [root];
|
|
20567
|
+
let files = 0;
|
|
20568
|
+
for (let depth = 0; depth < MAX_COMMAND_DEPTH && level.length > 0; depth += 1) {
|
|
20569
|
+
const next = [];
|
|
20570
|
+
for (const directory of level) {
|
|
20571
|
+
const entries = await NodeFSP2.readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
20572
|
+
for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
|
|
20573
|
+
const entryPath = NodePath6.join(directory, entry.name);
|
|
20574
|
+
if (entry.isDirectory()) {
|
|
20575
|
+
next.push(entryPath);
|
|
20576
|
+
watched.push(entryPath);
|
|
20577
|
+
continue;
|
|
20578
|
+
}
|
|
20579
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md")) continue;
|
|
20580
|
+
watched.push(entryPath);
|
|
20581
|
+
if (files >= MAX_COMMAND_FILES) continue;
|
|
20582
|
+
files += 1;
|
|
20583
|
+
const name = entry.name.slice(0, -".md".length).trim();
|
|
20584
|
+
if (name.length === 0 || commands.has(name)) continue;
|
|
20585
|
+
const contents = await NodeFSP2.readFile(entryPath, "utf8").catch(() => void 0);
|
|
20586
|
+
if (contents === void 0) continue;
|
|
20587
|
+
const frontMatter = parseSkillFrontMatter(contents);
|
|
20588
|
+
const description = frontMatter.description ?? firstBodyLine(contents);
|
|
20589
|
+
commands.set(name, {
|
|
20590
|
+
name,
|
|
20591
|
+
...description === void 0 ? {} : { description },
|
|
20592
|
+
...frontMatter.argumentHint === void 0 ? {} : { input: { hint: frontMatter.argumentHint } }
|
|
20593
|
+
});
|
|
20594
|
+
}
|
|
20595
|
+
}
|
|
20596
|
+
level = next;
|
|
20597
|
+
}
|
|
20598
|
+
return { commands: [...commands.values()], watched };
|
|
20599
|
+
};
|
|
20600
|
+
var watchSkillsRoot = async (claudeDir) => {
|
|
20601
|
+
const root = NodePath6.join(claudeDir, "skills");
|
|
20602
|
+
const entries = await NodeFSP2.readdir(root).catch(() => []);
|
|
20603
|
+
return [
|
|
20604
|
+
root,
|
|
20605
|
+
...entries.flatMap((entry) => [
|
|
20606
|
+
NodePath6.join(root, entry),
|
|
20607
|
+
NodePath6.join(root, entry, "SKILL.md")
|
|
20608
|
+
])
|
|
20609
|
+
];
|
|
20610
|
+
};
|
|
20611
|
+
var mergeByName = (base, preferred) => {
|
|
20612
|
+
const merged = /* @__PURE__ */ new Map();
|
|
20613
|
+
for (const entry of base) merged.set(entry.name, entry);
|
|
20614
|
+
for (const entry of preferred) merged.set(entry.name, entry);
|
|
20615
|
+
return [...merged.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
20616
|
+
};
|
|
20617
|
+
var discoverClaudeWorkspaceInventory = async (input) => {
|
|
20618
|
+
const projectClaudeDir = NodePath6.join(input.cwd, ".claude");
|
|
20619
|
+
const [userCommands, projectCommands, skills, userSkillWatch, projectSkillWatch] = await Promise.all([
|
|
20620
|
+
scanCommands(input.configDirPath),
|
|
20621
|
+
scanCommands(projectClaudeDir),
|
|
20622
|
+
discoverClaudeSkills(input.configDirPath, {
|
|
20623
|
+
cwd: input.cwd,
|
|
20624
|
+
...input.environment === void 0 ? {} : { environment: input.environment }
|
|
20625
|
+
}),
|
|
20626
|
+
watchSkillsRoot(input.configDirPath),
|
|
20627
|
+
watchSkillsRoot(projectClaudeDir)
|
|
20628
|
+
]);
|
|
20629
|
+
return {
|
|
20630
|
+
slashCommands: mergeByName(userCommands.commands, projectCommands.commands),
|
|
20631
|
+
skills,
|
|
20632
|
+
// 项目目录本身也看:`.claude` 整个是后来才建的,它出现就该重查。
|
|
20633
|
+
watchPaths: [
|
|
20634
|
+
projectClaudeDir,
|
|
20635
|
+
...userCommands.watched,
|
|
20636
|
+
...projectCommands.watched,
|
|
20637
|
+
...userSkillWatch,
|
|
20638
|
+
...projectSkillWatch,
|
|
20639
|
+
// `skillOverrides` 在这几个设置文件里:开关一个技能也要重查。
|
|
20640
|
+
NodePath6.join(input.configDirPath, "settings.json"),
|
|
20641
|
+
NodePath6.join(projectClaudeDir, "settings.json"),
|
|
20642
|
+
NodePath6.join(projectClaudeDir, "settings.local.json")
|
|
20643
|
+
]
|
|
20644
|
+
};
|
|
20645
|
+
};
|
|
20646
|
+
var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
|
|
20647
|
+
var nonEmptyString = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
20648
|
+
var claudeSlashCommandsFromNames = (names) => Array.isArray(names) ? names.flatMap((entry) => {
|
|
20649
|
+
const name = nonEmptyString(entry);
|
|
20650
|
+
return name === void 0 ? [] : [{ name }];
|
|
20651
|
+
}) : [];
|
|
20652
|
+
var claudeSlashCommandsFromSdk = (commands) => Array.isArray(commands) ? commands.flatMap((entry) => {
|
|
20653
|
+
const record = asRecord(entry);
|
|
20654
|
+
const name = nonEmptyString(record?.["name"]);
|
|
20655
|
+
if (name === void 0) return [];
|
|
20656
|
+
const description = nonEmptyString(record?.["description"]);
|
|
20657
|
+
const hint = nonEmptyString(record?.["argumentHint"]);
|
|
20658
|
+
return [
|
|
20659
|
+
{
|
|
20660
|
+
name,
|
|
20661
|
+
...description === void 0 ? {} : { description },
|
|
20662
|
+
...hint === void 0 ? {} : { input: { hint } }
|
|
20663
|
+
}
|
|
20664
|
+
];
|
|
20665
|
+
}) : [];
|
|
20666
|
+
|
|
20667
|
+
// src/config.ts
|
|
20668
|
+
var CLAUDE_AUTO_COMPACT_WINDOW_PATTERN = /^(?:|[1-9]\d{5}|1000000)$/;
|
|
20669
|
+
function isRecord3(value) {
|
|
20670
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20671
|
+
}
|
|
20672
|
+
function readString(value) {
|
|
20673
|
+
return typeof value === "string" ? value : "";
|
|
20674
|
+
}
|
|
20675
|
+
function readTrimmed(value) {
|
|
20676
|
+
return readString(value).trim();
|
|
20677
|
+
}
|
|
20678
|
+
function readEnvironment(value) {
|
|
20679
|
+
if (!Array.isArray(value)) return {};
|
|
20680
|
+
const env2 = {};
|
|
20681
|
+
for (const entry of value) {
|
|
20682
|
+
if (!isRecord3(entry)) continue;
|
|
20683
|
+
const name = readTrimmed(entry["name"]);
|
|
20684
|
+
if (name.length === 0) continue;
|
|
20685
|
+
env2[name] = readString(entry["value"]);
|
|
20686
|
+
}
|
|
20687
|
+
return env2;
|
|
20688
|
+
}
|
|
20689
|
+
function readCustomModels(value) {
|
|
20690
|
+
if (!Array.isArray(value)) return [];
|
|
20691
|
+
const models = [];
|
|
20692
|
+
for (const entry of value) {
|
|
20693
|
+
if (typeof entry === "string") {
|
|
20694
|
+
const slug2 = entry.trim();
|
|
20695
|
+
if (slug2.length > 0) models.push({ slug: slug2 });
|
|
20696
|
+
continue;
|
|
20697
|
+
}
|
|
20698
|
+
if (!isRecord3(entry)) continue;
|
|
20699
|
+
const slug = readTrimmed(entry["slug"]);
|
|
20700
|
+
if (slug.length === 0) continue;
|
|
20701
|
+
const thinkingRaw = entry["thinkingOptions"];
|
|
20702
|
+
const thinkingOptions = Array.isArray(thinkingRaw) ? thinkingRaw.flatMap((option) => {
|
|
20703
|
+
if (!isRecord3(option)) return [];
|
|
20704
|
+
const id2 = readTrimmed(option["id"]) || readTrimmed(option["value"]);
|
|
20705
|
+
const label = readTrimmed(option["label"]) || id2;
|
|
20706
|
+
if (id2.length === 0) return [];
|
|
20707
|
+
return [
|
|
20708
|
+
{
|
|
20709
|
+
id: id2,
|
|
20710
|
+
label,
|
|
20711
|
+
...typeof option["description"] === "string" ? { description: option["description"] } : {},
|
|
20712
|
+
...option["isDefault"] === true ? { isDefault: true } : {}
|
|
20713
|
+
}
|
|
20714
|
+
];
|
|
20715
|
+
}) : void 0;
|
|
20716
|
+
const aliasesRaw = entry["aliases"];
|
|
20717
|
+
const aliases = Array.isArray(aliasesRaw) ? aliasesRaw.filter(
|
|
20718
|
+
(alias) => typeof alias === "string" && alias.trim().length > 0
|
|
20719
|
+
) : void 0;
|
|
20720
|
+
const contextWindow = typeof entry["contextWindow"] === "number" && Number.isFinite(entry["contextWindow"]) && entry["contextWindow"] > 0 ? Math.round(entry["contextWindow"]) : void 0;
|
|
20721
|
+
models.push({
|
|
20722
|
+
slug,
|
|
20723
|
+
...readTrimmed(entry["label"]) ? { label: readTrimmed(entry["label"]) } : {},
|
|
20724
|
+
...thinkingOptions && thinkingOptions.length > 0 ? { thinkingOptions } : {},
|
|
20725
|
+
...contextWindow !== void 0 ? { contextWindow } : {},
|
|
20726
|
+
...aliases && aliases.length > 0 ? { aliases } : {}
|
|
20727
|
+
});
|
|
20728
|
+
}
|
|
20729
|
+
return models;
|
|
20730
|
+
}
|
|
20731
|
+
function readAutoCompactWindow(value) {
|
|
20732
|
+
const trimmed = readTrimmed(value);
|
|
20733
|
+
return CLAUDE_AUTO_COMPACT_WINDOW_PATTERN.test(trimmed) ? trimmed : "";
|
|
20734
|
+
}
|
|
20735
|
+
function parseClaudeInstanceConfig(config) {
|
|
20736
|
+
if (!isRecord3(config)) {
|
|
20737
|
+
return {
|
|
20738
|
+
binaryPath: "",
|
|
20739
|
+
homePath: "",
|
|
20740
|
+
credentialsPath: "",
|
|
20741
|
+
launchArgs: "",
|
|
20742
|
+
autoCompactWindow: "",
|
|
20743
|
+
customModels: [],
|
|
20744
|
+
enabled: true,
|
|
20745
|
+
environment: {},
|
|
20746
|
+
envelopeDriver: void 0
|
|
20747
|
+
};
|
|
20748
|
+
}
|
|
20749
|
+
const nested = isRecord3(config["config"]) ? config["config"] : void 0;
|
|
20750
|
+
const settings = nested ?? config;
|
|
20751
|
+
return {
|
|
20752
|
+
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
20753
|
+
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
|
|
20754
|
+
credentialsPath: readTrimmed(settings["credentialsPath"]) || readTrimmed(config["credentialsPath"]),
|
|
20755
|
+
launchArgs: readString(settings["launchArgs"]),
|
|
20756
|
+
autoCompactWindow: readAutoCompactWindow(settings["autoCompactWindow"]),
|
|
20757
|
+
customModels: readCustomModels(settings["customModels"]),
|
|
20758
|
+
enabled: settings["enabled"] !== false,
|
|
20759
|
+
environment: readEnvironment(config["environment"]),
|
|
20760
|
+
envelopeDriver: readTrimmed(config["driver"]) || void 0
|
|
20761
|
+
};
|
|
20762
|
+
}
|
|
20763
|
+
function tokenizeLaunchArgs(value) {
|
|
20764
|
+
const input = value.trim();
|
|
20765
|
+
if (!input) return [];
|
|
20766
|
+
const tokens = [];
|
|
20767
|
+
let current = "";
|
|
20768
|
+
let quote;
|
|
20769
|
+
let quoted = false;
|
|
20770
|
+
for (let index = 0; index < input.length; index++) {
|
|
20771
|
+
const char = input[index];
|
|
20772
|
+
if (char === void 0) continue;
|
|
20773
|
+
if (quote) {
|
|
20774
|
+
if (char === quote) {
|
|
20775
|
+
quote = void 0;
|
|
20776
|
+
quoted = true;
|
|
20777
|
+
} else if (char === "\\" && quote === '"') {
|
|
20778
|
+
const next = input[index + 1];
|
|
20779
|
+
if (next !== void 0 && ['"', "\\", "$", "`"].includes(next)) {
|
|
20780
|
+
current += next;
|
|
20781
|
+
index++;
|
|
20079
20782
|
} else {
|
|
20080
20783
|
current += char;
|
|
20081
20784
|
}
|
|
@@ -20124,189 +20827,56 @@ function parseCliArgs(args, options) {
|
|
|
20124
20827
|
continue;
|
|
20125
20828
|
}
|
|
20126
20829
|
if (booleanSet?.has(rest)) {
|
|
20127
|
-
flags[rest] = null;
|
|
20128
|
-
continue;
|
|
20129
|
-
}
|
|
20130
|
-
const next = tokens[i + 1];
|
|
20131
|
-
if (next !== void 0 && !next.startsWith("--")) {
|
|
20132
|
-
flags[rest] = next;
|
|
20133
|
-
i++;
|
|
20134
|
-
} else {
|
|
20135
|
-
flags[rest] = null;
|
|
20136
|
-
}
|
|
20137
|
-
} else {
|
|
20138
|
-
positionals.push(token);
|
|
20139
|
-
}
|
|
20140
|
-
}
|
|
20141
|
-
return { flags, positionals };
|
|
20142
|
-
}
|
|
20143
|
-
|
|
20144
|
-
// src/events.ts
|
|
20145
|
-
var EventBus = class {
|
|
20146
|
-
#queued = [];
|
|
20147
|
-
#waiters = [];
|
|
20148
|
-
#closed = false;
|
|
20149
|
-
push(event) {
|
|
20150
|
-
const waiter = this.#waiters.shift();
|
|
20151
|
-
if (waiter) {
|
|
20152
|
-
waiter({ done: false, value: event });
|
|
20153
|
-
return;
|
|
20154
|
-
}
|
|
20155
|
-
this.#queued.push(event);
|
|
20156
|
-
}
|
|
20157
|
-
close() {
|
|
20158
|
-
if (this.#closed) return;
|
|
20159
|
-
this.#closed = true;
|
|
20160
|
-
while (this.#waiters.length > 0) {
|
|
20161
|
-
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
20162
|
-
}
|
|
20163
|
-
}
|
|
20164
|
-
[Symbol.asyncIterator]() {
|
|
20165
|
-
return {
|
|
20166
|
-
next: () => {
|
|
20167
|
-
const queued = this.#queued.shift();
|
|
20168
|
-
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
20169
|
-
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
20170
|
-
return new Promise((resolve3) => {
|
|
20171
|
-
this.#waiters.push(resolve3);
|
|
20172
|
-
});
|
|
20173
|
-
}
|
|
20174
|
-
};
|
|
20175
|
-
}
|
|
20176
|
-
};
|
|
20177
|
-
|
|
20178
|
-
// src/model.ts
|
|
20179
|
-
import { matchCatalogModel } from "@ycodium-ai/plugin-api/executor";
|
|
20180
|
-
var DEFAULT_CLAUDE_MODEL_CAPABILITIES = {
|
|
20181
|
-
optionDescriptors: []
|
|
20182
|
-
};
|
|
20183
|
-
var CLAUDE_CUSTOM_MODEL_THINKING_SELECT = {
|
|
20184
|
-
id: "effort",
|
|
20185
|
-
label: "Reasoning"
|
|
20186
|
-
};
|
|
20187
|
-
function parseGenericCliVersion(output) {
|
|
20188
|
-
const match = output.match(/\bv?(\d+\.\d+\.\d+)\b/);
|
|
20189
|
-
return match?.[1] ?? null;
|
|
20190
|
-
}
|
|
20191
|
-
function normalizeCustomModelSlug(slug) {
|
|
20192
|
-
return slug.trim();
|
|
20193
|
-
}
|
|
20194
|
-
function knownClaudeModelCapabilities(model, catalog, customModels) {
|
|
20195
|
-
const slug = model?.trim();
|
|
20196
|
-
const fromCatalog = catalog.find((candidate) => candidate.slug === slug)?.capabilities;
|
|
20197
|
-
if (fromCatalog) return fromCatalog;
|
|
20198
|
-
const custom = customModels?.find(
|
|
20199
|
-
(candidate) => normalizeCustomModelSlug(candidate.slug) === slug
|
|
20200
|
-
);
|
|
20201
|
-
if (custom?.thinkingOptions !== void 0 && custom.thinkingOptions.length > 0) {
|
|
20202
|
-
const currentValue = custom.thinkingOptions.find((option) => option.isDefault)?.id;
|
|
20203
|
-
return {
|
|
20204
|
-
optionDescriptors: [
|
|
20205
|
-
{
|
|
20206
|
-
type: "select",
|
|
20207
|
-
id: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.id,
|
|
20208
|
-
label: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.label,
|
|
20209
|
-
options: custom.thinkingOptions,
|
|
20210
|
-
...currentValue !== void 0 ? {} : {}
|
|
20211
|
-
}
|
|
20212
|
-
]
|
|
20213
|
-
};
|
|
20214
|
-
}
|
|
20215
|
-
return void 0;
|
|
20216
|
-
}
|
|
20217
|
-
function claudeModelCapabilities(model, catalog, customModels) {
|
|
20218
|
-
return knownClaudeModelCapabilities(model, catalog, customModels) ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES;
|
|
20219
|
-
}
|
|
20220
|
-
function isRecord3(value) {
|
|
20221
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20222
|
-
}
|
|
20223
|
-
function getModelSelectionStringOptionValue(modelSelection, optionId) {
|
|
20224
|
-
if (!isRecord3(modelSelection)) return void 0;
|
|
20225
|
-
const options = modelSelection["options"];
|
|
20226
|
-
if (!Array.isArray(options)) return void 0;
|
|
20227
|
-
for (const entry of options) {
|
|
20228
|
-
if (!isRecord3(entry)) continue;
|
|
20229
|
-
if (entry["id"] === optionId && typeof entry["value"] === "string") {
|
|
20230
|
-
const trimmed = entry["value"].trim();
|
|
20231
|
-
if (trimmed.length > 0) return trimmed;
|
|
20830
|
+
flags[rest] = null;
|
|
20831
|
+
continue;
|
|
20832
|
+
}
|
|
20833
|
+
const next = tokens[i + 1];
|
|
20834
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
20835
|
+
flags[rest] = next;
|
|
20836
|
+
i++;
|
|
20837
|
+
} else {
|
|
20838
|
+
flags[rest] = null;
|
|
20839
|
+
}
|
|
20840
|
+
} else {
|
|
20841
|
+
positionals.push(token);
|
|
20232
20842
|
}
|
|
20233
20843
|
}
|
|
20234
|
-
return
|
|
20844
|
+
return { flags, positionals };
|
|
20235
20845
|
}
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20846
|
+
|
|
20847
|
+
// src/events.ts
|
|
20848
|
+
var EventBus = class {
|
|
20849
|
+
#queued = [];
|
|
20850
|
+
#waiters = [];
|
|
20851
|
+
#closed = false;
|
|
20852
|
+
push(event) {
|
|
20853
|
+
const waiter = this.#waiters.shift();
|
|
20854
|
+
if (waiter) {
|
|
20855
|
+
waiter({ done: false, value: event });
|
|
20856
|
+
return;
|
|
20244
20857
|
}
|
|
20858
|
+
this.#queued.push(event);
|
|
20245
20859
|
}
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
}
|
|
20253
|
-
function currentSelectValue(descriptor, raw) {
|
|
20254
|
-
if (raw && descriptor.options.some((option) => option.id === raw)) return raw;
|
|
20255
|
-
return descriptor.options.find((option) => option.isDefault)?.id;
|
|
20256
|
-
}
|
|
20257
|
-
function resolveClaudeEffort(caps, raw) {
|
|
20258
|
-
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20259
|
-
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20260
|
-
return currentSelectValue(descriptor, raw);
|
|
20261
|
-
}
|
|
20262
|
-
function normalizeClaudeCliEffort(effort) {
|
|
20263
|
-
if (!effort || effort === "ultrathink") {
|
|
20264
|
-
return void 0;
|
|
20265
|
-
}
|
|
20266
|
-
if (effort === "ultracode") {
|
|
20267
|
-
return "xhigh";
|
|
20268
|
-
}
|
|
20269
|
-
return effort;
|
|
20270
|
-
}
|
|
20271
|
-
function isClaudeUltracodeEffort(effort) {
|
|
20272
|
-
return effort === "ultracode";
|
|
20273
|
-
}
|
|
20274
|
-
function claudeCliModelId(input) {
|
|
20275
|
-
const requested = input.requestedModelId.trim();
|
|
20276
|
-
if (requested.length > 0 && (input.catalog ?? []).length === 0) return requested;
|
|
20277
|
-
const known = [
|
|
20278
|
-
...(input.catalog ?? []).map((model) => model.slug),
|
|
20279
|
-
...input.declared ?? [],
|
|
20280
|
-
...(input.customModels ?? []).map((model) => normalizeCustomModelSlug(model.slug))
|
|
20281
|
-
];
|
|
20282
|
-
return matchCatalogModel(input.requestedModelId, known) ?? input.placeholder;
|
|
20283
|
-
}
|
|
20284
|
-
function resolvePromptInjectedEffort(caps, rawEffort) {
|
|
20285
|
-
const trimmed = rawEffort?.trim();
|
|
20286
|
-
if (!trimmed) return void 0;
|
|
20287
|
-
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20288
|
-
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20289
|
-
if (!descriptor.promptInjectedValues?.includes(trimmed)) return void 0;
|
|
20290
|
-
return trimmed;
|
|
20291
|
-
}
|
|
20292
|
-
function applyClaudePromptEffortPrefix(text, effort) {
|
|
20293
|
-
const trimmed = text.trim();
|
|
20294
|
-
if (!trimmed) {
|
|
20295
|
-
return trimmed;
|
|
20296
|
-
}
|
|
20297
|
-
if (effort !== "ultrathink" || /^\/[^\s/]+(?:\s|$)/u.test(trimmed)) {
|
|
20298
|
-
return trimmed;
|
|
20860
|
+
close() {
|
|
20861
|
+
if (this.#closed) return;
|
|
20862
|
+
this.#closed = true;
|
|
20863
|
+
while (this.#waiters.length > 0) {
|
|
20864
|
+
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
20865
|
+
}
|
|
20299
20866
|
}
|
|
20300
|
-
|
|
20301
|
-
return
|
|
20867
|
+
[Symbol.asyncIterator]() {
|
|
20868
|
+
return {
|
|
20869
|
+
next: () => {
|
|
20870
|
+
const queued = this.#queued.shift();
|
|
20871
|
+
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
20872
|
+
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
20873
|
+
return new Promise((resolve4) => {
|
|
20874
|
+
this.#waiters.push(resolve4);
|
|
20875
|
+
});
|
|
20876
|
+
}
|
|
20877
|
+
};
|
|
20302
20878
|
}
|
|
20303
|
-
|
|
20304
|
-
${trimmed}`;
|
|
20305
|
-
}
|
|
20306
|
-
function getEffectiveClaudeAgentEffort(effort) {
|
|
20307
|
-
const normalized = normalizeClaudeCliEffort(effort);
|
|
20308
|
-
return normalized ? normalized : null;
|
|
20309
|
-
}
|
|
20879
|
+
};
|
|
20310
20880
|
|
|
20311
20881
|
// src/sdkModels.ts
|
|
20312
20882
|
import * as NodeOS5 from "node:os";
|
|
@@ -20355,9 +20925,9 @@ var claudeCatalogFromSdk = (models) => {
|
|
|
20355
20925
|
};
|
|
20356
20926
|
var silentPrompt = (signal) => ({
|
|
20357
20927
|
[Symbol.asyncIterator]: () => ({
|
|
20358
|
-
next: () => new Promise((
|
|
20359
|
-
if (signal.aborted)
|
|
20360
|
-
signal.addEventListener("abort", () =>
|
|
20928
|
+
next: () => new Promise((resolve4) => {
|
|
20929
|
+
if (signal.aborted) resolve4({ done: true, value: void 0 });
|
|
20930
|
+
signal.addEventListener("abort", () => resolve4({ done: true, value: void 0 }), {
|
|
20361
20931
|
once: true
|
|
20362
20932
|
});
|
|
20363
20933
|
}),
|
|
@@ -20587,10 +21157,10 @@ function inputDiffStat(input) {
|
|
|
20587
21157
|
let deletions = 0;
|
|
20588
21158
|
for (const edit of input.edits) {
|
|
20589
21159
|
if (edit === null || typeof edit !== "object" || Array.isArray(edit)) return void 0;
|
|
20590
|
-
const
|
|
20591
|
-
if (!
|
|
20592
|
-
additions +=
|
|
20593
|
-
deletions +=
|
|
21160
|
+
const stat2 = replacementDiffStat(edit, budget);
|
|
21161
|
+
if (!stat2) return void 0;
|
|
21162
|
+
additions += stat2.additions;
|
|
21163
|
+
deletions += stat2.deletions;
|
|
20594
21164
|
}
|
|
20595
21165
|
return { additions, deletions };
|
|
20596
21166
|
}
|
|
@@ -20976,7 +21546,7 @@ function terminalResultError(reason, failureHint) {
|
|
|
20976
21546
|
case "turn_setup_failed":
|
|
20977
21547
|
return "Claude could not start the turn.";
|
|
20978
21548
|
case "blocking_limit":
|
|
20979
|
-
return "Claude stopped: a usage limit blocked the request.";
|
|
21549
|
+
return failureHint ?? "Claude stopped: a usage limit blocked the request.";
|
|
20980
21550
|
case "rapid_refill_breaker":
|
|
20981
21551
|
return "Claude stopped: the context refilled too quickly after compaction.";
|
|
20982
21552
|
case "prompt_too_long":
|
|
@@ -21011,10 +21581,8 @@ function resultOutcome(result, failureHint) {
|
|
|
21011
21581
|
return { status: "completed", errorMessage };
|
|
21012
21582
|
}
|
|
21013
21583
|
if (isInterruptedResult(result)) return { status: "interrupted", errorMessage };
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
errorMessage
|
|
21017
|
-
};
|
|
21584
|
+
const cancelled = resultErrorsText(result).includes("cancel");
|
|
21585
|
+
return cancelled ? { status: "cancelled", errorMessage } : { status: "failed", errorMessage: errorMessage ?? failureHint };
|
|
21018
21586
|
}
|
|
21019
21587
|
function streamKindFromDeltaType(deltaType) {
|
|
21020
21588
|
return deltaType.includes("thinking") ? "reasoning_text" : "assistant_text";
|
|
@@ -21111,92 +21679,6 @@ function describeUnknownSdkMessage(kind, message) {
|
|
|
21111
21679
|
return preview ? `${kind} \u2014 ${preview}` : `${kind} (no displayable text content)`;
|
|
21112
21680
|
}
|
|
21113
21681
|
|
|
21114
|
-
// src/sessionSettings.ts
|
|
21115
|
-
function toSessionPermissionUpdates(toolName, suggestions) {
|
|
21116
|
-
const sessionScoped = (suggestions ?? []).map(
|
|
21117
|
-
(suggestion) => ({ ...suggestion, destination: "session" })
|
|
21118
|
-
);
|
|
21119
|
-
if (sessionScoped.length > 0) {
|
|
21120
|
-
return sessionScoped;
|
|
21121
|
-
}
|
|
21122
|
-
return [
|
|
21123
|
-
{
|
|
21124
|
-
type: "addRules",
|
|
21125
|
-
rules: [{ toolName }],
|
|
21126
|
-
behavior: "allow",
|
|
21127
|
-
destination: "session"
|
|
21128
|
-
}
|
|
21129
|
-
];
|
|
21130
|
-
}
|
|
21131
|
-
var CLAUDE_SESSION_SETTING_KEYS = [
|
|
21132
|
-
"alwaysThinkingEnabled",
|
|
21133
|
-
"fastMode",
|
|
21134
|
-
"ultracode",
|
|
21135
|
-
"autoCompactWindow"
|
|
21136
|
-
];
|
|
21137
|
-
function buildClaudeSessionSettings(input) {
|
|
21138
|
-
return {
|
|
21139
|
-
...typeof input.thinking === "boolean" ? { alwaysThinkingEnabled: input.thinking } : {},
|
|
21140
|
-
...input.fastMode ? { fastMode: true } : {},
|
|
21141
|
-
...input.ultracode ? { ultracode: true } : {},
|
|
21142
|
-
...input.autoCompactWindow ? { autoCompactWindow: Number(input.autoCompactWindow) } : {}
|
|
21143
|
-
};
|
|
21144
|
-
}
|
|
21145
|
-
function diffClaudeSessionSettings(previous, next) {
|
|
21146
|
-
const patch = {};
|
|
21147
|
-
let changed = false;
|
|
21148
|
-
const track = (key) => {
|
|
21149
|
-
if (previous[key] === next[key]) {
|
|
21150
|
-
return;
|
|
21151
|
-
}
|
|
21152
|
-
changed = true;
|
|
21153
|
-
patch[key] = next[key] ?? null;
|
|
21154
|
-
};
|
|
21155
|
-
for (const key of CLAUDE_SESSION_SETTING_KEYS) {
|
|
21156
|
-
track(key);
|
|
21157
|
-
}
|
|
21158
|
-
return changed ? patch : void 0;
|
|
21159
|
-
}
|
|
21160
|
-
var CLAUDE_NATIVE_MODES = [
|
|
21161
|
-
{ id: "default", name: "Manual", description: "Always ask before making changes" },
|
|
21162
|
-
{ id: "acceptEdits", name: "Accept edits", description: "Automatically accept all file edits" },
|
|
21163
|
-
{ id: "plan", name: "Plan", description: "Create a plan before making changes" },
|
|
21164
|
-
{ id: "auto", name: "Auto", description: "Claude handles permission decisions" },
|
|
21165
|
-
{
|
|
21166
|
-
id: "bypassPermissions",
|
|
21167
|
-
name: "Bypass permissions",
|
|
21168
|
-
description: "Accepts all permissions"
|
|
21169
|
-
}
|
|
21170
|
-
];
|
|
21171
|
-
var CLAUDE_DEFAULT_NATIVE_MODE_ID = "default";
|
|
21172
|
-
var CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE = {
|
|
21173
|
-
"approval-required": "default",
|
|
21174
|
-
"auto-accept-edits": "acceptEdits",
|
|
21175
|
-
auto: "auto",
|
|
21176
|
-
"full-access": "bypassPermissions"
|
|
21177
|
-
};
|
|
21178
|
-
var CLAUDE_NATIVE_MODE_REPORT = {
|
|
21179
|
-
nativeModes: CLAUDE_NATIVE_MODES.map((mode) => ({
|
|
21180
|
-
id: mode.id,
|
|
21181
|
-
name: mode.name,
|
|
21182
|
-
description: mode.description
|
|
21183
|
-
})),
|
|
21184
|
-
currentNativeModeId: CLAUDE_DEFAULT_NATIVE_MODE_ID,
|
|
21185
|
-
nativeModeByRuntimeMode: CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE
|
|
21186
|
-
};
|
|
21187
|
-
function isClaudeNativeModeId(value) {
|
|
21188
|
-
return CLAUDE_NATIVE_MODES.some((mode) => mode.id === value);
|
|
21189
|
-
}
|
|
21190
|
-
function claudePermissionModeFor(runtimeMode, nativeModeId) {
|
|
21191
|
-
if (nativeModeId !== void 0 && isClaudeNativeModeId(nativeModeId)) return nativeModeId;
|
|
21192
|
-
return CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE[runtimeMode];
|
|
21193
|
-
}
|
|
21194
|
-
var CLAUDE_SETTING_SOURCES = [
|
|
21195
|
-
"user",
|
|
21196
|
-
"project",
|
|
21197
|
-
"local"
|
|
21198
|
-
];
|
|
21199
|
-
|
|
21200
21682
|
// src/readOnlyDirectories.ts
|
|
21201
21683
|
var GLOB_METACHARACTERS = /[*?[\]{}]/;
|
|
21202
21684
|
function toClaudeAbsolutePath(directory) {
|
|
@@ -21222,8 +21704,8 @@ function claudeReadAllowRules(directories) {
|
|
|
21222
21704
|
// src/sessions.ts
|
|
21223
21705
|
import * as NodeFS3 from "node:fs";
|
|
21224
21706
|
import * as NodeOS6 from "node:os";
|
|
21225
|
-
import * as
|
|
21226
|
-
import * as
|
|
21707
|
+
import * as NodePath7 from "node:path";
|
|
21708
|
+
import * as NodeProcess2 from "node:process";
|
|
21227
21709
|
|
|
21228
21710
|
// ../../packages/ycodium-jsonl-stream/src/jsonlStream.ts
|
|
21229
21711
|
var DEFAULT_MAX_RETAINED_CHARS = 8e6;
|
|
@@ -21851,7 +22333,7 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
21851
22333
|
const scanned = matched.length > 0 ? matched : dirs;
|
|
21852
22334
|
const found = [];
|
|
21853
22335
|
for (const dir of scanned) {
|
|
21854
|
-
const projectDir =
|
|
22336
|
+
const projectDir = NodePath7.join(transcriptDir, dir);
|
|
21855
22337
|
let names;
|
|
21856
22338
|
try {
|
|
21857
22339
|
names = NodeFS3.readdirSync(projectDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TRANSCRIPT_SUFFIX)).map((entry) => entry.name);
|
|
@@ -21859,17 +22341,17 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
21859
22341
|
continue;
|
|
21860
22342
|
}
|
|
21861
22343
|
for (const name of names) {
|
|
21862
|
-
let
|
|
22344
|
+
let stat2;
|
|
21863
22345
|
try {
|
|
21864
|
-
|
|
22346
|
+
stat2 = NodeFS3.statSync(NodePath7.join(projectDir, name));
|
|
21865
22347
|
} catch {
|
|
21866
22348
|
continue;
|
|
21867
22349
|
}
|
|
21868
22350
|
found.push({
|
|
21869
|
-
path:
|
|
22351
|
+
path: NodePath7.join(projectDir, name),
|
|
21870
22352
|
sessionId: name.slice(0, -TRANSCRIPT_SUFFIX.length),
|
|
21871
|
-
size:
|
|
21872
|
-
mtimeMs: Number.isFinite(
|
|
22353
|
+
size: stat2.size,
|
|
22354
|
+
mtimeMs: Number.isFinite(stat2.mtimeMs) ? stat2.mtimeMs : 0
|
|
21873
22355
|
});
|
|
21874
22356
|
}
|
|
21875
22357
|
}
|
|
@@ -21877,7 +22359,7 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
21877
22359
|
}
|
|
21878
22360
|
function readClaudeLiveSessionIds(configDir) {
|
|
21879
22361
|
const live = /* @__PURE__ */ new Set();
|
|
21880
|
-
const markerDir =
|
|
22362
|
+
const markerDir = NodePath7.join(configDir, "sessions");
|
|
21881
22363
|
let entries;
|
|
21882
22364
|
try {
|
|
21883
22365
|
entries = NodeFS3.readdirSync(markerDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name);
|
|
@@ -21887,7 +22369,7 @@ function readClaudeLiveSessionIds(configDir) {
|
|
|
21887
22369
|
for (const entry of entries) {
|
|
21888
22370
|
let marker;
|
|
21889
22371
|
try {
|
|
21890
|
-
marker = JSON.parse(NodeFS3.readFileSync(
|
|
22372
|
+
marker = JSON.parse(NodeFS3.readFileSync(NodePath7.join(markerDir, entry), "utf8"));
|
|
21891
22373
|
} catch {
|
|
21892
22374
|
continue;
|
|
21893
22375
|
}
|
|
@@ -21895,7 +22377,7 @@ function readClaudeLiveSessionIds(configDir) {
|
|
|
21895
22377
|
const typed = marker;
|
|
21896
22378
|
if (typeof typed.pid !== "number" || typeof typed.sessionId !== "string") continue;
|
|
21897
22379
|
try {
|
|
21898
|
-
|
|
22380
|
+
NodeProcess2.kill(typed.pid, 0);
|
|
21899
22381
|
} catch {
|
|
21900
22382
|
continue;
|
|
21901
22383
|
}
|
|
@@ -21941,7 +22423,7 @@ async function scanClaudeSessions(input) {
|
|
|
21941
22423
|
function resolveTranscriptPath(input) {
|
|
21942
22424
|
const fileName = `${input.sessionId}${TRANSCRIPT_SUFFIX}`;
|
|
21943
22425
|
if (input.cwd !== void 0 && input.cwd.length > 0) {
|
|
21944
|
-
const direct =
|
|
22426
|
+
const direct = NodePath7.join(
|
|
21945
22427
|
input.transcriptDir,
|
|
21946
22428
|
encodeClaudeProjectDirName(input.cwd),
|
|
21947
22429
|
fileName
|
|
@@ -21958,7 +22440,7 @@ function resolveTranscriptPath(input) {
|
|
|
21958
22440
|
return null;
|
|
21959
22441
|
}
|
|
21960
22442
|
for (const dir of dirs) {
|
|
21961
|
-
const candidate =
|
|
22443
|
+
const candidate = NodePath7.join(input.transcriptDir, dir, fileName);
|
|
21962
22444
|
try {
|
|
21963
22445
|
if (NodeFS3.statSync(candidate).isFile()) return candidate;
|
|
21964
22446
|
} catch {
|
|
@@ -22417,69 +22899,28 @@ function normalizeClaudeTaskProgressTokenUsage(value, memory) {
|
|
|
22417
22899
|
const usage = value;
|
|
22418
22900
|
const snapshot = makeClaudeTokenUsageSnapshot({
|
|
22419
22901
|
activeTokens,
|
|
22420
|
-
...memory.lastKnownContextWindow !== void 0 ? { contextWindow: memory.lastKnownContextWindow } : {},
|
|
22421
|
-
totalProcessedTokens: Math.max(
|
|
22422
|
-
totalTokens,
|
|
22423
|
-
memory.lastKnownTotalProcessedTokens ?? totalTokens
|
|
22424
|
-
)
|
|
22425
|
-
});
|
|
22426
|
-
if (!snapshot) {
|
|
22427
|
-
return void 0;
|
|
22428
|
-
}
|
|
22429
|
-
const toolUses = finiteNonNegativeInteger(usage.tool_uses);
|
|
22430
|
-
const durationMs = finiteNonNegativeInteger(usage.duration_ms);
|
|
22431
|
-
return {
|
|
22432
|
-
...snapshot,
|
|
22433
|
-
...toolUses !== void 0 ? { toolUses } : {},
|
|
22434
|
-
...durationMs !== void 0 ? { durationMs } : {}
|
|
22435
|
-
};
|
|
22436
|
-
}
|
|
22437
|
-
|
|
22438
|
-
// src/probeModels.ts
|
|
22439
|
-
var toProbeCapabilities = (caps) => ({
|
|
22440
|
-
optionDescriptors: caps.optionDescriptors.map(
|
|
22441
|
-
(descriptor) => descriptor.type === "select" ? {
|
|
22442
|
-
id: descriptor.id,
|
|
22443
|
-
label: descriptor.label,
|
|
22444
|
-
type: "select",
|
|
22445
|
-
options: descriptor.options.map((option) => ({
|
|
22446
|
-
id: option.id,
|
|
22447
|
-
label: option.label,
|
|
22448
|
-
...option.description === void 0 ? {} : { description: option.description },
|
|
22449
|
-
...option.isDefault === void 0 ? {} : { isDefault: option.isDefault }
|
|
22450
|
-
}))
|
|
22451
|
-
} : {
|
|
22452
|
-
id: descriptor.id,
|
|
22453
|
-
label: descriptor.label,
|
|
22454
|
-
type: "boolean"
|
|
22455
|
-
}
|
|
22456
|
-
)
|
|
22457
|
-
});
|
|
22458
|
-
var claudeProbeModels = (input) => {
|
|
22459
|
-
const seen = /* @__PURE__ */ new Set();
|
|
22460
|
-
const out = [];
|
|
22461
|
-
for (const model of input.catalog) {
|
|
22462
|
-
if (seen.has(model.slug)) continue;
|
|
22463
|
-
seen.add(model.slug);
|
|
22464
|
-
const userLabel = input.customModels.find((entry) => entry.slug === model.slug)?.label;
|
|
22465
|
-
out.push({
|
|
22466
|
-
slug: model.slug,
|
|
22467
|
-
name: userLabel?.trim() || model.name,
|
|
22468
|
-
capabilities: toProbeCapabilities(model.capabilities)
|
|
22469
|
-
});
|
|
22470
|
-
}
|
|
22471
|
-
for (const model of input.customModels) {
|
|
22472
|
-
if (model.slug.trim().length === 0 || seen.has(model.slug)) continue;
|
|
22473
|
-
seen.add(model.slug);
|
|
22474
|
-
out.push({ slug: model.slug, name: model.label?.trim() || model.slug });
|
|
22902
|
+
...memory.lastKnownContextWindow !== void 0 ? { contextWindow: memory.lastKnownContextWindow } : {},
|
|
22903
|
+
totalProcessedTokens: Math.max(
|
|
22904
|
+
totalTokens,
|
|
22905
|
+
memory.lastKnownTotalProcessedTokens ?? totalTokens
|
|
22906
|
+
)
|
|
22907
|
+
});
|
|
22908
|
+
if (!snapshot) {
|
|
22909
|
+
return void 0;
|
|
22475
22910
|
}
|
|
22476
|
-
|
|
22477
|
-
|
|
22911
|
+
const toolUses = finiteNonNegativeInteger(usage.tool_uses);
|
|
22912
|
+
const durationMs = finiteNonNegativeInteger(usage.duration_ms);
|
|
22913
|
+
return {
|
|
22914
|
+
...snapshot,
|
|
22915
|
+
...toolUses !== void 0 ? { toolUses } : {},
|
|
22916
|
+
...durationMs !== void 0 ? { durationMs } : {}
|
|
22917
|
+
};
|
|
22918
|
+
}
|
|
22478
22919
|
|
|
22479
22920
|
// src/textGeneration.ts
|
|
22480
|
-
import * as
|
|
22921
|
+
import * as NodeFSP3 from "node:fs/promises";
|
|
22481
22922
|
import * as NodeOS7 from "node:os";
|
|
22482
|
-
import * as
|
|
22923
|
+
import * as NodePath8 from "node:path";
|
|
22483
22924
|
import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
|
|
22484
22925
|
|
|
22485
22926
|
// src/textGenerationUtils.ts
|
|
@@ -22948,16 +23389,16 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
22948
23389
|
return decodeStructuredOutput(stdout, input.operation);
|
|
22949
23390
|
};
|
|
22950
23391
|
if (input.operation !== "generateThreadTitle") return runIn(input.cwd);
|
|
22951
|
-
const scratchDirectory = await
|
|
22952
|
-
|
|
23392
|
+
const scratchDirectory = await NodeFSP3.mkdtemp(
|
|
23393
|
+
NodePath8.join(NodeOS7.tmpdir(), "ycodium-claude-title-")
|
|
22953
23394
|
);
|
|
22954
23395
|
try {
|
|
22955
23396
|
return await runIn(scratchDirectory);
|
|
22956
23397
|
} finally {
|
|
22957
|
-
await
|
|
23398
|
+
await NodeFSP3.rm(scratchDirectory, { recursive: true, force: true }).catch(() => void 0);
|
|
22958
23399
|
}
|
|
22959
23400
|
};
|
|
22960
|
-
const
|
|
23401
|
+
const asRecord2 = (value, operation) => {
|
|
22961
23402
|
if (!isRecord5(value))
|
|
22962
23403
|
throw new Error(`${operation}: Claude returned invalid structured output.`);
|
|
22963
23404
|
return value;
|
|
@@ -22965,7 +23406,7 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
22965
23406
|
return {
|
|
22966
23407
|
generateCommitMessage: async (raw, signal) => {
|
|
22967
23408
|
try {
|
|
22968
|
-
const input =
|
|
23409
|
+
const input = asRecord2(raw, "generateCommitMessage");
|
|
22969
23410
|
const includeBranch = input["includeBranch"] === true;
|
|
22970
23411
|
const { prompt, outputSchema } = buildCommitMessagePrompt({
|
|
22971
23412
|
branch: typeof input["branch"] === "string" ? input["branch"] : null,
|
|
@@ -22974,7 +23415,7 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
22974
23415
|
includeBranch,
|
|
22975
23416
|
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
22976
23417
|
});
|
|
22977
|
-
const generated =
|
|
23418
|
+
const generated = asRecord2(
|
|
22978
23419
|
await runClaudeJson({
|
|
22979
23420
|
operation: "generateCommitMessage",
|
|
22980
23421
|
cwd: readString3(input["cwd"]) || ".",
|
|
@@ -22993,114 +23434,799 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
22993
23434
|
} catch (error) {
|
|
22994
23435
|
throw normalizeCliError("claude", error, "Failed to generate commit message");
|
|
22995
23436
|
}
|
|
22996
|
-
},
|
|
22997
|
-
generatePrContent: async (raw, signal) => {
|
|
22998
|
-
try {
|
|
22999
|
-
const input =
|
|
23000
|
-
const { prompt, outputSchema } = buildPrContentPrompt({
|
|
23001
|
-
baseBranch: readString3(input["baseBranch"]),
|
|
23002
|
-
headBranch: readString3(input["headBranch"]),
|
|
23003
|
-
commitSummary: readString3(input["commitSummary"]),
|
|
23004
|
-
diffSummary: readString3(input["diffSummary"]),
|
|
23005
|
-
diffPatch: readString3(input["diffPatch"]),
|
|
23006
|
-
...typeof input["changeRequestTemplate"] === "string" ? { changeRequestTemplate: input["changeRequestTemplate"] } : {},
|
|
23007
|
-
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23008
|
-
});
|
|
23009
|
-
const generated =
|
|
23010
|
-
await runClaudeJson({
|
|
23011
|
-
operation: "generatePrContent",
|
|
23012
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23013
|
-
prompt,
|
|
23014
|
-
outputSchema,
|
|
23015
|
-
modelSelection: input["modelSelection"],
|
|
23016
|
-
...signal === void 0 ? {} : { signal }
|
|
23017
|
-
}),
|
|
23018
|
-
"generatePrContent"
|
|
23019
|
-
);
|
|
23020
|
-
return {
|
|
23021
|
-
title: sanitizePrTitle(readString3(generated["title"])),
|
|
23022
|
-
body: readString3(generated["body"]).trim()
|
|
23023
|
-
};
|
|
23024
|
-
} catch (error) {
|
|
23025
|
-
throw normalizeCliError("claude", error, "Failed to generate change request content");
|
|
23437
|
+
},
|
|
23438
|
+
generatePrContent: async (raw, signal) => {
|
|
23439
|
+
try {
|
|
23440
|
+
const input = asRecord2(raw, "generatePrContent");
|
|
23441
|
+
const { prompt, outputSchema } = buildPrContentPrompt({
|
|
23442
|
+
baseBranch: readString3(input["baseBranch"]),
|
|
23443
|
+
headBranch: readString3(input["headBranch"]),
|
|
23444
|
+
commitSummary: readString3(input["commitSummary"]),
|
|
23445
|
+
diffSummary: readString3(input["diffSummary"]),
|
|
23446
|
+
diffPatch: readString3(input["diffPatch"]),
|
|
23447
|
+
...typeof input["changeRequestTemplate"] === "string" ? { changeRequestTemplate: input["changeRequestTemplate"] } : {},
|
|
23448
|
+
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23449
|
+
});
|
|
23450
|
+
const generated = asRecord2(
|
|
23451
|
+
await runClaudeJson({
|
|
23452
|
+
operation: "generatePrContent",
|
|
23453
|
+
cwd: readString3(input["cwd"]) || ".",
|
|
23454
|
+
prompt,
|
|
23455
|
+
outputSchema,
|
|
23456
|
+
modelSelection: input["modelSelection"],
|
|
23457
|
+
...signal === void 0 ? {} : { signal }
|
|
23458
|
+
}),
|
|
23459
|
+
"generatePrContent"
|
|
23460
|
+
);
|
|
23461
|
+
return {
|
|
23462
|
+
title: sanitizePrTitle(readString3(generated["title"])),
|
|
23463
|
+
body: readString3(generated["body"]).trim()
|
|
23464
|
+
};
|
|
23465
|
+
} catch (error) {
|
|
23466
|
+
throw normalizeCliError("claude", error, "Failed to generate change request content");
|
|
23467
|
+
}
|
|
23468
|
+
},
|
|
23469
|
+
generateBranchName: async (raw, signal) => {
|
|
23470
|
+
try {
|
|
23471
|
+
const input = asRecord2(raw, "generateBranchName");
|
|
23472
|
+
const { prompt, outputSchema } = buildBranchNamePrompt({
|
|
23473
|
+
message: readString3(input["message"]),
|
|
23474
|
+
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
23475
|
+
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23476
|
+
});
|
|
23477
|
+
const generated = asRecord2(
|
|
23478
|
+
await runClaudeJson({
|
|
23479
|
+
operation: "generateBranchName",
|
|
23480
|
+
cwd: readString3(input["cwd"]) || ".",
|
|
23481
|
+
prompt,
|
|
23482
|
+
outputSchema,
|
|
23483
|
+
modelSelection: input["modelSelection"],
|
|
23484
|
+
...signal === void 0 ? {} : { signal }
|
|
23485
|
+
}),
|
|
23486
|
+
"generateBranchName"
|
|
23487
|
+
);
|
|
23488
|
+
return { branch: sanitizeBranchFragment(readString3(generated["branch"])) };
|
|
23489
|
+
} catch (error) {
|
|
23490
|
+
throw normalizeCliError("claude", error, "Failed to generate branch name");
|
|
23491
|
+
}
|
|
23492
|
+
},
|
|
23493
|
+
generateThreadTitle: async (raw, signal) => {
|
|
23494
|
+
try {
|
|
23495
|
+
const input = asRecord2(raw, "generateThreadTitle");
|
|
23496
|
+
const { prompt, outputSchema } = buildThreadTitlePrompt({
|
|
23497
|
+
message: readString3(input["message"]),
|
|
23498
|
+
...typeof input["linkedContext"] === "string" && input["linkedContext"].length > 0 ? { linkedContext: input["linkedContext"] } : {},
|
|
23499
|
+
...typeof input["previousTitle"] === "string" ? { previousTitle: input["previousTitle"] } : {},
|
|
23500
|
+
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
23501
|
+
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23502
|
+
});
|
|
23503
|
+
const generated = asRecord2(
|
|
23504
|
+
await runClaudeJson({
|
|
23505
|
+
operation: "generateThreadTitle",
|
|
23506
|
+
cwd: readString3(input["cwd"]) || ".",
|
|
23507
|
+
prompt,
|
|
23508
|
+
outputSchema,
|
|
23509
|
+
modelSelection: input["modelSelection"],
|
|
23510
|
+
...signal === void 0 ? {} : { signal }
|
|
23511
|
+
}),
|
|
23512
|
+
"generateThreadTitle"
|
|
23513
|
+
);
|
|
23514
|
+
return {
|
|
23515
|
+
title: sanitizeThreadTitle(readString3(generated["title"])),
|
|
23516
|
+
...generated["needsRefinement"] === true ? { needsRefinement: true } : {}
|
|
23517
|
+
};
|
|
23518
|
+
} catch (error) {
|
|
23519
|
+
throw normalizeCliError("claude", error, "Failed to generate thread title");
|
|
23520
|
+
}
|
|
23521
|
+
},
|
|
23522
|
+
summarizeHandover: async (raw, signal) => {
|
|
23523
|
+
try {
|
|
23524
|
+
const input = asRecord2(raw, "summarizeHandover");
|
|
23525
|
+
const { prompt, outputSchema } = buildHandoverSummaryPrompt({
|
|
23526
|
+
transcript: readString3(input["transcript"])
|
|
23527
|
+
});
|
|
23528
|
+
const generated = asRecord2(
|
|
23529
|
+
await runClaudeJson({
|
|
23530
|
+
operation: "summarizeHandover",
|
|
23531
|
+
cwd: readString3(input["cwd"]) || ".",
|
|
23532
|
+
prompt,
|
|
23533
|
+
outputSchema,
|
|
23534
|
+
modelSelection: input["modelSelection"],
|
|
23535
|
+
...signal === void 0 ? {} : { signal }
|
|
23536
|
+
}),
|
|
23537
|
+
"summarizeHandover"
|
|
23538
|
+
);
|
|
23539
|
+
return { summary: readString3(generated["summary"]).trim() };
|
|
23540
|
+
} catch (error) {
|
|
23541
|
+
throw normalizeCliError("claude", error, "Failed to summarize handover");
|
|
23542
|
+
}
|
|
23543
|
+
}
|
|
23544
|
+
};
|
|
23545
|
+
}
|
|
23546
|
+
|
|
23547
|
+
// src/usageRead/index.ts
|
|
23548
|
+
import * as NodePath12 from "node:path";
|
|
23549
|
+
|
|
23550
|
+
// src/usageRead/quota.ts
|
|
23551
|
+
import * as NodeFS4 from "node:fs";
|
|
23552
|
+
import * as NodePath9 from "node:path";
|
|
23553
|
+
import { mergeLaunchEnv as mergeLaunchEnv2, setsOwnModelConnection } from "@ycodium-ai/plugin-api/executor";
|
|
23554
|
+
import {
|
|
23555
|
+
parseRetryAfterMs
|
|
23556
|
+
} from "@ycodium-ai/plugin-api/usage";
|
|
23557
|
+
var CLAUDE_QUOTA_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
23558
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
23559
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
23560
|
+
var WINDOWS = [
|
|
23561
|
+
{ field: "five_hour", id: "session", labelKey: "usage.window.session", windowMs: 5 * HOUR_MS },
|
|
23562
|
+
{ field: "seven_day", id: "weekly", labelKey: "usage.window.weekly", windowMs: 7 * 24 * HOUR_MS }
|
|
23563
|
+
];
|
|
23564
|
+
var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23565
|
+
var launchEnvironment = (recipe) => mergeLaunchEnv2({
|
|
23566
|
+
inherited: process.env,
|
|
23567
|
+
instanceTable: recipe.environment,
|
|
23568
|
+
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
23569
|
+
});
|
|
23570
|
+
var claudeCredentialFileCandidates = (recipe) => {
|
|
23571
|
+
const environment = launchEnvironment(recipe);
|
|
23572
|
+
const credentialsDir = resolveClaudeCredentialsDirPath(
|
|
23573
|
+
environment[CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE] ?? ""
|
|
23574
|
+
);
|
|
23575
|
+
if (credentialsDir !== null) return [NodePath9.join(credentialsDir, ".credentials.json")];
|
|
23576
|
+
const configDir = resolveClaudeConfigDirPath(recipe.homePath, environment);
|
|
23577
|
+
const home = resolveClaudeHomePath(recipe.homePath);
|
|
23578
|
+
return [
|
|
23579
|
+
.../* @__PURE__ */ new Set([
|
|
23580
|
+
NodePath9.join(configDir, ".credentials.json"),
|
|
23581
|
+
NodePath9.join(home, ".claude", ".credentials.json"),
|
|
23582
|
+
NodePath9.join(home, ".credentials.json")
|
|
23583
|
+
])
|
|
23584
|
+
];
|
|
23585
|
+
};
|
|
23586
|
+
var readString4 = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
23587
|
+
var readLoginCredential = (candidates) => {
|
|
23588
|
+
for (const path of candidates) {
|
|
23589
|
+
let raw;
|
|
23590
|
+
try {
|
|
23591
|
+
raw = NodeFS4.readFileSync(path, "utf8");
|
|
23592
|
+
} catch {
|
|
23593
|
+
continue;
|
|
23594
|
+
}
|
|
23595
|
+
if (raw.trim().length === 0) continue;
|
|
23596
|
+
let parsed;
|
|
23597
|
+
try {
|
|
23598
|
+
parsed = JSON.parse(raw);
|
|
23599
|
+
} catch {
|
|
23600
|
+
continue;
|
|
23601
|
+
}
|
|
23602
|
+
const oauth = isRecord6(parsed) ? parsed["claudeAiOauth"] : void 0;
|
|
23603
|
+
if (!isRecord6(oauth)) continue;
|
|
23604
|
+
const accessToken = readString4(oauth["accessToken"]);
|
|
23605
|
+
if (accessToken === void 0) continue;
|
|
23606
|
+
return {
|
|
23607
|
+
accessToken,
|
|
23608
|
+
subscriptionType: readString4(oauth["subscriptionType"]),
|
|
23609
|
+
rateLimitTier: readString4(oauth["rateLimitTier"]),
|
|
23610
|
+
path
|
|
23611
|
+
};
|
|
23612
|
+
}
|
|
23613
|
+
return null;
|
|
23614
|
+
};
|
|
23615
|
+
var claudePlanName = (credential) => {
|
|
23616
|
+
const type4 = credential.subscriptionType;
|
|
23617
|
+
if (type4 === void 0) return void 0;
|
|
23618
|
+
const name = `${type4.charAt(0).toUpperCase()}${type4.slice(1)}`;
|
|
23619
|
+
const multiplier = /(?:^|_)(\d+x)$/.exec(credential.rateLimitTier ?? "")?.[1];
|
|
23620
|
+
return multiplier === void 0 ? name : `${name} ${multiplier}`;
|
|
23621
|
+
};
|
|
23622
|
+
var toIso = (value) => {
|
|
23623
|
+
if (typeof value !== "string") return null;
|
|
23624
|
+
const parsed = Date.parse(value);
|
|
23625
|
+
return Number.isNaN(parsed) ? null : new Date(parsed).toISOString();
|
|
23626
|
+
};
|
|
23627
|
+
var readWindows = (body) => WINDOWS.flatMap((spec) => {
|
|
23628
|
+
const row = body[spec.field];
|
|
23629
|
+
if (!isRecord6(row)) return [];
|
|
23630
|
+
const utilization = row["utilization"];
|
|
23631
|
+
if (typeof utilization !== "number" || !Number.isFinite(utilization)) return [];
|
|
23632
|
+
return [
|
|
23633
|
+
{
|
|
23634
|
+
id: spec.id,
|
|
23635
|
+
label: { key: spec.labelKey },
|
|
23636
|
+
usedPercent: Math.min(100, Math.max(0, utilization)),
|
|
23637
|
+
resetsAt: toIso(row["resets_at"]),
|
|
23638
|
+
windowMs: spec.windowMs
|
|
23639
|
+
}
|
|
23640
|
+
];
|
|
23641
|
+
});
|
|
23642
|
+
var readClaudeQuota = async (request) => {
|
|
23643
|
+
const { recipe } = request;
|
|
23644
|
+
const connectivity = CLAUDE_CARD.modelConnectivity;
|
|
23645
|
+
const environmentRows = Object.entries(recipe.environment).map(([name, value]) => ({
|
|
23646
|
+
name,
|
|
23647
|
+
value
|
|
23648
|
+
}));
|
|
23649
|
+
if (connectivity !== void 0 && setsOwnModelConnection(connectivity, environmentRows)) {
|
|
23650
|
+
const changesEndpoint = setsOwnModelConnection(
|
|
23651
|
+
{
|
|
23652
|
+
baseUrlEnvKey: connectivity.baseUrlEnvKey,
|
|
23653
|
+
backendSwitchEnvKeys: connectivity.backendSwitchEnvKeys
|
|
23654
|
+
},
|
|
23655
|
+
environmentRows
|
|
23656
|
+
);
|
|
23657
|
+
return {
|
|
23658
|
+
status: "unavailable",
|
|
23659
|
+
reason: changesEndpoint ? "customEndpoint" : "unsupportedLogin"
|
|
23660
|
+
};
|
|
23661
|
+
}
|
|
23662
|
+
const credential = readLoginCredential(claudeCredentialFileCandidates(recipe));
|
|
23663
|
+
if (credential === null) return { status: "unavailable", reason: "missingCredentials" };
|
|
23664
|
+
const now = request.now ?? Date.now;
|
|
23665
|
+
let response;
|
|
23666
|
+
try {
|
|
23667
|
+
response = await request.fetch(CLAUDE_QUOTA_URL, {
|
|
23668
|
+
method: "GET",
|
|
23669
|
+
headers: {
|
|
23670
|
+
Accept: "application/json",
|
|
23671
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
23672
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
23673
|
+
},
|
|
23674
|
+
redirect: "error",
|
|
23675
|
+
signal: request.signal === void 0 ? AbortSignal.timeout(REQUEST_TIMEOUT_MS) : AbortSignal.any([request.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)])
|
|
23676
|
+
});
|
|
23677
|
+
} catch (cause) {
|
|
23678
|
+
if (request.signal?.aborted === true) throw cause;
|
|
23679
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
23680
|
+
}
|
|
23681
|
+
const release = () => {
|
|
23682
|
+
void response.body?.cancel().catch(() => void 0);
|
|
23683
|
+
};
|
|
23684
|
+
if (response.status === 429) {
|
|
23685
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("Retry-After"), now());
|
|
23686
|
+
release();
|
|
23687
|
+
return {
|
|
23688
|
+
status: "unavailable",
|
|
23689
|
+
reason: "rateLimited",
|
|
23690
|
+
...retryAfterMs === null ? {} : { retryAfterMs }
|
|
23691
|
+
};
|
|
23692
|
+
}
|
|
23693
|
+
if (response.status === 401 || response.status === 403) {
|
|
23694
|
+
release();
|
|
23695
|
+
return { status: "unavailable", reason: "authRejected" };
|
|
23696
|
+
}
|
|
23697
|
+
if (response.status < 200 || response.status >= 300) {
|
|
23698
|
+
release();
|
|
23699
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
23700
|
+
}
|
|
23701
|
+
let body;
|
|
23702
|
+
try {
|
|
23703
|
+
body = JSON.parse(await response.text());
|
|
23704
|
+
} catch {
|
|
23705
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
23706
|
+
}
|
|
23707
|
+
if (!isRecord6(body)) return { status: "unavailable", reason: "unreachable" };
|
|
23708
|
+
const plan = claudePlanName(credential);
|
|
23709
|
+
return {
|
|
23710
|
+
status: "available",
|
|
23711
|
+
...plan === void 0 ? {} : { plan },
|
|
23712
|
+
windows: readWindows(body),
|
|
23713
|
+
balances: [],
|
|
23714
|
+
accountKey: credential.path
|
|
23715
|
+
};
|
|
23716
|
+
};
|
|
23717
|
+
|
|
23718
|
+
// src/usageRead/scanCache.ts
|
|
23719
|
+
import * as NodePath11 from "node:path";
|
|
23720
|
+
|
|
23721
|
+
// src/usageRead/transcriptScan.ts
|
|
23722
|
+
import * as NodeFS5 from "node:fs";
|
|
23723
|
+
import * as NodePath10 from "node:path";
|
|
23724
|
+
|
|
23725
|
+
// src/usageRead/transcriptLine.ts
|
|
23726
|
+
var int = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
|
|
23727
|
+
var parseTimestampMs = (value) => {
|
|
23728
|
+
if (typeof value !== "string") return null;
|
|
23729
|
+
const parsed = Date.parse(value);
|
|
23730
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
23731
|
+
};
|
|
23732
|
+
var mightCarryUsage = (line) => line.includes('"usage"');
|
|
23733
|
+
var parseClaudeLine = (line) => {
|
|
23734
|
+
let parsed;
|
|
23735
|
+
try {
|
|
23736
|
+
parsed = JSON.parse(line);
|
|
23737
|
+
} catch {
|
|
23738
|
+
return null;
|
|
23739
|
+
}
|
|
23740
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
23741
|
+
const record = parsed;
|
|
23742
|
+
if (record["type"] !== "assistant") return null;
|
|
23743
|
+
const message = record["message"];
|
|
23744
|
+
if (typeof message !== "object" || message === null) return null;
|
|
23745
|
+
const messageRecord = message;
|
|
23746
|
+
const usage = messageRecord["usage"];
|
|
23747
|
+
if (typeof usage !== "object" || usage === null) return null;
|
|
23748
|
+
const usageRecord = usage;
|
|
23749
|
+
const timestampMs = parseTimestampMs(record["timestamp"]);
|
|
23750
|
+
if (timestampMs === null) return null;
|
|
23751
|
+
const model = typeof messageRecord["model"] === "string" ? messageRecord["model"] : "";
|
|
23752
|
+
if (model.length === 0) return null;
|
|
23753
|
+
const messageId = typeof messageRecord["id"] === "string" ? messageRecord["id"] : null;
|
|
23754
|
+
const requestId = typeof record["requestId"] === "string" ? record["requestId"] : null;
|
|
23755
|
+
const dedupeKey = messageId === null && requestId === null ? null : `${messageId ?? ""}:${requestId ?? ""}`;
|
|
23756
|
+
const cost = record["costUSD"];
|
|
23757
|
+
return {
|
|
23758
|
+
timestampMs,
|
|
23759
|
+
model,
|
|
23760
|
+
sessionId: typeof record["sessionId"] === "string" ? record["sessionId"] : "",
|
|
23761
|
+
totals: {
|
|
23762
|
+
uncachedInputTokens: int(usageRecord["input_tokens"]),
|
|
23763
|
+
cachedInputTokens: int(usageRecord["cache_read_input_tokens"]),
|
|
23764
|
+
cacheCreationTokens: int(usageRecord["cache_creation_input_tokens"]),
|
|
23765
|
+
outputTokens: int(usageRecord["output_tokens"]),
|
|
23766
|
+
reasoningTokens: 0
|
|
23767
|
+
},
|
|
23768
|
+
reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
|
|
23769
|
+
dedupeKey
|
|
23770
|
+
};
|
|
23771
|
+
};
|
|
23772
|
+
|
|
23773
|
+
// src/usageRead/transcriptScan.ts
|
|
23774
|
+
var TRANSCRIPT_SUFFIX2 = ".jsonl";
|
|
23775
|
+
async function listTranscriptFiles2(root, sinceMs) {
|
|
23776
|
+
const found = [];
|
|
23777
|
+
const walk = async (dir) => {
|
|
23778
|
+
let entries;
|
|
23779
|
+
try {
|
|
23780
|
+
entries = await NodeFS5.promises.readdir(dir, { withFileTypes: true });
|
|
23781
|
+
} catch {
|
|
23782
|
+
return;
|
|
23783
|
+
}
|
|
23784
|
+
for (const entry of entries) {
|
|
23785
|
+
const child = NodePath10.join(dir, entry.name);
|
|
23786
|
+
if (entry.isDirectory()) {
|
|
23787
|
+
await walk(child);
|
|
23788
|
+
continue;
|
|
23789
|
+
}
|
|
23790
|
+
if (!entry.isFile() || !entry.name.endsWith(TRANSCRIPT_SUFFIX2)) continue;
|
|
23791
|
+
let stat2;
|
|
23792
|
+
try {
|
|
23793
|
+
stat2 = await NodeFS5.promises.stat(child);
|
|
23794
|
+
} catch {
|
|
23795
|
+
continue;
|
|
23796
|
+
}
|
|
23797
|
+
if (stat2.mtimeMs < sinceMs) continue;
|
|
23798
|
+
found.push({ path: child, size: stat2.size, mtimeMs: stat2.mtimeMs });
|
|
23799
|
+
}
|
|
23800
|
+
};
|
|
23801
|
+
await walk(root);
|
|
23802
|
+
return found;
|
|
23803
|
+
}
|
|
23804
|
+
async function statTranscriptRoot(root) {
|
|
23805
|
+
try {
|
|
23806
|
+
const stat2 = await NodeFS5.promises.stat(root);
|
|
23807
|
+
if (!stat2.isDirectory()) return null;
|
|
23808
|
+
return { volumeId: stat2.ino === 0 ? "" : `${String(stat2.dev)}:${String(stat2.ino)}` };
|
|
23809
|
+
} catch {
|
|
23810
|
+
return null;
|
|
23811
|
+
}
|
|
23812
|
+
}
|
|
23813
|
+
var GUARD_LENGTH = 64;
|
|
23814
|
+
var NEWLINE = 10;
|
|
23815
|
+
var CARRIAGE_RETURN = 13;
|
|
23816
|
+
var fnv1a = (bytes) => {
|
|
23817
|
+
let hash = 2166136261;
|
|
23818
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
23819
|
+
hash ^= bytes[index];
|
|
23820
|
+
hash = Math.imul(hash, 16777619);
|
|
23821
|
+
}
|
|
23822
|
+
return hash >>> 0;
|
|
23823
|
+
};
|
|
23824
|
+
var asBuffer = (chunk) => typeof chunk === "string" ? Buffer.from(chunk) : Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
23825
|
+
async function readMatchingGuard(filePath, position) {
|
|
23826
|
+
const { guardLength, resumeOffset } = position;
|
|
23827
|
+
if (guardLength <= 0 || guardLength > GUARD_LENGTH || guardLength > resumeOffset) return null;
|
|
23828
|
+
try {
|
|
23829
|
+
const chunks = [];
|
|
23830
|
+
for await (const chunk of NodeFS5.createReadStream(filePath, {
|
|
23831
|
+
start: resumeOffset - guardLength,
|
|
23832
|
+
end: resumeOffset - 1
|
|
23833
|
+
})) {
|
|
23834
|
+
chunks.push(asBuffer(chunk));
|
|
23835
|
+
}
|
|
23836
|
+
const window2 = Buffer.concat(chunks);
|
|
23837
|
+
return window2.length === guardLength && fnv1a(window2) === position.guardHash ? window2 : null;
|
|
23838
|
+
} catch {
|
|
23839
|
+
return null;
|
|
23840
|
+
}
|
|
23841
|
+
}
|
|
23842
|
+
async function readTranscriptRecords(filePath, resumeFrom) {
|
|
23843
|
+
try {
|
|
23844
|
+
let resumed = false;
|
|
23845
|
+
let start = 0;
|
|
23846
|
+
let guardWindow = Buffer.alloc(0);
|
|
23847
|
+
if (resumeFrom !== void 0 && resumeFrom.resumeOffset > 0) {
|
|
23848
|
+
const window2 = await readMatchingGuard(filePath, resumeFrom);
|
|
23849
|
+
if (window2 !== null) {
|
|
23850
|
+
start = resumeFrom.resumeOffset;
|
|
23851
|
+
guardWindow = window2;
|
|
23852
|
+
resumed = true;
|
|
23853
|
+
}
|
|
23854
|
+
}
|
|
23855
|
+
const parseLine = (line, out) => {
|
|
23856
|
+
if (!mightCarryUsage(line)) return;
|
|
23857
|
+
const record = parseClaudeLine(line);
|
|
23858
|
+
if (record !== null) out.push(record);
|
|
23859
|
+
};
|
|
23860
|
+
const toLineString = (lineBuffer) => {
|
|
23861
|
+
const content = lineBuffer.length > 0 && lineBuffer[lineBuffer.length - 1] === CARRIAGE_RETURN ? lineBuffer.subarray(0, -1) : lineBuffer;
|
|
23862
|
+
return content.toString("utf8");
|
|
23863
|
+
};
|
|
23864
|
+
const records = [];
|
|
23865
|
+
let resumeOffset = start;
|
|
23866
|
+
let pendingChunks = [];
|
|
23867
|
+
for await (const raw of NodeFS5.createReadStream(filePath, start > 0 ? { start } : void 0)) {
|
|
23868
|
+
const chunk = asBuffer(raw);
|
|
23869
|
+
if (!chunk.includes(NEWLINE)) {
|
|
23870
|
+
pendingChunks.push(chunk);
|
|
23871
|
+
continue;
|
|
23872
|
+
}
|
|
23873
|
+
const buffer = pendingChunks.length === 0 ? chunk : Buffer.concat([...pendingChunks, chunk]);
|
|
23874
|
+
pendingChunks = [];
|
|
23875
|
+
let lineStart = 0;
|
|
23876
|
+
for (; ; ) {
|
|
23877
|
+
const newlineIndex = buffer.indexOf(NEWLINE, lineStart);
|
|
23878
|
+
if (newlineIndex === -1) break;
|
|
23879
|
+
parseLine(toLineString(buffer.subarray(lineStart, newlineIndex)), records);
|
|
23880
|
+
lineStart = newlineIndex + 1;
|
|
23881
|
+
}
|
|
23882
|
+
resumeOffset += lineStart;
|
|
23883
|
+
const consumed = buffer.subarray(0, lineStart);
|
|
23884
|
+
guardWindow = consumed.length >= GUARD_LENGTH ? Buffer.from(consumed.subarray(-GUARD_LENGTH)) : Buffer.concat([guardWindow, consumed]).subarray(-GUARD_LENGTH);
|
|
23885
|
+
if (lineStart < buffer.length) pendingChunks.push(buffer.subarray(lineStart));
|
|
23886
|
+
}
|
|
23887
|
+
const tailRecords = [];
|
|
23888
|
+
if (pendingChunks.length > 0) {
|
|
23889
|
+
const pending = pendingChunks.length === 1 ? pendingChunks[0] : Buffer.concat(pendingChunks);
|
|
23890
|
+
if (pending.length > 0) parseLine(toLineString(pending), tailRecords);
|
|
23891
|
+
}
|
|
23892
|
+
return {
|
|
23893
|
+
records,
|
|
23894
|
+
tailRecords,
|
|
23895
|
+
position: {
|
|
23896
|
+
resumeOffset,
|
|
23897
|
+
guardLength: guardWindow.length,
|
|
23898
|
+
guardHash: guardWindow.length > 0 ? fnv1a(guardWindow) : 0
|
|
23899
|
+
},
|
|
23900
|
+
resumed
|
|
23901
|
+
};
|
|
23902
|
+
} catch {
|
|
23903
|
+
return null;
|
|
23904
|
+
}
|
|
23905
|
+
}
|
|
23906
|
+
|
|
23907
|
+
// src/usageRead/scanCache.ts
|
|
23908
|
+
var USAGE_SCAN_CACHE_VERSION = 1;
|
|
23909
|
+
function encodeScanCache(cache) {
|
|
23910
|
+
const models = [];
|
|
23911
|
+
const sessions = [];
|
|
23912
|
+
const modelIndex = /* @__PURE__ */ new Map();
|
|
23913
|
+
const sessionIndex = /* @__PURE__ */ new Map();
|
|
23914
|
+
const intern = (table, index, value) => {
|
|
23915
|
+
const existing = index.get(value);
|
|
23916
|
+
if (existing !== void 0) return existing;
|
|
23917
|
+
const next = table.length;
|
|
23918
|
+
table.push(value);
|
|
23919
|
+
index.set(value, next);
|
|
23920
|
+
return next;
|
|
23921
|
+
};
|
|
23922
|
+
const serializeRecord = (record) => [
|
|
23923
|
+
record.timestampMs,
|
|
23924
|
+
intern(models, modelIndex, record.model),
|
|
23925
|
+
intern(sessions, sessionIndex, record.sessionId),
|
|
23926
|
+
record.totals.uncachedInputTokens,
|
|
23927
|
+
record.totals.cachedInputTokens,
|
|
23928
|
+
record.totals.cacheCreationTokens,
|
|
23929
|
+
record.totals.outputTokens,
|
|
23930
|
+
record.totals.reasoningTokens,
|
|
23931
|
+
record.dedupeKey,
|
|
23932
|
+
record.reportedCostUsd
|
|
23933
|
+
];
|
|
23934
|
+
const files = {};
|
|
23935
|
+
for (const [path, entry] of cache) {
|
|
23936
|
+
files[path] = {
|
|
23937
|
+
s: entry.size,
|
|
23938
|
+
m: entry.mtimeMs,
|
|
23939
|
+
r: entry.records.map(serializeRecord),
|
|
23940
|
+
t: entry.tailRecords.map(serializeRecord),
|
|
23941
|
+
o: entry.position.resumeOffset,
|
|
23942
|
+
gl: entry.position.guardLength,
|
|
23943
|
+
gh: entry.position.guardHash
|
|
23944
|
+
};
|
|
23945
|
+
}
|
|
23946
|
+
return { version: USAGE_SCAN_CACHE_VERSION, models, sessions, files };
|
|
23947
|
+
}
|
|
23948
|
+
function decodeScanCache(document) {
|
|
23949
|
+
const cache = /* @__PURE__ */ new Map();
|
|
23950
|
+
if (typeof document !== "object" || document === null) return cache;
|
|
23951
|
+
const root = document;
|
|
23952
|
+
if (root.version !== USAGE_SCAN_CACHE_VERSION) return cache;
|
|
23953
|
+
if (!Array.isArray(root.models) || !Array.isArray(root.sessions)) return cache;
|
|
23954
|
+
if (typeof root.files !== "object" || root.files === null) return cache;
|
|
23955
|
+
if (!root.models.every((value) => typeof value === "string")) return cache;
|
|
23956
|
+
if (!root.sessions.every((value) => typeof value === "string")) return cache;
|
|
23957
|
+
const models = root.models;
|
|
23958
|
+
const sessions = root.sessions;
|
|
23959
|
+
const decodeRecords = (rows) => {
|
|
23960
|
+
const records = [];
|
|
23961
|
+
for (const row of rows) {
|
|
23962
|
+
if (!Array.isArray(row) || row.length < 10) return null;
|
|
23963
|
+
const [
|
|
23964
|
+
timestampMs,
|
|
23965
|
+
modelIndex,
|
|
23966
|
+
sessionIndex,
|
|
23967
|
+
uncached,
|
|
23968
|
+
cached,
|
|
23969
|
+
cacheCreation,
|
|
23970
|
+
output,
|
|
23971
|
+
reasoning,
|
|
23972
|
+
dedupeKey,
|
|
23973
|
+
reportedCostUsd
|
|
23974
|
+
] = row;
|
|
23975
|
+
const model = typeof modelIndex === "number" ? models[modelIndex] : void 0;
|
|
23976
|
+
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs) || model === void 0 || !Number.isFinite(uncached) || !Number.isFinite(cached) || !Number.isFinite(cacheCreation) || !Number.isFinite(output) || !Number.isFinite(reasoning)) {
|
|
23977
|
+
return null;
|
|
23978
|
+
}
|
|
23979
|
+
records.push({
|
|
23980
|
+
timestampMs,
|
|
23981
|
+
model,
|
|
23982
|
+
sessionId: (typeof sessionIndex === "number" ? sessions[sessionIndex] : void 0) ?? "",
|
|
23983
|
+
totals: {
|
|
23984
|
+
uncachedInputTokens: uncached,
|
|
23985
|
+
cachedInputTokens: cached,
|
|
23986
|
+
cacheCreationTokens: cacheCreation,
|
|
23987
|
+
outputTokens: output,
|
|
23988
|
+
reasoningTokens: reasoning
|
|
23989
|
+
},
|
|
23990
|
+
reportedCostUsd: typeof reportedCostUsd === "number" ? reportedCostUsd : null,
|
|
23991
|
+
dedupeKey: typeof dedupeKey === "string" ? dedupeKey : null
|
|
23992
|
+
});
|
|
23993
|
+
}
|
|
23994
|
+
return records;
|
|
23995
|
+
};
|
|
23996
|
+
for (const [path, raw] of Object.entries(root.files)) {
|
|
23997
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
23998
|
+
const entry = raw;
|
|
23999
|
+
if (typeof entry.s !== "number" || typeof entry.m !== "number") continue;
|
|
24000
|
+
if (!Array.isArray(entry.r) || !Array.isArray(entry.t)) continue;
|
|
24001
|
+
if (typeof entry.o !== "number" || !Number.isSafeInteger(entry.o) || entry.o < 0 || typeof entry.gl !== "number" || !Number.isSafeInteger(entry.gl) || entry.gl < 0 || entry.gl > GUARD_LENGTH || entry.gl > entry.o || typeof entry.gh !== "number" || !Number.isFinite(entry.gh)) {
|
|
24002
|
+
continue;
|
|
24003
|
+
}
|
|
24004
|
+
const records = decodeRecords(entry.r);
|
|
24005
|
+
const tailRecords = decodeRecords(entry.t);
|
|
24006
|
+
if (records === null || tailRecords === null) continue;
|
|
24007
|
+
cache.set(path, {
|
|
24008
|
+
size: entry.s,
|
|
24009
|
+
mtimeMs: entry.m,
|
|
24010
|
+
records,
|
|
24011
|
+
tailRecords,
|
|
24012
|
+
position: { resumeOffset: entry.o, guardLength: entry.gl, guardHash: entry.gh }
|
|
24013
|
+
});
|
|
24014
|
+
}
|
|
24015
|
+
return cache;
|
|
24016
|
+
}
|
|
24017
|
+
function pruneScanCache(cache, options) {
|
|
24018
|
+
let removed = 0;
|
|
24019
|
+
for (const [path, entry] of cache) {
|
|
24020
|
+
const agedOut = entry.mtimeMs < options.retentionCutoffMs;
|
|
24021
|
+
const underWalkedRoot = options.walkedRoots.some((root) => {
|
|
24022
|
+
const relative2 = NodePath11.relative(root, path);
|
|
24023
|
+
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${NodePath11.sep}`) && !NodePath11.isAbsolute(relative2);
|
|
24024
|
+
});
|
|
24025
|
+
const deleted = underWalkedRoot && entry.mtimeMs >= options.windowStartMs && !options.livePaths.has(path);
|
|
24026
|
+
if (agedOut || deleted) {
|
|
24027
|
+
cache.delete(path);
|
|
24028
|
+
removed += 1;
|
|
24029
|
+
}
|
|
24030
|
+
}
|
|
24031
|
+
return removed;
|
|
24032
|
+
}
|
|
24033
|
+
function dedupeWithinFile(records, seen = /* @__PURE__ */ new Set()) {
|
|
24034
|
+
const kept = [];
|
|
24035
|
+
for (const record of records) {
|
|
24036
|
+
if (record.dedupeKey !== null) {
|
|
24037
|
+
if (seen.has(record.dedupeKey)) continue;
|
|
24038
|
+
seen.add(record.dedupeKey);
|
|
24039
|
+
}
|
|
24040
|
+
kept.push(record);
|
|
24041
|
+
}
|
|
24042
|
+
return kept;
|
|
24043
|
+
}
|
|
24044
|
+
|
|
24045
|
+
// src/usageRead/tokenUsage.ts
|
|
24046
|
+
var MTIME_SLACK_MS = 36 * 60 * 60 * 1e3;
|
|
24047
|
+
var CACHE_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
24048
|
+
var SCAN_CACHE_KEY_PREFIX = "claude-usage-scan:";
|
|
24049
|
+
var runtimes = /* @__PURE__ */ new Map();
|
|
24050
|
+
var runtimeFor = (root) => {
|
|
24051
|
+
let runtime = runtimes.get(root);
|
|
24052
|
+
if (runtime === void 0) {
|
|
24053
|
+
runtime = { fileCache: /* @__PURE__ */ new Map(), loaded: void 0, dirty: false, queue: Promise.resolve() };
|
|
24054
|
+
runtimes.set(root, runtime);
|
|
24055
|
+
}
|
|
24056
|
+
return runtime;
|
|
24057
|
+
};
|
|
24058
|
+
var ensureLoaded = (runtime, root, cache) => {
|
|
24059
|
+
runtime.loaded ??= (async () => {
|
|
24060
|
+
if (cache === void 0) return;
|
|
24061
|
+
const cached = await cache.getJson(`${SCAN_CACHE_KEY_PREFIX}${root}`).catch(() => null);
|
|
24062
|
+
if (cached === null) return;
|
|
24063
|
+
for (const [path, entry] of decodeScanCache(cached.value)) runtime.fileCache.set(path, entry);
|
|
24064
|
+
})();
|
|
24065
|
+
return runtime.loaded;
|
|
24066
|
+
};
|
|
24067
|
+
var readFileRecords = async (runtime, filePath, size, mtimeMs) => {
|
|
24068
|
+
const cached = runtime.fileCache.get(filePath);
|
|
24069
|
+
if (cached && cached.size === size && cached.mtimeMs === mtimeMs) {
|
|
24070
|
+
return cached.tailRecords.length === 0 ? cached.records : [...cached.records, ...cached.tailRecords];
|
|
24071
|
+
}
|
|
24072
|
+
const resumeFrom = cached !== void 0 && size > cached.size ? cached.position : void 0;
|
|
24073
|
+
const parsed = await readTranscriptRecords(filePath, resumeFrom);
|
|
24074
|
+
if (parsed === null) return null;
|
|
24075
|
+
const base = parsed.resumed && cached !== void 0 ? cached.records : [];
|
|
24076
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24077
|
+
const records = dedupeWithinFile([...base, ...parsed.records], seen);
|
|
24078
|
+
const tailRecords = dedupeWithinFile(parsed.tailRecords, seen);
|
|
24079
|
+
runtime.fileCache.set(filePath, {
|
|
24080
|
+
size,
|
|
24081
|
+
mtimeMs,
|
|
24082
|
+
records,
|
|
24083
|
+
tailRecords,
|
|
24084
|
+
position: parsed.position
|
|
24085
|
+
});
|
|
24086
|
+
runtime.dirty = true;
|
|
24087
|
+
return tailRecords.length === 0 ? records : [...records, ...tailRecords];
|
|
24088
|
+
};
|
|
24089
|
+
var createClaudeTokenReader = (options) => {
|
|
24090
|
+
const { configDir, transcriptRoot, cache } = options;
|
|
24091
|
+
const scan = async (input) => {
|
|
24092
|
+
const sinceMs = Date.parse(input.since);
|
|
24093
|
+
const untilMs = Date.parse(input.until);
|
|
24094
|
+
if (Number.isNaN(sinceMs) || Number.isNaN(untilMs)) {
|
|
24095
|
+
throw new Error(`readTokenUsage: invalid window '${input.since}'..'${input.until}'`);
|
|
24096
|
+
}
|
|
24097
|
+
const root = await statTranscriptRoot(transcriptRoot);
|
|
24098
|
+
if (root === null) {
|
|
24099
|
+
return {
|
|
24100
|
+
records: [],
|
|
24101
|
+
source: {
|
|
24102
|
+
homePath: configDir,
|
|
24103
|
+
status: "missing",
|
|
24104
|
+
scannedFiles: 0,
|
|
24105
|
+
skippedFiles: 0,
|
|
24106
|
+
message: "No Claude Code session records found on this machine."
|
|
24107
|
+
}
|
|
24108
|
+
};
|
|
24109
|
+
}
|
|
24110
|
+
const runtime = runtimeFor(transcriptRoot);
|
|
24111
|
+
await ensureLoaded(runtime, transcriptRoot, cache);
|
|
24112
|
+
const startedAtMs = Date.now();
|
|
24113
|
+
const windowStartMs = sinceMs - MTIME_SLACK_MS;
|
|
24114
|
+
const files = (await listTranscriptFiles2(transcriptRoot, windowStartMs)).toSorted(
|
|
24115
|
+
(a, b3) => a.path < b3.path ? -1 : a.path > b3.path ? 1 : 0
|
|
24116
|
+
);
|
|
24117
|
+
let scannedFiles = 0;
|
|
24118
|
+
let skippedFiles = 0;
|
|
24119
|
+
let failedFiles = 0;
|
|
24120
|
+
const livePaths = /* @__PURE__ */ new Set();
|
|
24121
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24122
|
+
const records = [];
|
|
24123
|
+
for (const file of files) {
|
|
24124
|
+
input.signal?.throwIfAborted();
|
|
24125
|
+
livePaths.add(file.path);
|
|
24126
|
+
const fileRecords = await readFileRecords(runtime, file.path, file.size, file.mtimeMs);
|
|
24127
|
+
if (fileRecords === null) {
|
|
24128
|
+
failedFiles += 1;
|
|
24129
|
+
continue;
|
|
24130
|
+
}
|
|
24131
|
+
if (fileRecords.length === 0) {
|
|
24132
|
+
skippedFiles += 1;
|
|
24133
|
+
continue;
|
|
23026
24134
|
}
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
|
|
23034
|
-
|
|
24135
|
+
scannedFiles += 1;
|
|
24136
|
+
for (const record of fileRecords) {
|
|
24137
|
+
if (record.dedupeKey !== null) {
|
|
24138
|
+
if (seen.has(record.dedupeKey)) continue;
|
|
24139
|
+
seen.add(record.dedupeKey);
|
|
24140
|
+
}
|
|
24141
|
+
if (record.timestampMs < sinceMs || record.timestampMs >= untilMs) continue;
|
|
24142
|
+
records.push({
|
|
24143
|
+
at: new Date(record.timestampMs).toISOString(),
|
|
24144
|
+
model: record.model,
|
|
24145
|
+
...record.sessionId.length > 0 ? { sessionId: record.sessionId } : {},
|
|
24146
|
+
totals: record.totals,
|
|
24147
|
+
...record.reportedCostUsd === null ? {} : { reportedCostUsd: record.reportedCostUsd }
|
|
23035
24148
|
});
|
|
23036
|
-
const generated = asRecord(
|
|
23037
|
-
await runClaudeJson({
|
|
23038
|
-
operation: "generateBranchName",
|
|
23039
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23040
|
-
prompt,
|
|
23041
|
-
outputSchema,
|
|
23042
|
-
modelSelection: input["modelSelection"],
|
|
23043
|
-
...signal === void 0 ? {} : { signal }
|
|
23044
|
-
}),
|
|
23045
|
-
"generateBranchName"
|
|
23046
|
-
);
|
|
23047
|
-
return { branch: sanitizeBranchFragment(readString3(generated["branch"])) };
|
|
23048
|
-
} catch (error) {
|
|
23049
|
-
throw normalizeCliError("claude", error, "Failed to generate branch name");
|
|
23050
24149
|
}
|
|
23051
|
-
}
|
|
23052
|
-
|
|
24150
|
+
}
|
|
24151
|
+
const pruned = pruneScanCache(runtime.fileCache, {
|
|
24152
|
+
livePaths,
|
|
24153
|
+
walkedRoots: [transcriptRoot],
|
|
24154
|
+
windowStartMs,
|
|
24155
|
+
retentionCutoffMs: startedAtMs - CACHE_RETENTION_MS
|
|
24156
|
+
});
|
|
24157
|
+
if (pruned > 0) runtime.dirty = true;
|
|
24158
|
+
if (runtime.dirty && cache !== void 0) {
|
|
23053
24159
|
try {
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
...typeof input["linkedContext"] === "string" && input["linkedContext"].length > 0 ? { linkedContext: input["linkedContext"] } : {},
|
|
23058
|
-
...typeof input["previousTitle"] === "string" ? { previousTitle: input["previousTitle"] } : {},
|
|
23059
|
-
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
23060
|
-
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23061
|
-
});
|
|
23062
|
-
const generated = asRecord(
|
|
23063
|
-
await runClaudeJson({
|
|
23064
|
-
operation: "generateThreadTitle",
|
|
23065
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23066
|
-
prompt,
|
|
23067
|
-
outputSchema,
|
|
23068
|
-
modelSelection: input["modelSelection"],
|
|
23069
|
-
...signal === void 0 ? {} : { signal }
|
|
23070
|
-
}),
|
|
23071
|
-
"generateThreadTitle"
|
|
24160
|
+
await cache.setJson(
|
|
24161
|
+
`${SCAN_CACHE_KEY_PREFIX}${transcriptRoot}`,
|
|
24162
|
+
encodeScanCache(runtime.fileCache)
|
|
23072
24163
|
);
|
|
23073
|
-
|
|
23074
|
-
|
|
23075
|
-
...generated["needsRefinement"] === true ? { needsRefinement: true } : {}
|
|
23076
|
-
};
|
|
23077
|
-
} catch (error) {
|
|
23078
|
-
throw normalizeCliError("claude", error, "Failed to generate thread title");
|
|
24164
|
+
runtime.dirty = false;
|
|
24165
|
+
} catch {
|
|
23079
24166
|
}
|
|
23080
|
-
}
|
|
23081
|
-
|
|
23082
|
-
|
|
23083
|
-
|
|
23084
|
-
|
|
23085
|
-
|
|
23086
|
-
|
|
23087
|
-
|
|
23088
|
-
|
|
23089
|
-
|
|
23090
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23091
|
-
prompt,
|
|
23092
|
-
outputSchema,
|
|
23093
|
-
modelSelection: input["modelSelection"],
|
|
23094
|
-
...signal === void 0 ? {} : { signal }
|
|
23095
|
-
}),
|
|
23096
|
-
"summarizeHandover"
|
|
23097
|
-
);
|
|
23098
|
-
return { summary: readString3(generated["summary"]).trim() };
|
|
23099
|
-
} catch (error) {
|
|
23100
|
-
throw normalizeCliError("claude", error, "Failed to summarize handover");
|
|
24167
|
+
}
|
|
24168
|
+
return {
|
|
24169
|
+
records,
|
|
24170
|
+
source: {
|
|
24171
|
+
homePath: configDir,
|
|
24172
|
+
volumeId: root.volumeId,
|
|
24173
|
+
status: failedFiles > 0 ? "partial" : "ok",
|
|
24174
|
+
scannedFiles,
|
|
24175
|
+
skippedFiles,
|
|
24176
|
+
...failedFiles > 0 ? { message: `${String(failedFiles)} session record file(s) could not be read.` } : {}
|
|
23101
24177
|
}
|
|
24178
|
+
};
|
|
24179
|
+
};
|
|
24180
|
+
return {
|
|
24181
|
+
readTokenUsage: (input) => {
|
|
24182
|
+
const runtime = runtimeFor(transcriptRoot);
|
|
24183
|
+
const run = runtime.queue.then(() => scan(input));
|
|
24184
|
+
runtime.queue = run.catch(() => void 0);
|
|
24185
|
+
return run;
|
|
23102
24186
|
}
|
|
23103
24187
|
};
|
|
24188
|
+
};
|
|
24189
|
+
|
|
24190
|
+
// src/usageRead/index.ts
|
|
24191
|
+
var createClaudeUsage = (input) => {
|
|
24192
|
+
const { recipe, host } = input;
|
|
24193
|
+
const configDir = resolveClaudeConfigDirPath(recipe.homePath, {
|
|
24194
|
+
...process.env,
|
|
24195
|
+
...recipe.environment
|
|
24196
|
+
});
|
|
24197
|
+
const tokens = createClaudeTokenReader({
|
|
24198
|
+
configDir,
|
|
24199
|
+
transcriptRoot: NodePath12.join(configDir, "projects"),
|
|
24200
|
+
cache: input.cache
|
|
24201
|
+
});
|
|
24202
|
+
return {
|
|
24203
|
+
readQuota: ({ signal }) => readClaudeQuota({ recipe, fetch: host.fetch, signal }),
|
|
24204
|
+
readTokenUsage: tokens.readTokenUsage
|
|
24205
|
+
};
|
|
24206
|
+
};
|
|
24207
|
+
|
|
24208
|
+
// src/claudeSkillDispatch.ts
|
|
24209
|
+
var SKILL_MENTION_PATTERN = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s|$)/g;
|
|
24210
|
+
function planClaudeSkillDispatch(prompt, skillNames) {
|
|
24211
|
+
const mentions = [...prompt.matchAll(SKILL_MENTION_PATTERN)].flatMap((match) => {
|
|
24212
|
+
const name = match[2] ?? "";
|
|
24213
|
+
if (!skillNames.has(name)) return [];
|
|
24214
|
+
const start = (match.index ?? 0) + (match[1]?.length ?? 0);
|
|
24215
|
+
return [{ name, start, end: start + name.length + 1 }];
|
|
24216
|
+
});
|
|
24217
|
+
const last = mentions.at(-1);
|
|
24218
|
+
if (last === void 0) return void 0;
|
|
24219
|
+
const leading = prompt.slice(0, last.start);
|
|
24220
|
+
const trailing = prompt.slice(last.end);
|
|
24221
|
+
const leadingWithInlineSlashes = mentions.slice(0, -1).reduceRight(
|
|
24222
|
+
(text, mention) => `${text.slice(0, mention.start)}/${text.slice(mention.start + 1)}`,
|
|
24223
|
+
leading
|
|
24224
|
+
).trimEnd();
|
|
24225
|
+
return {
|
|
24226
|
+
leadingText: leadingWithInlineSlashes.length > 0 ? leadingWithInlineSlashes : void 0,
|
|
24227
|
+
commandText: `/${last.name}${trailing}`.trimEnd(),
|
|
24228
|
+
skillName: last.name
|
|
24229
|
+
};
|
|
23104
24230
|
}
|
|
23105
24231
|
|
|
23106
24232
|
// src/imageMime.ts
|
|
@@ -23183,9 +24309,9 @@ var PromptQueue = class {
|
|
|
23183
24309
|
const queued = this.#queued.shift();
|
|
23184
24310
|
if (queued !== void 0) return Promise.resolve(queued);
|
|
23185
24311
|
if (this.#closed) return Promise.resolve(void 0);
|
|
23186
|
-
return new Promise((
|
|
24312
|
+
return new Promise((resolve4) => {
|
|
23187
24313
|
this.#waiters.push((result) => {
|
|
23188
|
-
|
|
24314
|
+
resolve4(result.done ? void 0 : result.value);
|
|
23189
24315
|
});
|
|
23190
24316
|
});
|
|
23191
24317
|
}
|
|
@@ -23266,6 +24392,10 @@ function nativeProviderRefs(_context, options) {
|
|
|
23266
24392
|
}
|
|
23267
24393
|
async function buildUserMessageFromTurn(input) {
|
|
23268
24394
|
const sdkContent = [];
|
|
24395
|
+
const dispatch = input.skillNames === void 0 ? void 0 : planClaudeSkillDispatch(input.text, input.skillNames);
|
|
24396
|
+
if (dispatch?.leadingText !== void 0) {
|
|
24397
|
+
sdkContent.push({ type: "text", text: dispatch.leadingText });
|
|
24398
|
+
}
|
|
23269
24399
|
for (const attachment of input.attachments ?? []) {
|
|
23270
24400
|
if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) continue;
|
|
23271
24401
|
const rec = attachment;
|
|
@@ -23284,7 +24414,9 @@ async function buildUserMessageFromTurn(input) {
|
|
|
23284
24414
|
const bytes = await input.attachmentsApi.read(id2);
|
|
23285
24415
|
sdkContent.push(buildClaudeImageContentBlock({ mimeType, bytes }));
|
|
23286
24416
|
}
|
|
23287
|
-
if (
|
|
24417
|
+
if (dispatch !== void 0) {
|
|
24418
|
+
sdkContent.push({ type: "text", text: dispatch.commandText });
|
|
24419
|
+
} else if (input.text.length > 0) {
|
|
23288
24420
|
sdkContent.push({ type: "text", text: input.text });
|
|
23289
24421
|
}
|
|
23290
24422
|
return buildUserMessage({ sdkContent });
|
|
@@ -23304,10 +24436,10 @@ async function persistProducedImage(input) {
|
|
|
23304
24436
|
}
|
|
23305
24437
|
|
|
23306
24438
|
// src/claudeInstance.ts
|
|
23307
|
-
function compactEnv(
|
|
24439
|
+
function compactEnv(env2) {
|
|
23308
24440
|
const out = {};
|
|
23309
|
-
if (!
|
|
23310
|
-
for (const [key, value] of Object.entries(
|
|
24441
|
+
if (!env2) return out;
|
|
24442
|
+
for (const [key, value] of Object.entries(env2)) {
|
|
23311
24443
|
if (value !== void 0) out[key] = value;
|
|
23312
24444
|
}
|
|
23313
24445
|
return out;
|
|
@@ -23329,7 +24461,6 @@ function toClaudeMcpServers(entries) {
|
|
|
23329
24461
|
}
|
|
23330
24462
|
return servers;
|
|
23331
24463
|
}
|
|
23332
|
-
var CLAUDE_PROGRAM_NOT_CONFIGURED = "Claude program path is not configured";
|
|
23333
24464
|
function createClaudeAdapter(recipe, host, options) {
|
|
23334
24465
|
const boundInstanceId = options?.instanceId ?? host.instanceId ?? "claudeAgent";
|
|
23335
24466
|
const claudeHomeEnvironment = makeClaudeEnvironment(recipe, options?.environment);
|
|
@@ -23345,7 +24476,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
23345
24476
|
if (recipe.binaryPath.length === 0) throw new Error(CLAUDE_PROGRAM_NOT_CONFIGURED);
|
|
23346
24477
|
return sdkCreateQuery(input);
|
|
23347
24478
|
};
|
|
23348
|
-
const buildLaunchEnvironment = () =>
|
|
24479
|
+
const buildLaunchEnvironment = () => mergeLaunchEnv3({
|
|
23349
24480
|
inherited: { ...process.env, ...options?.environment },
|
|
23350
24481
|
instanceTable: recipe.environment,
|
|
23351
24482
|
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
@@ -23738,7 +24869,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
23738
24869
|
compactedSinceLatestAssistantUsage: false,
|
|
23739
24870
|
retrying: false,
|
|
23740
24871
|
authenticationFailed: false,
|
|
23741
|
-
nextSyntheticAssistantBlockIndex: -1
|
|
24872
|
+
nextSyntheticAssistantBlockIndex: -1,
|
|
24873
|
+
rejectedRateLimits: /* @__PURE__ */ new Map(),
|
|
24874
|
+
announcedUsageLimits: /* @__PURE__ */ new Set(),
|
|
24875
|
+
latestAssistantRateLimited: false
|
|
23742
24876
|
};
|
|
23743
24877
|
context.session = {
|
|
23744
24878
|
...context.session,
|
|
@@ -24325,6 +25459,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24325
25459
|
if (message.type !== "assistant") {
|
|
24326
25460
|
return;
|
|
24327
25461
|
}
|
|
25462
|
+
const rateLimitParent = message.parent_tool_use_id;
|
|
25463
|
+
if (context.turnState && (rateLimitParent === null || rateLimitParent === void 0)) {
|
|
25464
|
+
context.turnState.latestAssistantRateLimited = message.error === "rate_limit";
|
|
25465
|
+
}
|
|
24328
25466
|
if (isClaudeSyntheticApiErrorMessage(message)) {
|
|
24329
25467
|
if (context.turnState && message.error === "authentication_failed") {
|
|
24330
25468
|
context.turnState.authenticationFailed = true;
|
|
@@ -24396,14 +25534,22 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24396
25534
|
return;
|
|
24397
25535
|
}
|
|
24398
25536
|
context.compactionInProgress = false;
|
|
24399
|
-
const
|
|
25537
|
+
const outcome = resultOutcome(
|
|
24400
25538
|
message,
|
|
24401
25539
|
claudeFailureHint({
|
|
24402
25540
|
authenticationFailed: context.turnState?.authenticationFailed === true,
|
|
24403
25541
|
environment: buildLaunchEnvironment(),
|
|
24404
|
-
cwd:
|
|
25542
|
+
cwd: NodePath13.resolve(context.session.cwd ?? "."),
|
|
25543
|
+
...context.turnState === void 0 ? {} : {
|
|
25544
|
+
usageLimit: {
|
|
25545
|
+
rejected: context.turnState.rejectedRateLimits,
|
|
25546
|
+
latestAssistantRateLimited: context.turnState.latestAssistantRateLimited,
|
|
25547
|
+
nowMs: Date.now()
|
|
25548
|
+
}
|
|
25549
|
+
}
|
|
24405
25550
|
})
|
|
24406
25551
|
);
|
|
25552
|
+
const { status, errorMessage } = outcome;
|
|
24407
25553
|
if (status === "failed") {
|
|
24408
25554
|
await emitRuntimeError(context, errorMessage ?? "Claude turn failed.");
|
|
24409
25555
|
}
|
|
@@ -24510,7 +25656,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24510
25656
|
}
|
|
24511
25657
|
}
|
|
24512
25658
|
switch (message.subtype) {
|
|
24513
|
-
case "init":
|
|
25659
|
+
case "init": {
|
|
24514
25660
|
offerRuntimeEvent(context, {
|
|
24515
25661
|
...base,
|
|
24516
25662
|
type: "session.configured",
|
|
@@ -24518,6 +25664,27 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24518
25664
|
config: message
|
|
24519
25665
|
}
|
|
24520
25666
|
});
|
|
25667
|
+
const threadId = context.session.threadId;
|
|
25668
|
+
const names = claudeSlashCommandsFromNames(message.slash_commands);
|
|
25669
|
+
if (names.length > 0) host.reportSessionInventory?.({ threadId, slashCommands: names });
|
|
25670
|
+
void context.query.supportedCommands?.().then(
|
|
25671
|
+
(commands) => {
|
|
25672
|
+
const detailed = claudeSlashCommandsFromSdk(commands);
|
|
25673
|
+
if (detailed.length > 0) {
|
|
25674
|
+
host.reportSessionInventory?.({ threadId, slashCommands: detailed });
|
|
25675
|
+
}
|
|
25676
|
+
},
|
|
25677
|
+
() => void 0
|
|
25678
|
+
);
|
|
25679
|
+
return;
|
|
25680
|
+
}
|
|
25681
|
+
case "commands_changed":
|
|
25682
|
+
if (Array.isArray(message.commands)) {
|
|
25683
|
+
host.reportSessionInventory?.({
|
|
25684
|
+
threadId: context.session.threadId,
|
|
25685
|
+
slashCommands: claudeSlashCommandsFromSdk(message.commands)
|
|
25686
|
+
});
|
|
25687
|
+
}
|
|
24521
25688
|
return;
|
|
24522
25689
|
case "status": {
|
|
24523
25690
|
const compacting = message.status === "compacting";
|
|
@@ -24825,7 +25992,6 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24825
25992
|
// deliberately so they don't masquerade as unknown-subtype warnings.
|
|
24826
25993
|
case "local_command_output":
|
|
24827
25994
|
case "plugin_install":
|
|
24828
|
-
case "commands_changed":
|
|
24829
25995
|
case "memory_recall":
|
|
24830
25996
|
case "elicitation_complete":
|
|
24831
25997
|
return;
|
|
@@ -24925,6 +26091,25 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24925
26091
|
rateLimits: message
|
|
24926
26092
|
}
|
|
24927
26093
|
});
|
|
26094
|
+
const info = message.rate_limit_info;
|
|
26095
|
+
const turn = context.turnState;
|
|
26096
|
+
if (info && turn) {
|
|
26097
|
+
const type4 = info.rateLimitType ?? "unknown";
|
|
26098
|
+
if (isBlockingRateLimit(info)) {
|
|
26099
|
+
turn.rejectedRateLimits.set(type4, info.resetsAt);
|
|
26100
|
+
const key = rateLimitKey(info);
|
|
26101
|
+
if (!turn.announcedUsageLimits.has(key)) {
|
|
26102
|
+
turn.announcedUsageLimits.add(key);
|
|
26103
|
+
await emitRuntimeWarning(
|
|
26104
|
+
context,
|
|
26105
|
+
describeUsageLimitPause(info, Date.parse(stamp.createdAt)),
|
|
26106
|
+
info
|
|
26107
|
+
);
|
|
26108
|
+
}
|
|
26109
|
+
} else if (isClearingRateLimit(info)) {
|
|
26110
|
+
turn.rejectedRateLimits.delete(type4);
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
24928
26113
|
return;
|
|
24929
26114
|
}
|
|
24930
26115
|
};
|
|
@@ -25071,7 +26256,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25071
26256
|
if (streamFiber) {
|
|
25072
26257
|
await Promise.race([
|
|
25073
26258
|
streamFiber.catch(() => void 0),
|
|
25074
|
-
new Promise((
|
|
26259
|
+
new Promise((resolve4) => setTimeout(resolve4, 1e3))
|
|
25075
26260
|
]);
|
|
25076
26261
|
}
|
|
25077
26262
|
const updatedAt = nowIso();
|
|
@@ -25282,7 +26467,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25282
26467
|
return await Promise.race([
|
|
25283
26468
|
contextDeferred.promise,
|
|
25284
26469
|
new Promise(
|
|
25285
|
-
(
|
|
26470
|
+
(resolve4) => setTimeout(() => resolve4(void 0), CLAUDE_SESSION_CONTEXT_WAIT_MS)
|
|
25286
26471
|
)
|
|
25287
26472
|
]);
|
|
25288
26473
|
} catch {
|
|
@@ -25817,7 +27002,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25817
27002
|
compactedSinceLatestAssistantUsage: false,
|
|
25818
27003
|
retrying: false,
|
|
25819
27004
|
authenticationFailed: false,
|
|
25820
|
-
nextSyntheticAssistantBlockIndex: -1
|
|
27005
|
+
nextSyntheticAssistantBlockIndex: -1,
|
|
27006
|
+
rejectedRateLimits: /* @__PURE__ */ new Map(),
|
|
27007
|
+
announcedUsageLimits: /* @__PURE__ */ new Set(),
|
|
27008
|
+
latestAssistantRateLimited: false
|
|
25821
27009
|
};
|
|
25822
27010
|
const updatedAt = nowIso();
|
|
25823
27011
|
context.turnState = turnState;
|
|
@@ -25839,10 +27027,18 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25839
27027
|
providerRefs: {}
|
|
25840
27028
|
});
|
|
25841
27029
|
}
|
|
27030
|
+
const cliEnvironment = { ...process.env, ...recipe.environment };
|
|
27031
|
+
const skills = await discoverClaudeSkills(
|
|
27032
|
+
resolveClaudeConfigDirPath(recipe.homePath, cliEnvironment, context.session.cwd),
|
|
27033
|
+
{ environment: cliEnvironment, ...context.session.cwd ? { cwd: context.session.cwd } : {} }
|
|
27034
|
+
);
|
|
25842
27035
|
const message = await buildUserMessageFromTurn({
|
|
25843
27036
|
text: buildPromptText(turnCapsForPrompt, input, boundInstanceId),
|
|
25844
27037
|
attachments: input.attachments,
|
|
25845
|
-
attachmentsApi: options?.attachments
|
|
27038
|
+
attachmentsApi: options?.attachments,
|
|
27039
|
+
skillNames: new Set(
|
|
27040
|
+
skills.filter((skill) => skill.enabled && skill.userInvocable !== false).map((skill) => skill.name)
|
|
27041
|
+
)
|
|
25846
27042
|
});
|
|
25847
27043
|
validateSteeringTarget();
|
|
25848
27044
|
context.promptQueue.push({
|
|
@@ -25870,7 +27066,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25870
27066
|
context.query.interrupt().then(() => settled.promise).then(() => {
|
|
25871
27067
|
acknowledged = true;
|
|
25872
27068
|
}),
|
|
25873
|
-
new Promise((
|
|
27069
|
+
new Promise((resolve4) => setTimeout(resolve4, CLAUDE_INTERRUPT_GRACE_MS))
|
|
25874
27070
|
]);
|
|
25875
27071
|
} catch (cause) {
|
|
25876
27072
|
throw toRequestError(threadId, "turn/interrupt", cause);
|
|
@@ -26000,7 +27196,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
26000
27196
|
function claudeAdapterBaseEnvironment(recipe) {
|
|
26001
27197
|
return { ...process.env, ...recipe.environment };
|
|
26002
27198
|
}
|
|
26003
|
-
function createClaudeInstance(config, host, attachments, overrides) {
|
|
27199
|
+
function createClaudeInstance(config, host, attachments, overrides, usageCache) {
|
|
26004
27200
|
const recipe = parseClaudeInstanceConfig(config);
|
|
26005
27201
|
const adapter = createClaudeAdapter(recipe, host, {
|
|
26006
27202
|
instanceId: host.instanceId,
|
|
@@ -26009,118 +27205,7 @@ function createClaudeInstance(config, host, attachments, overrides) {
|
|
|
26009
27205
|
environment: claudeAdapterBaseEnvironment(recipe),
|
|
26010
27206
|
log: host.log
|
|
26011
27207
|
});
|
|
26012
|
-
const
|
|
26013
|
-
const chunks = [];
|
|
26014
|
-
for await (const chunk of stream) {
|
|
26015
|
-
chunks.push(Buffer.from(chunk));
|
|
26016
|
-
}
|
|
26017
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
26018
|
-
};
|
|
26019
|
-
const probeAuth = () => {
|
|
26020
|
-
const hasEnvToken = (recipe.environment.ANTHROPIC_AUTH_TOKEN ?? "").trim().length > 0;
|
|
26021
|
-
const hasEnvApiKey = (recipe.environment.ANTHROPIC_API_KEY ?? "").trim().length > 0;
|
|
26022
|
-
if (hasEnvToken || hasEnvApiKey) {
|
|
26023
|
-
return {
|
|
26024
|
-
status: "authenticated",
|
|
26025
|
-
type: hasEnvToken ? "env-token" : "api-key",
|
|
26026
|
-
label: hasEnvToken ? "ANTHROPIC_AUTH_TOKEN" : "ANTHROPIC_API_KEY"
|
|
26027
|
-
};
|
|
26028
|
-
}
|
|
26029
|
-
const account = readClaudeAccount(resolveClaudeCredentialsDirPath(recipe.credentialsPath));
|
|
26030
|
-
switch (account.state) {
|
|
26031
|
-
case "signed-in":
|
|
26032
|
-
case "expired":
|
|
26033
|
-
return { status: "authenticated" };
|
|
26034
|
-
case "signed-out":
|
|
26035
|
-
return { status: "unauthenticated" };
|
|
26036
|
-
case "unreadable":
|
|
26037
|
-
return { status: "unknown" };
|
|
26038
|
-
}
|
|
26039
|
-
};
|
|
26040
|
-
let lastProbedVersion;
|
|
26041
|
-
const probe = async (signal) => {
|
|
26042
|
-
if (recipe.binaryPath.length === 0) {
|
|
26043
|
-
return {
|
|
26044
|
-
installed: false,
|
|
26045
|
-
version: null,
|
|
26046
|
-
readiness: "not-installed",
|
|
26047
|
-
auth: { status: "unknown" },
|
|
26048
|
-
detail: CLAUDE_PROGRAM_NOT_CONFIGURED
|
|
26049
|
-
};
|
|
26050
|
-
}
|
|
26051
|
-
if (signal?.aborted) {
|
|
26052
|
-
throw new Error("aborted");
|
|
26053
|
-
}
|
|
26054
|
-
let handle;
|
|
26055
|
-
try {
|
|
26056
|
-
handle = await host.process.spawn({
|
|
26057
|
-
program: recipe.binaryPath,
|
|
26058
|
-
args: ["--version"],
|
|
26059
|
-
owner: { bindingId: host.bindingId }
|
|
26060
|
-
});
|
|
26061
|
-
} catch (error) {
|
|
26062
|
-
if (error instanceof ExecutorSpawnRefusedError) throw error;
|
|
26063
|
-
const failure = describeExecutorSpawnFailure(error);
|
|
26064
|
-
return {
|
|
26065
|
-
installed: false,
|
|
26066
|
-
version: null,
|
|
26067
|
-
readiness: failure.readiness,
|
|
26068
|
-
auth: { status: "unknown" },
|
|
26069
|
-
detail: failure.detail
|
|
26070
|
-
};
|
|
26071
|
-
}
|
|
26072
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
26073
|
-
collectProcessText(handle.stdout),
|
|
26074
|
-
collectProcessText(handle.stderr),
|
|
26075
|
-
handle.exited
|
|
26076
|
-
]);
|
|
26077
|
-
const version = parseGenericCliVersion(`${stdout}
|
|
26078
|
-
${stderr}`);
|
|
26079
|
-
if (version !== null || exitCode === 0) {
|
|
26080
|
-
await adapter.modelCatalog.refresh({ signal, force: version !== lastProbedVersion });
|
|
26081
|
-
lastProbedVersion = version;
|
|
26082
|
-
}
|
|
26083
|
-
const models = claudeProbeModels({
|
|
26084
|
-
catalog: adapter.modelCatalog.current(),
|
|
26085
|
-
customModels: recipe.customModels
|
|
26086
|
-
});
|
|
26087
|
-
const auth = probeAuth();
|
|
26088
|
-
const skills = await discoverClaudeSkills(
|
|
26089
|
-
resolveClaudeConfigDirPath(recipe.homePath, { ...process.env, ...recipe.environment })
|
|
26090
|
-
);
|
|
26091
|
-
if (exitCode !== 0 && version === null) {
|
|
26092
|
-
const detail = (stderr || stdout || "claude --version failed").trim();
|
|
26093
|
-
return {
|
|
26094
|
-
installed: false,
|
|
26095
|
-
version: null,
|
|
26096
|
-
readiness: "error",
|
|
26097
|
-
auth,
|
|
26098
|
-
...detail.length > 0 ? { detail } : {}
|
|
26099
|
-
};
|
|
26100
|
-
}
|
|
26101
|
-
if (auth.status === "unauthenticated") {
|
|
26102
|
-
return {
|
|
26103
|
-
installed: true,
|
|
26104
|
-
version,
|
|
26105
|
-
readiness: "error",
|
|
26106
|
-
auth,
|
|
26107
|
-
models,
|
|
26108
|
-
skills,
|
|
26109
|
-
detail: "Claude is signed out",
|
|
26110
|
-
// 退出登录了档位照样是那五档。不报就退回宿主四档,而那份映射少了 `plan`。
|
|
26111
|
-
...CLAUDE_NATIVE_MODE_REPORT
|
|
26112
|
-
};
|
|
26113
|
-
}
|
|
26114
|
-
return {
|
|
26115
|
-
installed: true,
|
|
26116
|
-
version,
|
|
26117
|
-
readiness: "ready",
|
|
26118
|
-
auth,
|
|
26119
|
-
models,
|
|
26120
|
-
skills,
|
|
26121
|
-
...CLAUDE_NATIVE_MODE_REPORT
|
|
26122
|
-
};
|
|
26123
|
-
};
|
|
27208
|
+
const probe = createClaudeProbe({ recipe, host, modelCatalog: adapter.modelCatalog });
|
|
26124
27209
|
const resolveTranscriptRoots = (directory) => {
|
|
26125
27210
|
const configDir = resolveClaudeConfigDirPath(
|
|
26126
27211
|
recipe.homePath,
|
|
@@ -26129,7 +27214,7 @@ ${stderr}`);
|
|
|
26129
27214
|
);
|
|
26130
27215
|
return {
|
|
26131
27216
|
configDir,
|
|
26132
|
-
transcriptDir:
|
|
27217
|
+
transcriptDir: NodePath13.join(configDir, "projects")
|
|
26133
27218
|
};
|
|
26134
27219
|
};
|
|
26135
27220
|
return {
|
|
@@ -26146,8 +27231,18 @@ ${stderr}`);
|
|
|
26146
27231
|
readThread: adapter.readThread,
|
|
26147
27232
|
events: adapter.events,
|
|
26148
27233
|
dispose: adapter.dispose,
|
|
27234
|
+
// 项目里的命令与技能:探测没有工作区,只能报用户配置目录那份;这里按目录扫。
|
|
27235
|
+
workspaceInventory: ({ cwd }) => {
|
|
27236
|
+
const cliEnvironment = { ...process.env, ...recipe.environment };
|
|
27237
|
+
return discoverClaudeWorkspaceInventory({
|
|
27238
|
+
configDirPath: resolveClaudeConfigDirPath(recipe.homePath, cliEnvironment, cwd),
|
|
27239
|
+
cwd,
|
|
27240
|
+
environment: cliEnvironment
|
|
27241
|
+
});
|
|
27242
|
+
},
|
|
26149
27243
|
textGeneration: createClaudeTextGeneration(recipe, host, adapter.modelCatalog.current),
|
|
26150
27244
|
continuationKey: claudeContinuationKey(recipe.homePath),
|
|
27245
|
+
usage: createClaudeUsage({ recipe, host, cache: usageCache }),
|
|
26151
27246
|
sessions: {
|
|
26152
27247
|
scan: async (input) => {
|
|
26153
27248
|
const roots = resolveTranscriptRoots(input.directory);
|
|
@@ -26188,12 +27283,13 @@ ${stderr}`);
|
|
|
26188
27283
|
|
|
26189
27284
|
// src/index.ts
|
|
26190
27285
|
var capturedAttachments;
|
|
27286
|
+
var capturedCache;
|
|
26191
27287
|
var executors = [
|
|
26192
27288
|
{
|
|
26193
27289
|
card: CLAUDE_CARD,
|
|
26194
27290
|
createInstance: async (config, host) => {
|
|
26195
27291
|
host.log.info("createInstance");
|
|
26196
|
-
return createClaudeInstance(config, host, capturedAttachments);
|
|
27292
|
+
return createClaudeInstance(config, host, capturedAttachments, void 0, capturedCache);
|
|
26197
27293
|
}
|
|
26198
27294
|
}
|
|
26199
27295
|
];
|
|
@@ -26203,6 +27299,7 @@ var index_default = definePlugin({
|
|
|
26203
27299
|
executors,
|
|
26204
27300
|
activate(ctx) {
|
|
26205
27301
|
capturedAttachments = ctx.attachments;
|
|
27302
|
+
capturedCache = ctx.cache;
|
|
26206
27303
|
ctx.log.info("claude executor ready");
|
|
26207
27304
|
}
|
|
26208
27305
|
});
|