@ycodium-ai/agent-claude 0.2.2690 → 0.2.2696
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 +1676 -764
- package/locales/en.json +6 -0
- package/locales/zh-CN.json +6 -0
- package/package.json +2 -2
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,18 @@ 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, platform2) {
|
|
19904
|
-
const command = "claude auth login";
|
|
19905
|
-
const credentialsDirPath = resolveClaudeCredentialsDirPath(credentialsPath);
|
|
19906
|
-
if (credentialsDirPath === null) return command;
|
|
19907
|
-
return withClaudeCredentialsDir({ command, credentialsDirPath, platform: platform2 });
|
|
19908
|
-
}
|
|
19909
|
-
|
|
19910
19891
|
// src/claudeSkills.ts
|
|
19911
19892
|
import * as NodeFSP from "node:fs/promises";
|
|
19912
|
-
import * as
|
|
19893
|
+
import * as NodePath4 from "node:path";
|
|
19913
19894
|
import * as NodeProcess from "node:process";
|
|
19914
|
-
var FRONT_MATTER_KEY = /^(description|disable-model-invocation|user-invocable):[ \t]*(.*)$/;
|
|
19895
|
+
var FRONT_MATTER_KEY = /^(description|disable-model-invocation|user-invocable|argument-hint):[ \t]*(.*)$/;
|
|
19915
19896
|
var BLOCK_SCALAR = /^[|>][+-]?$/;
|
|
19916
19897
|
function parseFrontMatterBoolean(value) {
|
|
19917
19898
|
switch (value?.trim().toLowerCase()) {
|
|
@@ -19952,14 +19933,16 @@ function parseSkillFrontMatter(contents) {
|
|
|
19952
19933
|
}
|
|
19953
19934
|
value = block.join(value.startsWith("|") ? "\n" : " ");
|
|
19954
19935
|
} else {
|
|
19955
|
-
if (key !== "description") value = value.replace(/\s+#.*$/, "");
|
|
19936
|
+
if (key !== "description" && key !== "argument-hint") value = value.replace(/\s+#.*$/, "");
|
|
19956
19937
|
value = value.replace(/^(["'])(.*)\1$/, "$2").trim();
|
|
19957
19938
|
}
|
|
19958
19939
|
if (value.length > 0 && values[key] === void 0) values[key] = value;
|
|
19959
19940
|
}
|
|
19960
19941
|
const description = values["description"];
|
|
19942
|
+
const argumentHint = values["argument-hint"];
|
|
19961
19943
|
return {
|
|
19962
19944
|
...description === void 0 ? {} : { description },
|
|
19945
|
+
...argumentHint === void 0 ? {} : { argumentHint },
|
|
19963
19946
|
...parseFrontMatterBoolean(values["disable-model-invocation"]) === true ? { userInvocationOnly: true } : {},
|
|
19964
19947
|
...parseFrontMatterBoolean(values["user-invocable"]) === false ? { userInvocable: false } : {}
|
|
19965
19948
|
};
|
|
@@ -19970,7 +19953,7 @@ function claudeManagedSettingsPath(platform2, environment) {
|
|
|
19970
19953
|
}
|
|
19971
19954
|
if (platform2 === "win32") {
|
|
19972
19955
|
const programData = environment["PROGRAMDATA"]?.trim();
|
|
19973
|
-
return programData ?
|
|
19956
|
+
return programData ? NodePath4.join(programData, "ClaudeCode", "managed-settings.json") : void 0;
|
|
19974
19957
|
}
|
|
19975
19958
|
return "/etc/claude-code/managed-settings.json";
|
|
19976
19959
|
}
|
|
@@ -19978,24 +19961,24 @@ function skillOverrideSettingsPaths(configDirPath, cwd, platform2, environment,
|
|
|
19978
19961
|
const managedPath = claudeManagedSettingsPath(platform2, environment);
|
|
19979
19962
|
const root = repositoryRoot !== void 0 && repositoryRoot !== cwd ? repositoryRoot : void 0;
|
|
19980
19963
|
return [
|
|
19981
|
-
|
|
19964
|
+
NodePath4.join(configDirPath, "settings.json"),
|
|
19982
19965
|
...cwd ? [
|
|
19983
|
-
|
|
19984
|
-
|
|
19966
|
+
NodePath4.join(cwd, ".claude", "settings.json"),
|
|
19967
|
+
NodePath4.join(cwd, ".claude", "settings.local.json")
|
|
19985
19968
|
] : [],
|
|
19986
|
-
...root ? [
|
|
19969
|
+
...root ? [NodePath4.join(root, ".claude", "settings.local.json")] : [],
|
|
19987
19970
|
...managedPath ? [managedPath] : []
|
|
19988
19971
|
];
|
|
19989
19972
|
}
|
|
19990
19973
|
async function findRepositoryRoot(cwd) {
|
|
19991
|
-
let current =
|
|
19974
|
+
let current = NodePath4.resolve(cwd);
|
|
19992
19975
|
for (; ; ) {
|
|
19993
|
-
const found = await NodeFSP.stat(
|
|
19976
|
+
const found = await NodeFSP.stat(NodePath4.join(current, ".git")).then(
|
|
19994
19977
|
() => true,
|
|
19995
19978
|
() => false
|
|
19996
19979
|
);
|
|
19997
19980
|
if (found) return current;
|
|
19998
|
-
const parent =
|
|
19981
|
+
const parent = NodePath4.dirname(current);
|
|
19999
19982
|
if (parent === current) return void 0;
|
|
20000
19983
|
current = parent;
|
|
20001
19984
|
}
|
|
@@ -20077,8 +20060,8 @@ async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
|
20077
20060
|
options.environment ?? NodeProcess.env
|
|
20078
20061
|
);
|
|
20079
20062
|
const roots = [
|
|
20080
|
-
{ directory:
|
|
20081
|
-
...cwd ? [{ directory:
|
|
20063
|
+
{ directory: NodePath4.join(configDirPath, "skills"), scope: "user" },
|
|
20064
|
+
...cwd ? [{ directory: NodePath4.join(cwd, ".claude", "skills"), scope: "project" }] : []
|
|
20082
20065
|
];
|
|
20083
20066
|
const skills = /* @__PURE__ */ new Map();
|
|
20084
20067
|
for (const root of roots) {
|
|
@@ -20086,7 +20069,7 @@ async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
|
20086
20069
|
for (const entry of entries.toSorted()) {
|
|
20087
20070
|
const name = entry.trim();
|
|
20088
20071
|
if (name.length === 0 || skills.has(name)) continue;
|
|
20089
|
-
const skillPath =
|
|
20072
|
+
const skillPath = NodePath4.join(root.directory, entry, "SKILL.md");
|
|
20090
20073
|
const contents = await NodeFSP.readFile(skillPath, "utf8").catch(() => void 0);
|
|
20091
20074
|
if (contents === void 0) continue;
|
|
20092
20075
|
const frontMatter = parseSkillFrontMatter(contents);
|
|
@@ -20106,115 +20089,690 @@ async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
|
20106
20089
|
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
20107
20090
|
}
|
|
20108
20091
|
|
|
20109
|
-
// src/
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
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;
|
|
20113
20104
|
}
|
|
20114
|
-
function
|
|
20115
|
-
return
|
|
20105
|
+
function normalizeCustomModelSlug(slug) {
|
|
20106
|
+
return slug.trim();
|
|
20116
20107
|
}
|
|
20117
|
-
function
|
|
20118
|
-
|
|
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;
|
|
20117
|
+
return {
|
|
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
|
+
]
|
|
20127
|
+
};
|
|
20128
|
+
}
|
|
20129
|
+
return void 0;
|
|
20119
20130
|
}
|
|
20120
|
-
function
|
|
20121
|
-
|
|
20122
|
-
|
|
20123
|
-
|
|
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) {
|
|
20124
20142
|
if (!isRecord2(entry)) continue;
|
|
20125
|
-
|
|
20126
|
-
|
|
20127
|
-
|
|
20143
|
+
if (entry["id"] === optionId && typeof entry["value"] === "string") {
|
|
20144
|
+
const trimmed = entry["value"].trim();
|
|
20145
|
+
if (trimmed.length > 0) return trimmed;
|
|
20146
|
+
}
|
|
20128
20147
|
}
|
|
20129
|
-
return
|
|
20148
|
+
return void 0;
|
|
20130
20149
|
}
|
|
20131
|
-
function
|
|
20132
|
-
if (!
|
|
20133
|
-
const
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
const slug2 = entry.trim();
|
|
20137
|
-
if (slug2.length > 0) models.push({ slug: slug2 });
|
|
20138
|
-
continue;
|
|
20139
|
-
}
|
|
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) {
|
|
20140
20155
|
if (!isRecord2(entry)) continue;
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
const thinkingOptions = Array.isArray(thinkingRaw) ? thinkingRaw.flatMap((option) => {
|
|
20145
|
-
if (!isRecord2(option)) return [];
|
|
20146
|
-
const id2 = readTrimmed(option["id"]) || readTrimmed(option["value"]);
|
|
20147
|
-
const label = readTrimmed(option["label"]) || id2;
|
|
20148
|
-
if (id2.length === 0) return [];
|
|
20149
|
-
return [
|
|
20150
|
-
{
|
|
20151
|
-
id: id2,
|
|
20152
|
-
label,
|
|
20153
|
-
...typeof option["description"] === "string" ? { description: option["description"] } : {},
|
|
20154
|
-
...option["isDefault"] === true ? { isDefault: true } : {}
|
|
20155
|
-
}
|
|
20156
|
-
];
|
|
20157
|
-
}) : void 0;
|
|
20158
|
-
const aliasesRaw = entry["aliases"];
|
|
20159
|
-
const aliases = Array.isArray(aliasesRaw) ? aliasesRaw.filter(
|
|
20160
|
-
(alias) => typeof alias === "string" && alias.trim().length > 0
|
|
20161
|
-
) : void 0;
|
|
20162
|
-
const contextWindow = typeof entry["contextWindow"] === "number" && Number.isFinite(entry["contextWindow"]) && entry["contextWindow"] > 0 ? Math.round(entry["contextWindow"]) : void 0;
|
|
20163
|
-
models.push({
|
|
20164
|
-
slug,
|
|
20165
|
-
...readTrimmed(entry["label"]) ? { label: readTrimmed(entry["label"]) } : {},
|
|
20166
|
-
...thinkingOptions && thinkingOptions.length > 0 ? { thinkingOptions } : {},
|
|
20167
|
-
...contextWindow !== void 0 ? { contextWindow } : {},
|
|
20168
|
-
...aliases && aliases.length > 0 ? { aliases } : {}
|
|
20169
|
-
});
|
|
20156
|
+
if (entry["id"] === optionId && typeof entry["value"] === "boolean") {
|
|
20157
|
+
return entry["value"];
|
|
20158
|
+
}
|
|
20170
20159
|
}
|
|
20171
|
-
return
|
|
20160
|
+
return void 0;
|
|
20172
20161
|
}
|
|
20173
|
-
function
|
|
20174
|
-
|
|
20175
|
-
|
|
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;
|
|
20176
20166
|
}
|
|
20177
|
-
function
|
|
20178
|
-
if (
|
|
20179
|
-
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
};
|
|
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;
|
|
20190
20179
|
}
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
|
|
20196
|
-
credentialsPath: readTrimmed(settings["credentialsPath"]) || readTrimmed(config["credentialsPath"]),
|
|
20197
|
-
launchArgs: readString(settings["launchArgs"]),
|
|
20198
|
-
autoCompactWindow: readAutoCompactWindow(settings["autoCompactWindow"]),
|
|
20199
|
-
customModels: readCustomModels(settings["customModels"]),
|
|
20200
|
-
enabled: settings["enabled"] !== false,
|
|
20201
|
-
environment: readEnvironment(config["environment"]),
|
|
20202
|
-
envelopeDriver: readTrimmed(config["driver"]) || void 0
|
|
20203
|
-
};
|
|
20180
|
+
if (effort === "ultracode") {
|
|
20181
|
+
return "xhigh";
|
|
20182
|
+
}
|
|
20183
|
+
return effort;
|
|
20204
20184
|
}
|
|
20205
|
-
function
|
|
20206
|
-
|
|
20207
|
-
|
|
20208
|
-
|
|
20209
|
-
|
|
20210
|
-
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
|
|
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;
|
|
20218
20776
|
quoted = true;
|
|
20219
20777
|
} else if (char === "\\" && quote === '"') {
|
|
20220
20778
|
const next = input[index + 1];
|
|
@@ -20275,183 +20833,50 @@ function parseCliArgs(args, options) {
|
|
|
20275
20833
|
const next = tokens[i + 1];
|
|
20276
20834
|
if (next !== void 0 && !next.startsWith("--")) {
|
|
20277
20835
|
flags[rest] = next;
|
|
20278
|
-
i++;
|
|
20279
|
-
} else {
|
|
20280
|
-
flags[rest] = null;
|
|
20281
|
-
}
|
|
20282
|
-
} else {
|
|
20283
|
-
positionals.push(token);
|
|
20284
|
-
}
|
|
20285
|
-
}
|
|
20286
|
-
return { flags, positionals };
|
|
20287
|
-
}
|
|
20288
|
-
|
|
20289
|
-
// src/events.ts
|
|
20290
|
-
var EventBus = class {
|
|
20291
|
-
#queued = [];
|
|
20292
|
-
#waiters = [];
|
|
20293
|
-
#closed = false;
|
|
20294
|
-
push(event) {
|
|
20295
|
-
const waiter = this.#waiters.shift();
|
|
20296
|
-
if (waiter) {
|
|
20297
|
-
waiter({ done: false, value: event });
|
|
20298
|
-
return;
|
|
20299
|
-
}
|
|
20300
|
-
this.#queued.push(event);
|
|
20301
|
-
}
|
|
20302
|
-
close() {
|
|
20303
|
-
if (this.#closed) return;
|
|
20304
|
-
this.#closed = true;
|
|
20305
|
-
while (this.#waiters.length > 0) {
|
|
20306
|
-
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
20307
|
-
}
|
|
20308
|
-
}
|
|
20309
|
-
[Symbol.asyncIterator]() {
|
|
20310
|
-
return {
|
|
20311
|
-
next: () => {
|
|
20312
|
-
const queued = this.#queued.shift();
|
|
20313
|
-
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
20314
|
-
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
20315
|
-
return new Promise((resolve4) => {
|
|
20316
|
-
this.#waiters.push(resolve4);
|
|
20317
|
-
});
|
|
20318
|
-
}
|
|
20319
|
-
};
|
|
20320
|
-
}
|
|
20321
|
-
};
|
|
20322
|
-
|
|
20323
|
-
// src/model.ts
|
|
20324
|
-
import { matchCatalogModel } from "@ycodium-ai/plugin-api/executor";
|
|
20325
|
-
var DEFAULT_CLAUDE_MODEL_CAPABILITIES = {
|
|
20326
|
-
optionDescriptors: []
|
|
20327
|
-
};
|
|
20328
|
-
var CLAUDE_CUSTOM_MODEL_THINKING_SELECT = {
|
|
20329
|
-
id: "effort",
|
|
20330
|
-
label: "Reasoning"
|
|
20331
|
-
};
|
|
20332
|
-
function parseGenericCliVersion(output) {
|
|
20333
|
-
const match = output.match(/\bv?(\d+\.\d+\.\d+)\b/);
|
|
20334
|
-
return match?.[1] ?? null;
|
|
20335
|
-
}
|
|
20336
|
-
function normalizeCustomModelSlug(slug) {
|
|
20337
|
-
return slug.trim();
|
|
20338
|
-
}
|
|
20339
|
-
function knownClaudeModelCapabilities(model, catalog, customModels) {
|
|
20340
|
-
const slug = model?.trim();
|
|
20341
|
-
const fromCatalog = catalog.find((candidate) => candidate.slug === slug)?.capabilities;
|
|
20342
|
-
if (fromCatalog) return fromCatalog;
|
|
20343
|
-
const custom = customModels?.find(
|
|
20344
|
-
(candidate) => normalizeCustomModelSlug(candidate.slug) === slug
|
|
20345
|
-
);
|
|
20346
|
-
if (custom?.thinkingOptions !== void 0 && custom.thinkingOptions.length > 0) {
|
|
20347
|
-
const currentValue = custom.thinkingOptions.find((option) => option.isDefault)?.id;
|
|
20348
|
-
return {
|
|
20349
|
-
optionDescriptors: [
|
|
20350
|
-
{
|
|
20351
|
-
type: "select",
|
|
20352
|
-
id: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.id,
|
|
20353
|
-
label: CLAUDE_CUSTOM_MODEL_THINKING_SELECT.label,
|
|
20354
|
-
options: custom.thinkingOptions,
|
|
20355
|
-
...currentValue !== void 0 ? {} : {}
|
|
20356
|
-
}
|
|
20357
|
-
]
|
|
20358
|
-
};
|
|
20359
|
-
}
|
|
20360
|
-
return void 0;
|
|
20361
|
-
}
|
|
20362
|
-
function claudeModelCapabilities(model, catalog, customModels) {
|
|
20363
|
-
return knownClaudeModelCapabilities(model, catalog, customModels) ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES;
|
|
20364
|
-
}
|
|
20365
|
-
function isRecord3(value) {
|
|
20366
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20367
|
-
}
|
|
20368
|
-
function getModelSelectionStringOptionValue(modelSelection, optionId) {
|
|
20369
|
-
if (!isRecord3(modelSelection)) return void 0;
|
|
20370
|
-
const options = modelSelection["options"];
|
|
20371
|
-
if (!Array.isArray(options)) return void 0;
|
|
20372
|
-
for (const entry of options) {
|
|
20373
|
-
if (!isRecord3(entry)) continue;
|
|
20374
|
-
if (entry["id"] === optionId && typeof entry["value"] === "string") {
|
|
20375
|
-
const trimmed = entry["value"].trim();
|
|
20376
|
-
if (trimmed.length > 0) return trimmed;
|
|
20836
|
+
i++;
|
|
20837
|
+
} else {
|
|
20838
|
+
flags[rest] = null;
|
|
20839
|
+
}
|
|
20840
|
+
} else {
|
|
20841
|
+
positionals.push(token);
|
|
20377
20842
|
}
|
|
20378
20843
|
}
|
|
20379
|
-
return
|
|
20844
|
+
return { flags, positionals };
|
|
20380
20845
|
}
|
|
20381
|
-
|
|
20382
|
-
|
|
20383
|
-
|
|
20384
|
-
|
|
20385
|
-
|
|
20386
|
-
|
|
20387
|
-
|
|
20388
|
-
|
|
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;
|
|
20389
20857
|
}
|
|
20858
|
+
this.#queued.push(event);
|
|
20390
20859
|
}
|
|
20391
|
-
|
|
20392
|
-
|
|
20393
|
-
|
|
20394
|
-
|
|
20395
|
-
|
|
20396
|
-
|
|
20397
|
-
}
|
|
20398
|
-
function currentSelectValue(descriptor, raw) {
|
|
20399
|
-
if (raw && descriptor.options.some((option) => option.id === raw)) return raw;
|
|
20400
|
-
return descriptor.options.find((option) => option.isDefault)?.id;
|
|
20401
|
-
}
|
|
20402
|
-
function resolveClaudeEffort(caps, raw) {
|
|
20403
|
-
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20404
|
-
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20405
|
-
return currentSelectValue(descriptor, raw);
|
|
20406
|
-
}
|
|
20407
|
-
function normalizeClaudeCliEffort(effort) {
|
|
20408
|
-
if (!effort || effort === "ultrathink") {
|
|
20409
|
-
return void 0;
|
|
20410
|
-
}
|
|
20411
|
-
if (effort === "ultracode") {
|
|
20412
|
-
return "xhigh";
|
|
20413
|
-
}
|
|
20414
|
-
return effort;
|
|
20415
|
-
}
|
|
20416
|
-
function isClaudeUltracodeEffort(effort) {
|
|
20417
|
-
return effort === "ultracode";
|
|
20418
|
-
}
|
|
20419
|
-
function claudeCliModelId(input) {
|
|
20420
|
-
const requested = input.requestedModelId.trim();
|
|
20421
|
-
if (requested.length > 0 && (input.catalog ?? []).length === 0) return requested;
|
|
20422
|
-
const known = [
|
|
20423
|
-
...(input.catalog ?? []).map((model) => model.slug),
|
|
20424
|
-
...input.declared ?? [],
|
|
20425
|
-
...(input.customModels ?? []).map((model) => normalizeCustomModelSlug(model.slug))
|
|
20426
|
-
];
|
|
20427
|
-
return matchCatalogModel(input.requestedModelId, known) ?? input.placeholder;
|
|
20428
|
-
}
|
|
20429
|
-
function resolvePromptInjectedEffort(caps, rawEffort) {
|
|
20430
|
-
const trimmed = rawEffort?.trim();
|
|
20431
|
-
if (!trimmed) return void 0;
|
|
20432
|
-
const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
|
|
20433
|
-
if (!descriptor || descriptor.type !== "select") return void 0;
|
|
20434
|
-
if (!descriptor.promptInjectedValues?.includes(trimmed)) return void 0;
|
|
20435
|
-
return trimmed;
|
|
20436
|
-
}
|
|
20437
|
-
function applyClaudePromptEffortPrefix(text, effort) {
|
|
20438
|
-
const trimmed = text.trim();
|
|
20439
|
-
if (!trimmed) {
|
|
20440
|
-
return trimmed;
|
|
20441
|
-
}
|
|
20442
|
-
if (effort !== "ultrathink" || /^\/[^\s/]+(?:\s|$)/u.test(trimmed)) {
|
|
20443
|
-
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
|
+
}
|
|
20444
20866
|
}
|
|
20445
|
-
|
|
20446
|
-
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
|
+
};
|
|
20447
20878
|
}
|
|
20448
|
-
|
|
20449
|
-
${trimmed}`;
|
|
20450
|
-
}
|
|
20451
|
-
function getEffectiveClaudeAgentEffort(effort) {
|
|
20452
|
-
const normalized = normalizeClaudeCliEffort(effort);
|
|
20453
|
-
return normalized ? normalized : null;
|
|
20454
|
-
}
|
|
20879
|
+
};
|
|
20455
20880
|
|
|
20456
20881
|
// src/sdkModels.ts
|
|
20457
20882
|
import * as NodeOS5 from "node:os";
|
|
@@ -21121,7 +21546,7 @@ function terminalResultError(reason, failureHint) {
|
|
|
21121
21546
|
case "turn_setup_failed":
|
|
21122
21547
|
return "Claude could not start the turn.";
|
|
21123
21548
|
case "blocking_limit":
|
|
21124
|
-
return "Claude stopped: a usage limit blocked the request.";
|
|
21549
|
+
return failureHint ?? "Claude stopped: a usage limit blocked the request.";
|
|
21125
21550
|
case "rapid_refill_breaker":
|
|
21126
21551
|
return "Claude stopped: the context refilled too quickly after compaction.";
|
|
21127
21552
|
case "prompt_too_long":
|
|
@@ -21156,10 +21581,8 @@ function resultOutcome(result, failureHint) {
|
|
|
21156
21581
|
return { status: "completed", errorMessage };
|
|
21157
21582
|
}
|
|
21158
21583
|
if (isInterruptedResult(result)) return { status: "interrupted", errorMessage };
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
errorMessage
|
|
21162
|
-
};
|
|
21584
|
+
const cancelled = resultErrorsText(result).includes("cancel");
|
|
21585
|
+
return cancelled ? { status: "cancelled", errorMessage } : { status: "failed", errorMessage: errorMessage ?? failureHint };
|
|
21163
21586
|
}
|
|
21164
21587
|
function streamKindFromDeltaType(deltaType) {
|
|
21165
21588
|
return deltaType.includes("thinking") ? "reasoning_text" : "assistant_text";
|
|
@@ -21256,92 +21679,6 @@ function describeUnknownSdkMessage(kind, message) {
|
|
|
21256
21679
|
return preview ? `${kind} \u2014 ${preview}` : `${kind} (no displayable text content)`;
|
|
21257
21680
|
}
|
|
21258
21681
|
|
|
21259
|
-
// src/sessionSettings.ts
|
|
21260
|
-
function toSessionPermissionUpdates(toolName, suggestions) {
|
|
21261
|
-
const sessionScoped = (suggestions ?? []).map(
|
|
21262
|
-
(suggestion) => ({ ...suggestion, destination: "session" })
|
|
21263
|
-
);
|
|
21264
|
-
if (sessionScoped.length > 0) {
|
|
21265
|
-
return sessionScoped;
|
|
21266
|
-
}
|
|
21267
|
-
return [
|
|
21268
|
-
{
|
|
21269
|
-
type: "addRules",
|
|
21270
|
-
rules: [{ toolName }],
|
|
21271
|
-
behavior: "allow",
|
|
21272
|
-
destination: "session"
|
|
21273
|
-
}
|
|
21274
|
-
];
|
|
21275
|
-
}
|
|
21276
|
-
var CLAUDE_SESSION_SETTING_KEYS = [
|
|
21277
|
-
"alwaysThinkingEnabled",
|
|
21278
|
-
"fastMode",
|
|
21279
|
-
"ultracode",
|
|
21280
|
-
"autoCompactWindow"
|
|
21281
|
-
];
|
|
21282
|
-
function buildClaudeSessionSettings(input) {
|
|
21283
|
-
return {
|
|
21284
|
-
...typeof input.thinking === "boolean" ? { alwaysThinkingEnabled: input.thinking } : {},
|
|
21285
|
-
...input.fastMode ? { fastMode: true } : {},
|
|
21286
|
-
...input.ultracode ? { ultracode: true } : {},
|
|
21287
|
-
...input.autoCompactWindow ? { autoCompactWindow: Number(input.autoCompactWindow) } : {}
|
|
21288
|
-
};
|
|
21289
|
-
}
|
|
21290
|
-
function diffClaudeSessionSettings(previous, next) {
|
|
21291
|
-
const patch = {};
|
|
21292
|
-
let changed = false;
|
|
21293
|
-
const track = (key) => {
|
|
21294
|
-
if (previous[key] === next[key]) {
|
|
21295
|
-
return;
|
|
21296
|
-
}
|
|
21297
|
-
changed = true;
|
|
21298
|
-
patch[key] = next[key] ?? null;
|
|
21299
|
-
};
|
|
21300
|
-
for (const key of CLAUDE_SESSION_SETTING_KEYS) {
|
|
21301
|
-
track(key);
|
|
21302
|
-
}
|
|
21303
|
-
return changed ? patch : void 0;
|
|
21304
|
-
}
|
|
21305
|
-
var CLAUDE_NATIVE_MODES = [
|
|
21306
|
-
{ id: "default", name: "Manual", description: "Always ask before making changes" },
|
|
21307
|
-
{ id: "acceptEdits", name: "Accept edits", description: "Automatically accept all file edits" },
|
|
21308
|
-
{ id: "plan", name: "Plan", description: "Create a plan before making changes" },
|
|
21309
|
-
{ id: "auto", name: "Auto", description: "Claude handles permission decisions" },
|
|
21310
|
-
{
|
|
21311
|
-
id: "bypassPermissions",
|
|
21312
|
-
name: "Bypass permissions",
|
|
21313
|
-
description: "Accepts all permissions"
|
|
21314
|
-
}
|
|
21315
|
-
];
|
|
21316
|
-
var CLAUDE_DEFAULT_NATIVE_MODE_ID = "default";
|
|
21317
|
-
var CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE = {
|
|
21318
|
-
"approval-required": "default",
|
|
21319
|
-
"auto-accept-edits": "acceptEdits",
|
|
21320
|
-
auto: "auto",
|
|
21321
|
-
"full-access": "bypassPermissions"
|
|
21322
|
-
};
|
|
21323
|
-
var CLAUDE_NATIVE_MODE_REPORT = {
|
|
21324
|
-
nativeModes: CLAUDE_NATIVE_MODES.map((mode) => ({
|
|
21325
|
-
id: mode.id,
|
|
21326
|
-
name: mode.name,
|
|
21327
|
-
description: mode.description
|
|
21328
|
-
})),
|
|
21329
|
-
currentNativeModeId: CLAUDE_DEFAULT_NATIVE_MODE_ID,
|
|
21330
|
-
nativeModeByRuntimeMode: CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE
|
|
21331
|
-
};
|
|
21332
|
-
function isClaudeNativeModeId(value) {
|
|
21333
|
-
return CLAUDE_NATIVE_MODES.some((mode) => mode.id === value);
|
|
21334
|
-
}
|
|
21335
|
-
function claudePermissionModeFor(runtimeMode, nativeModeId) {
|
|
21336
|
-
if (nativeModeId !== void 0 && isClaudeNativeModeId(nativeModeId)) return nativeModeId;
|
|
21337
|
-
return CLAUDE_NATIVE_MODE_BY_RUNTIME_MODE[runtimeMode];
|
|
21338
|
-
}
|
|
21339
|
-
var CLAUDE_SETTING_SOURCES = [
|
|
21340
|
-
"user",
|
|
21341
|
-
"project",
|
|
21342
|
-
"local"
|
|
21343
|
-
];
|
|
21344
|
-
|
|
21345
21682
|
// src/readOnlyDirectories.ts
|
|
21346
21683
|
var GLOB_METACHARACTERS = /[*?[\]{}]/;
|
|
21347
21684
|
function toClaudeAbsolutePath(directory) {
|
|
@@ -21367,7 +21704,7 @@ function claudeReadAllowRules(directories) {
|
|
|
21367
21704
|
// src/sessions.ts
|
|
21368
21705
|
import * as NodeFS3 from "node:fs";
|
|
21369
21706
|
import * as NodeOS6 from "node:os";
|
|
21370
|
-
import * as
|
|
21707
|
+
import * as NodePath7 from "node:path";
|
|
21371
21708
|
import * as NodeProcess2 from "node:process";
|
|
21372
21709
|
|
|
21373
21710
|
// ../../packages/ycodium-jsonl-stream/src/jsonlStream.ts
|
|
@@ -21996,7 +22333,7 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
21996
22333
|
const scanned = matched.length > 0 ? matched : dirs;
|
|
21997
22334
|
const found = [];
|
|
21998
22335
|
for (const dir of scanned) {
|
|
21999
|
-
const projectDir =
|
|
22336
|
+
const projectDir = NodePath7.join(transcriptDir, dir);
|
|
22000
22337
|
let names;
|
|
22001
22338
|
try {
|
|
22002
22339
|
names = NodeFS3.readdirSync(projectDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TRANSCRIPT_SUFFIX)).map((entry) => entry.name);
|
|
@@ -22006,12 +22343,12 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
22006
22343
|
for (const name of names) {
|
|
22007
22344
|
let stat2;
|
|
22008
22345
|
try {
|
|
22009
|
-
stat2 = NodeFS3.statSync(
|
|
22346
|
+
stat2 = NodeFS3.statSync(NodePath7.join(projectDir, name));
|
|
22010
22347
|
} catch {
|
|
22011
22348
|
continue;
|
|
22012
22349
|
}
|
|
22013
22350
|
found.push({
|
|
22014
|
-
path:
|
|
22351
|
+
path: NodePath7.join(projectDir, name),
|
|
22015
22352
|
sessionId: name.slice(0, -TRANSCRIPT_SUFFIX.length),
|
|
22016
22353
|
size: stat2.size,
|
|
22017
22354
|
mtimeMs: Number.isFinite(stat2.mtimeMs) ? stat2.mtimeMs : 0
|
|
@@ -22022,7 +22359,7 @@ function listTranscriptFiles(transcriptDir, directory) {
|
|
|
22022
22359
|
}
|
|
22023
22360
|
function readClaudeLiveSessionIds(configDir) {
|
|
22024
22361
|
const live = /* @__PURE__ */ new Set();
|
|
22025
|
-
const markerDir =
|
|
22362
|
+
const markerDir = NodePath7.join(configDir, "sessions");
|
|
22026
22363
|
let entries;
|
|
22027
22364
|
try {
|
|
22028
22365
|
entries = NodeFS3.readdirSync(markerDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name);
|
|
@@ -22032,7 +22369,7 @@ function readClaudeLiveSessionIds(configDir) {
|
|
|
22032
22369
|
for (const entry of entries) {
|
|
22033
22370
|
let marker;
|
|
22034
22371
|
try {
|
|
22035
|
-
marker = JSON.parse(NodeFS3.readFileSync(
|
|
22372
|
+
marker = JSON.parse(NodeFS3.readFileSync(NodePath7.join(markerDir, entry), "utf8"));
|
|
22036
22373
|
} catch {
|
|
22037
22374
|
continue;
|
|
22038
22375
|
}
|
|
@@ -22086,7 +22423,7 @@ async function scanClaudeSessions(input) {
|
|
|
22086
22423
|
function resolveTranscriptPath(input) {
|
|
22087
22424
|
const fileName = `${input.sessionId}${TRANSCRIPT_SUFFIX}`;
|
|
22088
22425
|
if (input.cwd !== void 0 && input.cwd.length > 0) {
|
|
22089
|
-
const direct =
|
|
22426
|
+
const direct = NodePath7.join(
|
|
22090
22427
|
input.transcriptDir,
|
|
22091
22428
|
encodeClaudeProjectDirName(input.cwd),
|
|
22092
22429
|
fileName
|
|
@@ -22103,7 +22440,7 @@ function resolveTranscriptPath(input) {
|
|
|
22103
22440
|
return null;
|
|
22104
22441
|
}
|
|
22105
22442
|
for (const dir of dirs) {
|
|
22106
|
-
const candidate =
|
|
22443
|
+
const candidate = NodePath7.join(input.transcriptDir, dir, fileName);
|
|
22107
22444
|
try {
|
|
22108
22445
|
if (NodeFS3.statSync(candidate).isFile()) return candidate;
|
|
22109
22446
|
} catch {
|
|
@@ -22557,74 +22894,33 @@ function normalizeClaudeTaskProgressTokenUsage(value, memory) {
|
|
|
22557
22894
|
const lastUsedTokens = memory.lastKnownTokenUsage?.usedTokens;
|
|
22558
22895
|
const activeTokens = lastUsedTokens !== void 0 ? Math.max(totalTokens, lastUsedTokens) : totalTokens;
|
|
22559
22896
|
if (lastUsedTokens !== void 0 && activeTokens === lastUsedTokens) {
|
|
22560
|
-
return void 0;
|
|
22561
|
-
}
|
|
22562
|
-
const usage = value;
|
|
22563
|
-
const snapshot = makeClaudeTokenUsageSnapshot({
|
|
22564
|
-
activeTokens,
|
|
22565
|
-
...memory.lastKnownContextWindow !== void 0 ? { contextWindow: memory.lastKnownContextWindow } : {},
|
|
22566
|
-
totalProcessedTokens: Math.max(
|
|
22567
|
-
totalTokens,
|
|
22568
|
-
memory.lastKnownTotalProcessedTokens ?? totalTokens
|
|
22569
|
-
)
|
|
22570
|
-
});
|
|
22571
|
-
if (!snapshot) {
|
|
22572
|
-
return void 0;
|
|
22573
|
-
}
|
|
22574
|
-
const toolUses = finiteNonNegativeInteger(usage.tool_uses);
|
|
22575
|
-
const durationMs = finiteNonNegativeInteger(usage.duration_ms);
|
|
22576
|
-
return {
|
|
22577
|
-
...snapshot,
|
|
22578
|
-
...toolUses !== void 0 ? { toolUses } : {},
|
|
22579
|
-
...durationMs !== void 0 ? { durationMs } : {}
|
|
22580
|
-
};
|
|
22581
|
-
}
|
|
22582
|
-
|
|
22583
|
-
// src/probeModels.ts
|
|
22584
|
-
var toProbeCapabilities = (caps) => ({
|
|
22585
|
-
optionDescriptors: caps.optionDescriptors.map(
|
|
22586
|
-
(descriptor) => descriptor.type === "select" ? {
|
|
22587
|
-
id: descriptor.id,
|
|
22588
|
-
label: descriptor.label,
|
|
22589
|
-
type: "select",
|
|
22590
|
-
options: descriptor.options.map((option) => ({
|
|
22591
|
-
id: option.id,
|
|
22592
|
-
label: option.label,
|
|
22593
|
-
...option.description === void 0 ? {} : { description: option.description },
|
|
22594
|
-
...option.isDefault === void 0 ? {} : { isDefault: option.isDefault }
|
|
22595
|
-
}))
|
|
22596
|
-
} : {
|
|
22597
|
-
id: descriptor.id,
|
|
22598
|
-
label: descriptor.label,
|
|
22599
|
-
type: "boolean"
|
|
22600
|
-
}
|
|
22601
|
-
)
|
|
22602
|
-
});
|
|
22603
|
-
var claudeProbeModels = (input) => {
|
|
22604
|
-
const seen = /* @__PURE__ */ new Set();
|
|
22605
|
-
const out = [];
|
|
22606
|
-
for (const model of input.catalog) {
|
|
22607
|
-
if (seen.has(model.slug)) continue;
|
|
22608
|
-
seen.add(model.slug);
|
|
22609
|
-
const userLabel = input.customModels.find((entry) => entry.slug === model.slug)?.label;
|
|
22610
|
-
out.push({
|
|
22611
|
-
slug: model.slug,
|
|
22612
|
-
name: userLabel?.trim() || model.name,
|
|
22613
|
-
capabilities: toProbeCapabilities(model.capabilities)
|
|
22614
|
-
});
|
|
22615
|
-
}
|
|
22616
|
-
for (const model of input.customModels) {
|
|
22617
|
-
if (model.slug.trim().length === 0 || seen.has(model.slug)) continue;
|
|
22618
|
-
seen.add(model.slug);
|
|
22619
|
-
out.push({ slug: model.slug, name: model.label?.trim() || model.slug });
|
|
22897
|
+
return void 0;
|
|
22620
22898
|
}
|
|
22621
|
-
|
|
22622
|
-
|
|
22899
|
+
const usage = value;
|
|
22900
|
+
const snapshot = makeClaudeTokenUsageSnapshot({
|
|
22901
|
+
activeTokens,
|
|
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;
|
|
22910
|
+
}
|
|
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
|
+
}
|
|
22623
22919
|
|
|
22624
22920
|
// src/textGeneration.ts
|
|
22625
|
-
import * as
|
|
22921
|
+
import * as NodeFSP3 from "node:fs/promises";
|
|
22626
22922
|
import * as NodeOS7 from "node:os";
|
|
22627
|
-
import * as
|
|
22923
|
+
import * as NodePath8 from "node:path";
|
|
22628
22924
|
import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
|
|
22629
22925
|
|
|
22630
22926
|
// src/textGenerationUtils.ts
|
|
@@ -23093,16 +23389,16 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
23093
23389
|
return decodeStructuredOutput(stdout, input.operation);
|
|
23094
23390
|
};
|
|
23095
23391
|
if (input.operation !== "generateThreadTitle") return runIn(input.cwd);
|
|
23096
|
-
const scratchDirectory = await
|
|
23097
|
-
|
|
23392
|
+
const scratchDirectory = await NodeFSP3.mkdtemp(
|
|
23393
|
+
NodePath8.join(NodeOS7.tmpdir(), "ycodium-claude-title-")
|
|
23098
23394
|
);
|
|
23099
23395
|
try {
|
|
23100
23396
|
return await runIn(scratchDirectory);
|
|
23101
23397
|
} finally {
|
|
23102
|
-
await
|
|
23398
|
+
await NodeFSP3.rm(scratchDirectory, { recursive: true, force: true }).catch(() => void 0);
|
|
23103
23399
|
}
|
|
23104
23400
|
};
|
|
23105
|
-
const
|
|
23401
|
+
const asRecord2 = (value, operation) => {
|
|
23106
23402
|
if (!isRecord5(value))
|
|
23107
23403
|
throw new Error(`${operation}: Claude returned invalid structured output.`);
|
|
23108
23404
|
return value;
|
|
@@ -23110,7 +23406,7 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
23110
23406
|
return {
|
|
23111
23407
|
generateCommitMessage: async (raw, signal) => {
|
|
23112
23408
|
try {
|
|
23113
|
-
const input =
|
|
23409
|
+
const input = asRecord2(raw, "generateCommitMessage");
|
|
23114
23410
|
const includeBranch = input["includeBranch"] === true;
|
|
23115
23411
|
const { prompt, outputSchema } = buildCommitMessagePrompt({
|
|
23116
23412
|
branch: typeof input["branch"] === "string" ? input["branch"] : null,
|
|
@@ -23119,7 +23415,7 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
23119
23415
|
includeBranch,
|
|
23120
23416
|
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23121
23417
|
});
|
|
23122
|
-
const generated =
|
|
23418
|
+
const generated = asRecord2(
|
|
23123
23419
|
await runClaudeJson({
|
|
23124
23420
|
operation: "generateCommitMessage",
|
|
23125
23421
|
cwd: readString3(input["cwd"]) || ".",
|
|
@@ -23138,115 +23434,776 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
23138
23434
|
} catch (error) {
|
|
23139
23435
|
throw normalizeCliError("claude", error, "Failed to generate commit message");
|
|
23140
23436
|
}
|
|
23141
|
-
},
|
|
23142
|
-
generatePrContent: async (raw, signal) => {
|
|
23143
|
-
try {
|
|
23144
|
-
const input =
|
|
23145
|
-
const { prompt, outputSchema } = buildPrContentPrompt({
|
|
23146
|
-
baseBranch: readString3(input["baseBranch"]),
|
|
23147
|
-
headBranch: readString3(input["headBranch"]),
|
|
23148
|
-
commitSummary: readString3(input["commitSummary"]),
|
|
23149
|
-
diffSummary: readString3(input["diffSummary"]),
|
|
23150
|
-
diffPatch: readString3(input["diffPatch"]),
|
|
23151
|
-
...typeof input["changeRequestTemplate"] === "string" ? { changeRequestTemplate: input["changeRequestTemplate"] } : {},
|
|
23152
|
-
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23153
|
-
});
|
|
23154
|
-
const generated =
|
|
23155
|
-
await runClaudeJson({
|
|
23156
|
-
operation: "generatePrContent",
|
|
23157
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23158
|
-
prompt,
|
|
23159
|
-
outputSchema,
|
|
23160
|
-
modelSelection: input["modelSelection"],
|
|
23161
|
-
...signal === void 0 ? {} : { signal }
|
|
23162
|
-
}),
|
|
23163
|
-
"generatePrContent"
|
|
23164
|
-
);
|
|
23165
|
-
return {
|
|
23166
|
-
title: sanitizePrTitle(readString3(generated["title"])),
|
|
23167
|
-
body: readString3(generated["body"]).trim()
|
|
23168
|
-
};
|
|
23169
|
-
} catch (error) {
|
|
23170
|
-
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;
|
|
23171
24134
|
}
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
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 }
|
|
23180
24148
|
});
|
|
23181
|
-
const generated = asRecord(
|
|
23182
|
-
await runClaudeJson({
|
|
23183
|
-
operation: "generateBranchName",
|
|
23184
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23185
|
-
prompt,
|
|
23186
|
-
outputSchema,
|
|
23187
|
-
modelSelection: input["modelSelection"],
|
|
23188
|
-
...signal === void 0 ? {} : { signal }
|
|
23189
|
-
}),
|
|
23190
|
-
"generateBranchName"
|
|
23191
|
-
);
|
|
23192
|
-
return { branch: sanitizeBranchFragment(readString3(generated["branch"])) };
|
|
23193
|
-
} catch (error) {
|
|
23194
|
-
throw normalizeCliError("claude", error, "Failed to generate branch name");
|
|
23195
24149
|
}
|
|
23196
|
-
}
|
|
23197
|
-
|
|
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) {
|
|
23198
24159
|
try {
|
|
23199
|
-
|
|
23200
|
-
|
|
23201
|
-
|
|
23202
|
-
...typeof input["linkedContext"] === "string" && input["linkedContext"].length > 0 ? { linkedContext: input["linkedContext"] } : {},
|
|
23203
|
-
...typeof input["previousTitle"] === "string" ? { previousTitle: input["previousTitle"] } : {},
|
|
23204
|
-
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
23205
|
-
...isRecord5(input["policy"]) ? { policy: input["policy"] } : {}
|
|
23206
|
-
});
|
|
23207
|
-
const generated = asRecord(
|
|
23208
|
-
await runClaudeJson({
|
|
23209
|
-
operation: "generateThreadTitle",
|
|
23210
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23211
|
-
prompt,
|
|
23212
|
-
outputSchema,
|
|
23213
|
-
modelSelection: input["modelSelection"],
|
|
23214
|
-
...signal === void 0 ? {} : { signal }
|
|
23215
|
-
}),
|
|
23216
|
-
"generateThreadTitle"
|
|
24160
|
+
await cache.setJson(
|
|
24161
|
+
`${SCAN_CACHE_KEY_PREFIX}${transcriptRoot}`,
|
|
24162
|
+
encodeScanCache(runtime.fileCache)
|
|
23217
24163
|
);
|
|
23218
|
-
|
|
23219
|
-
|
|
23220
|
-
...generated["needsRefinement"] === true ? { needsRefinement: true } : {}
|
|
23221
|
-
};
|
|
23222
|
-
} catch (error) {
|
|
23223
|
-
throw normalizeCliError("claude", error, "Failed to generate thread title");
|
|
24164
|
+
runtime.dirty = false;
|
|
24165
|
+
} catch {
|
|
23224
24166
|
}
|
|
23225
|
-
}
|
|
23226
|
-
|
|
23227
|
-
|
|
23228
|
-
|
|
23229
|
-
|
|
23230
|
-
|
|
23231
|
-
|
|
23232
|
-
|
|
23233
|
-
|
|
23234
|
-
|
|
23235
|
-
cwd: readString3(input["cwd"]) || ".",
|
|
23236
|
-
prompt,
|
|
23237
|
-
outputSchema,
|
|
23238
|
-
modelSelection: input["modelSelection"],
|
|
23239
|
-
...signal === void 0 ? {} : { signal }
|
|
23240
|
-
}),
|
|
23241
|
-
"summarizeHandover"
|
|
23242
|
-
);
|
|
23243
|
-
return { summary: readString3(generated["summary"]).trim() };
|
|
23244
|
-
} catch (error) {
|
|
23245
|
-
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.` } : {}
|
|
23246
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;
|
|
23247
24186
|
}
|
|
23248
24187
|
};
|
|
23249
|
-
}
|
|
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
|
+
};
|
|
23250
24207
|
|
|
23251
24208
|
// src/claudeSkillDispatch.ts
|
|
23252
24209
|
var SKILL_MENTION_PATTERN = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s|$)/g;
|
|
@@ -23504,7 +24461,6 @@ function toClaudeMcpServers(entries) {
|
|
|
23504
24461
|
}
|
|
23505
24462
|
return servers;
|
|
23506
24463
|
}
|
|
23507
|
-
var CLAUDE_PROGRAM_NOT_CONFIGURED = "Claude program path is not configured";
|
|
23508
24464
|
function createClaudeAdapter(recipe, host, options) {
|
|
23509
24465
|
const boundInstanceId = options?.instanceId ?? host.instanceId ?? "claudeAgent";
|
|
23510
24466
|
const claudeHomeEnvironment = makeClaudeEnvironment(recipe, options?.environment);
|
|
@@ -23520,7 +24476,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
23520
24476
|
if (recipe.binaryPath.length === 0) throw new Error(CLAUDE_PROGRAM_NOT_CONFIGURED);
|
|
23521
24477
|
return sdkCreateQuery(input);
|
|
23522
24478
|
};
|
|
23523
|
-
const buildLaunchEnvironment = () =>
|
|
24479
|
+
const buildLaunchEnvironment = () => mergeLaunchEnv3({
|
|
23524
24480
|
inherited: { ...process.env, ...options?.environment },
|
|
23525
24481
|
instanceTable: recipe.environment,
|
|
23526
24482
|
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
@@ -23913,7 +24869,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
23913
24869
|
compactedSinceLatestAssistantUsage: false,
|
|
23914
24870
|
retrying: false,
|
|
23915
24871
|
authenticationFailed: false,
|
|
23916
|
-
nextSyntheticAssistantBlockIndex: -1
|
|
24872
|
+
nextSyntheticAssistantBlockIndex: -1,
|
|
24873
|
+
rejectedRateLimits: /* @__PURE__ */ new Map(),
|
|
24874
|
+
announcedUsageLimits: /* @__PURE__ */ new Set(),
|
|
24875
|
+
latestAssistantRateLimited: false
|
|
23917
24876
|
};
|
|
23918
24877
|
context.session = {
|
|
23919
24878
|
...context.session,
|
|
@@ -24500,6 +25459,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24500
25459
|
if (message.type !== "assistant") {
|
|
24501
25460
|
return;
|
|
24502
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
|
+
}
|
|
24503
25466
|
if (isClaudeSyntheticApiErrorMessage(message)) {
|
|
24504
25467
|
if (context.turnState && message.error === "authentication_failed") {
|
|
24505
25468
|
context.turnState.authenticationFailed = true;
|
|
@@ -24571,14 +25534,22 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24571
25534
|
return;
|
|
24572
25535
|
}
|
|
24573
25536
|
context.compactionInProgress = false;
|
|
24574
|
-
const
|
|
25537
|
+
const outcome = resultOutcome(
|
|
24575
25538
|
message,
|
|
24576
25539
|
claudeFailureHint({
|
|
24577
25540
|
authenticationFailed: context.turnState?.authenticationFailed === true,
|
|
24578
25541
|
environment: buildLaunchEnvironment(),
|
|
24579
|
-
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
|
+
}
|
|
24580
25550
|
})
|
|
24581
25551
|
);
|
|
25552
|
+
const { status, errorMessage } = outcome;
|
|
24582
25553
|
if (status === "failed") {
|
|
24583
25554
|
await emitRuntimeError(context, errorMessage ?? "Claude turn failed.");
|
|
24584
25555
|
}
|
|
@@ -24685,7 +25656,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24685
25656
|
}
|
|
24686
25657
|
}
|
|
24687
25658
|
switch (message.subtype) {
|
|
24688
|
-
case "init":
|
|
25659
|
+
case "init": {
|
|
24689
25660
|
offerRuntimeEvent(context, {
|
|
24690
25661
|
...base,
|
|
24691
25662
|
type: "session.configured",
|
|
@@ -24693,6 +25664,27 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
24693
25664
|
config: message
|
|
24694
25665
|
}
|
|
24695
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
|
+
}
|
|
24696
25688
|
return;
|
|
24697
25689
|
case "status": {
|
|
24698
25690
|
const compacting = message.status === "compacting";
|
|
@@ -25000,7 +25992,6 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25000
25992
|
// deliberately so they don't masquerade as unknown-subtype warnings.
|
|
25001
25993
|
case "local_command_output":
|
|
25002
25994
|
case "plugin_install":
|
|
25003
|
-
case "commands_changed":
|
|
25004
25995
|
case "memory_recall":
|
|
25005
25996
|
case "elicitation_complete":
|
|
25006
25997
|
return;
|
|
@@ -25100,6 +26091,25 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25100
26091
|
rateLimits: message
|
|
25101
26092
|
}
|
|
25102
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
|
+
}
|
|
25103
26113
|
return;
|
|
25104
26114
|
}
|
|
25105
26115
|
};
|
|
@@ -25992,7 +27002,10 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
25992
27002
|
compactedSinceLatestAssistantUsage: false,
|
|
25993
27003
|
retrying: false,
|
|
25994
27004
|
authenticationFailed: false,
|
|
25995
|
-
nextSyntheticAssistantBlockIndex: -1
|
|
27005
|
+
nextSyntheticAssistantBlockIndex: -1,
|
|
27006
|
+
rejectedRateLimits: /* @__PURE__ */ new Map(),
|
|
27007
|
+
announcedUsageLimits: /* @__PURE__ */ new Set(),
|
|
27008
|
+
latestAssistantRateLimited: false
|
|
25996
27009
|
};
|
|
25997
27010
|
const updatedAt = nowIso();
|
|
25998
27011
|
context.turnState = turnState;
|
|
@@ -26024,9 +27037,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
26024
27037
|
attachments: input.attachments,
|
|
26025
27038
|
attachmentsApi: options?.attachments,
|
|
26026
27039
|
skillNames: new Set(
|
|
26027
|
-
skills.filter(
|
|
26028
|
-
(skill) => skill.scope === "user" && skill.enabled && skill.userInvocable !== false
|
|
26029
|
-
).map((skill) => skill.name)
|
|
27040
|
+
skills.filter((skill) => skill.enabled && skill.userInvocable !== false).map((skill) => skill.name)
|
|
26030
27041
|
)
|
|
26031
27042
|
});
|
|
26032
27043
|
validateSteeringTarget();
|
|
@@ -26185,7 +27196,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
26185
27196
|
function claudeAdapterBaseEnvironment(recipe) {
|
|
26186
27197
|
return { ...process.env, ...recipe.environment };
|
|
26187
27198
|
}
|
|
26188
|
-
function createClaudeInstance(config, host, attachments, overrides) {
|
|
27199
|
+
function createClaudeInstance(config, host, attachments, overrides, usageCache) {
|
|
26189
27200
|
const recipe = parseClaudeInstanceConfig(config);
|
|
26190
27201
|
const adapter = createClaudeAdapter(recipe, host, {
|
|
26191
27202
|
instanceId: host.instanceId,
|
|
@@ -26194,118 +27205,7 @@ function createClaudeInstance(config, host, attachments, overrides) {
|
|
|
26194
27205
|
environment: claudeAdapterBaseEnvironment(recipe),
|
|
26195
27206
|
log: host.log
|
|
26196
27207
|
});
|
|
26197
|
-
const
|
|
26198
|
-
const chunks = [];
|
|
26199
|
-
for await (const chunk of stream) {
|
|
26200
|
-
chunks.push(Buffer.from(chunk));
|
|
26201
|
-
}
|
|
26202
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
26203
|
-
};
|
|
26204
|
-
const probeAuth = () => {
|
|
26205
|
-
const hasEnvToken = (recipe.environment.ANTHROPIC_AUTH_TOKEN ?? "").trim().length > 0;
|
|
26206
|
-
const hasEnvApiKey = (recipe.environment.ANTHROPIC_API_KEY ?? "").trim().length > 0;
|
|
26207
|
-
if (hasEnvToken || hasEnvApiKey) {
|
|
26208
|
-
return {
|
|
26209
|
-
status: "authenticated",
|
|
26210
|
-
type: hasEnvToken ? "env-token" : "api-key",
|
|
26211
|
-
label: hasEnvToken ? "ANTHROPIC_AUTH_TOKEN" : "ANTHROPIC_API_KEY"
|
|
26212
|
-
};
|
|
26213
|
-
}
|
|
26214
|
-
const account = readClaudeAccount(resolveClaudeCredentialsDirPath(recipe.credentialsPath));
|
|
26215
|
-
switch (account.state) {
|
|
26216
|
-
case "signed-in":
|
|
26217
|
-
case "expired":
|
|
26218
|
-
return { status: "authenticated" };
|
|
26219
|
-
case "signed-out":
|
|
26220
|
-
return { status: "unauthenticated" };
|
|
26221
|
-
case "unreadable":
|
|
26222
|
-
return { status: "unknown" };
|
|
26223
|
-
}
|
|
26224
|
-
};
|
|
26225
|
-
let lastProbedVersion;
|
|
26226
|
-
const probe = async (signal) => {
|
|
26227
|
-
if (recipe.binaryPath.length === 0) {
|
|
26228
|
-
return {
|
|
26229
|
-
installed: false,
|
|
26230
|
-
version: null,
|
|
26231
|
-
readiness: "not-installed",
|
|
26232
|
-
auth: { status: "unknown" },
|
|
26233
|
-
detail: CLAUDE_PROGRAM_NOT_CONFIGURED
|
|
26234
|
-
};
|
|
26235
|
-
}
|
|
26236
|
-
if (signal?.aborted) {
|
|
26237
|
-
throw new Error("aborted");
|
|
26238
|
-
}
|
|
26239
|
-
let handle;
|
|
26240
|
-
try {
|
|
26241
|
-
handle = await host.process.spawn({
|
|
26242
|
-
program: recipe.binaryPath,
|
|
26243
|
-
args: ["--version"],
|
|
26244
|
-
owner: { bindingId: host.bindingId }
|
|
26245
|
-
});
|
|
26246
|
-
} catch (error) {
|
|
26247
|
-
if (error instanceof ExecutorSpawnRefusedError) throw error;
|
|
26248
|
-
const failure = describeExecutorSpawnFailure(error);
|
|
26249
|
-
return {
|
|
26250
|
-
installed: false,
|
|
26251
|
-
version: null,
|
|
26252
|
-
readiness: failure.readiness,
|
|
26253
|
-
auth: { status: "unknown" },
|
|
26254
|
-
detail: failure.detail
|
|
26255
|
-
};
|
|
26256
|
-
}
|
|
26257
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
26258
|
-
collectProcessText(handle.stdout),
|
|
26259
|
-
collectProcessText(handle.stderr),
|
|
26260
|
-
handle.exited
|
|
26261
|
-
]);
|
|
26262
|
-
const version = parseGenericCliVersion(`${stdout}
|
|
26263
|
-
${stderr}`);
|
|
26264
|
-
if (version !== null || exitCode === 0) {
|
|
26265
|
-
await adapter.modelCatalog.refresh({ signal, force: version !== lastProbedVersion });
|
|
26266
|
-
lastProbedVersion = version;
|
|
26267
|
-
}
|
|
26268
|
-
const models = claudeProbeModels({
|
|
26269
|
-
catalog: adapter.modelCatalog.current(),
|
|
26270
|
-
customModels: recipe.customModels
|
|
26271
|
-
});
|
|
26272
|
-
const auth = probeAuth();
|
|
26273
|
-
const skills = await discoverClaudeSkills(
|
|
26274
|
-
resolveClaudeConfigDirPath(recipe.homePath, { ...process.env, ...recipe.environment })
|
|
26275
|
-
);
|
|
26276
|
-
if (exitCode !== 0 && version === null) {
|
|
26277
|
-
const detail = (stderr || stdout || "claude --version failed").trim();
|
|
26278
|
-
return {
|
|
26279
|
-
installed: false,
|
|
26280
|
-
version: null,
|
|
26281
|
-
readiness: "error",
|
|
26282
|
-
auth,
|
|
26283
|
-
...detail.length > 0 ? { detail } : {}
|
|
26284
|
-
};
|
|
26285
|
-
}
|
|
26286
|
-
if (auth.status === "unauthenticated") {
|
|
26287
|
-
return {
|
|
26288
|
-
installed: true,
|
|
26289
|
-
version,
|
|
26290
|
-
readiness: "error",
|
|
26291
|
-
auth,
|
|
26292
|
-
models,
|
|
26293
|
-
skills,
|
|
26294
|
-
detail: "Claude is signed out",
|
|
26295
|
-
// 退出登录了档位照样是那五档。不报就退回宿主四档,而那份映射少了 `plan`。
|
|
26296
|
-
...CLAUDE_NATIVE_MODE_REPORT
|
|
26297
|
-
};
|
|
26298
|
-
}
|
|
26299
|
-
return {
|
|
26300
|
-
installed: true,
|
|
26301
|
-
version,
|
|
26302
|
-
readiness: "ready",
|
|
26303
|
-
auth,
|
|
26304
|
-
models,
|
|
26305
|
-
skills,
|
|
26306
|
-
...CLAUDE_NATIVE_MODE_REPORT
|
|
26307
|
-
};
|
|
26308
|
-
};
|
|
27208
|
+
const probe = createClaudeProbe({ recipe, host, modelCatalog: adapter.modelCatalog });
|
|
26309
27209
|
const resolveTranscriptRoots = (directory) => {
|
|
26310
27210
|
const configDir = resolveClaudeConfigDirPath(
|
|
26311
27211
|
recipe.homePath,
|
|
@@ -26314,7 +27214,7 @@ ${stderr}`);
|
|
|
26314
27214
|
);
|
|
26315
27215
|
return {
|
|
26316
27216
|
configDir,
|
|
26317
|
-
transcriptDir:
|
|
27217
|
+
transcriptDir: NodePath13.join(configDir, "projects")
|
|
26318
27218
|
};
|
|
26319
27219
|
};
|
|
26320
27220
|
return {
|
|
@@ -26331,8 +27231,18 @@ ${stderr}`);
|
|
|
26331
27231
|
readThread: adapter.readThread,
|
|
26332
27232
|
events: adapter.events,
|
|
26333
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
|
+
},
|
|
26334
27243
|
textGeneration: createClaudeTextGeneration(recipe, host, adapter.modelCatalog.current),
|
|
26335
27244
|
continuationKey: claudeContinuationKey(recipe.homePath),
|
|
27245
|
+
usage: createClaudeUsage({ recipe, host, cache: usageCache }),
|
|
26336
27246
|
sessions: {
|
|
26337
27247
|
scan: async (input) => {
|
|
26338
27248
|
const roots = resolveTranscriptRoots(input.directory);
|
|
@@ -26373,12 +27283,13 @@ ${stderr}`);
|
|
|
26373
27283
|
|
|
26374
27284
|
// src/index.ts
|
|
26375
27285
|
var capturedAttachments;
|
|
27286
|
+
var capturedCache;
|
|
26376
27287
|
var executors = [
|
|
26377
27288
|
{
|
|
26378
27289
|
card: CLAUDE_CARD,
|
|
26379
27290
|
createInstance: async (config, host) => {
|
|
26380
27291
|
host.log.info("createInstance");
|
|
26381
|
-
return createClaudeInstance(config, host, capturedAttachments);
|
|
27292
|
+
return createClaudeInstance(config, host, capturedAttachments, void 0, capturedCache);
|
|
26382
27293
|
}
|
|
26383
27294
|
}
|
|
26384
27295
|
];
|
|
@@ -26388,6 +27299,7 @@ var index_default = definePlugin({
|
|
|
26388
27299
|
executors,
|
|
26389
27300
|
activate(ctx) {
|
|
26390
27301
|
capturedAttachments = ctx.attachments;
|
|
27302
|
+
capturedCache = ctx.cache;
|
|
26391
27303
|
ctx.log.info("claude executor ready");
|
|
26392
27304
|
}
|
|
26393
27305
|
});
|