@ycodium-ai/agent-claude 0.2.3484 → 0.2.3502
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/index.js +929 -721
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -60,6 +60,8 @@ var CLAUDE_CARD = {
|
|
|
60
60
|
reportsSpawnedAgents: true,
|
|
61
61
|
// 用户点名的技能:最后一个原生 `/name` 派发,更早的读 SKILL.md 内联展开(claudeSkillDispatch.ts)。
|
|
62
62
|
handlesSkillInvocations: true,
|
|
63
|
+
// 会话的其它文件夹经 `--add-dir` 声明成工作目录,并让 CLI 加载它们的 CLAUDE.md 与规则(workingDirectories.ts)。
|
|
64
|
+
acceptsAdditionalDirectories: true,
|
|
63
65
|
// 出处:Anthropic Messages API 的视觉文档——单张图片 5 MB、宽高各不超过 8000 像素,超了
|
|
64
66
|
// API 直接拒掉整轮。5 MB 量的是 base64 之后的长度(SDK 把图片以 base64 块发出),所以
|
|
65
67
|
// 原始字节上限是它的 3/4。宿主据此把更大的图退化成路径(Claude 自己的 Read 工具会读那个
|
|
@@ -347,8 +349,8 @@ async function* historyBytes(path, start, end, signal) {
|
|
|
347
349
|
async function* historyText(path, range, signal) {
|
|
348
350
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
349
351
|
for await (const bytes of historyBytes(path, range.start, range.end, signal)) {
|
|
350
|
-
const
|
|
351
|
-
if (
|
|
352
|
+
const text2 = decoder.decode(bytes, { stream: true });
|
|
353
|
+
if (text2) yield text2;
|
|
352
354
|
}
|
|
353
355
|
const last = decoder.decode();
|
|
354
356
|
if (last) yield last;
|
|
@@ -691,33 +693,33 @@ var OversizedRecordParser = class {
|
|
|
691
693
|
this.#strCap = cap;
|
|
692
694
|
}
|
|
693
695
|
/** 字符串里的一个解码后片段;按保留规则累积。 */
|
|
694
|
-
#append(
|
|
695
|
-
if (
|
|
696
|
+
#append(text2) {
|
|
697
|
+
if (text2.length === 0) return;
|
|
696
698
|
if (this.#stringIsKey) {
|
|
697
699
|
if (this.#keyOverflow) return;
|
|
698
|
-
this.#key +=
|
|
700
|
+
this.#key += text2;
|
|
699
701
|
if (this.#key.length > MAX_KEY_CHARS) {
|
|
700
702
|
this.#keyOverflow = true;
|
|
701
703
|
this.#key = "";
|
|
702
704
|
}
|
|
703
705
|
return;
|
|
704
706
|
}
|
|
705
|
-
this.#strLength +=
|
|
706
|
-
this.#strObserver?.onChunk?.(
|
|
707
|
+
this.#strLength += text2.length;
|
|
708
|
+
this.#strObserver?.onChunk?.(text2);
|
|
707
709
|
if (!this.#strRetain) return;
|
|
708
710
|
const cap = this.#strCap;
|
|
709
711
|
if (cap === void 0) {
|
|
710
|
-
this.#strHead +=
|
|
711
|
-
this.#charge(
|
|
712
|
+
this.#strHead += text2;
|
|
713
|
+
this.#charge(text2.length);
|
|
712
714
|
return;
|
|
713
715
|
}
|
|
714
716
|
if (this.#strHead.length < cap) {
|
|
715
717
|
const room = cap - this.#strHead.length;
|
|
716
|
-
this.#strHead +=
|
|
717
|
-
|
|
718
|
-
if (
|
|
718
|
+
this.#strHead += text2.slice(0, room);
|
|
719
|
+
text2 = text2.slice(room);
|
|
720
|
+
if (text2.length === 0) return;
|
|
719
721
|
}
|
|
720
|
-
this.#strTail +=
|
|
722
|
+
this.#strTail += text2;
|
|
721
723
|
if (this.#strTail.length > cap * 2) this.#strTail = this.#strTail.slice(-cap);
|
|
722
724
|
}
|
|
723
725
|
#consumeString(chunk, start) {
|
|
@@ -807,35 +809,35 @@ var OversizedRecordParser = class {
|
|
|
807
809
|
return;
|
|
808
810
|
}
|
|
809
811
|
const cap = this.#strCap;
|
|
810
|
-
let
|
|
812
|
+
let text2 = this.#strHead;
|
|
811
813
|
if (cap !== void 0) {
|
|
812
814
|
let tail = this.#strTail;
|
|
813
815
|
if (tail.length > cap) tail = tail.slice(-cap);
|
|
814
|
-
if (this.#strLength >
|
|
815
|
-
if (isHighSurrogate(
|
|
816
|
+
if (this.#strLength > text2.length + tail.length) {
|
|
817
|
+
if (isHighSurrogate(text2.charCodeAt(text2.length - 1))) text2 = text2.slice(0, -1);
|
|
816
818
|
if (isLowSurrogate(tail.charCodeAt(0))) tail = tail.slice(1);
|
|
817
|
-
const omitted = this.#strLength -
|
|
818
|
-
|
|
819
|
+
const omitted = this.#strLength - text2.length - tail.length;
|
|
820
|
+
text2 = `${text2}
|
|
819
821
|
[\u2026 ${omitted} chars omitted \u2026]
|
|
820
822
|
${tail}`;
|
|
821
823
|
} else {
|
|
822
|
-
|
|
824
|
+
text2 = `${text2}${tail}`;
|
|
823
825
|
}
|
|
824
|
-
this.#charge(
|
|
826
|
+
this.#charge(text2.length);
|
|
825
827
|
}
|
|
826
828
|
this.#strHead = "";
|
|
827
829
|
this.#strTail = "";
|
|
828
|
-
this.#store(
|
|
830
|
+
this.#store(text2);
|
|
829
831
|
}
|
|
830
832
|
#finishBare() {
|
|
831
|
-
const
|
|
833
|
+
const text2 = this.#bare;
|
|
832
834
|
this.#bare = "";
|
|
833
835
|
const { mode, path } = this.#childMode(false);
|
|
834
836
|
let value;
|
|
835
|
-
if (
|
|
836
|
-
else if (
|
|
837
|
-
else if (
|
|
838
|
-
else if (NUMBER_PATTERN.test(
|
|
837
|
+
if (text2 === "true") value = true;
|
|
838
|
+
else if (text2 === "false") value = false;
|
|
839
|
+
else if (text2 === "null") value = null;
|
|
840
|
+
else if (NUMBER_PATTERN.test(text2)) value = Number(text2);
|
|
839
841
|
else this.#fail();
|
|
840
842
|
const observer = this.#fields.find(
|
|
841
843
|
(field) => field.path.length === path.length && matchesPrefix(field.path, path, path.length)
|
|
@@ -891,14 +893,14 @@ async function* readJsonlEntries(fs2, path, options) {
|
|
|
891
893
|
pending2 = 0;
|
|
892
894
|
return next;
|
|
893
895
|
};
|
|
894
|
-
const append = (
|
|
895
|
-
if (
|
|
896
|
+
const append = (text2) => {
|
|
897
|
+
if (text2.length === 0) return;
|
|
896
898
|
if (parser !== null) {
|
|
897
|
-
parser.write(
|
|
899
|
+
parser.write(text2);
|
|
898
900
|
return;
|
|
899
901
|
}
|
|
900
|
-
pieces.push(
|
|
901
|
-
pending2 +=
|
|
902
|
+
pieces.push(text2);
|
|
903
|
+
pending2 += text2.length;
|
|
902
904
|
if (pending2 > options.maxLineChars) parser = startOversized();
|
|
903
905
|
};
|
|
904
906
|
const takeLine = () => {
|
|
@@ -914,15 +916,15 @@ async function* readJsonlEntries(fs2, path, options) {
|
|
|
914
916
|
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
915
917
|
return line.length === 0 ? null : { line };
|
|
916
918
|
};
|
|
917
|
-
const feed = function* (
|
|
919
|
+
const feed = function* (text2) {
|
|
918
920
|
let from = 0;
|
|
919
|
-
while (from <=
|
|
920
|
-
const newline =
|
|
921
|
+
while (from <= text2.length) {
|
|
922
|
+
const newline = text2.indexOf("\n", from);
|
|
921
923
|
if (newline < 0) {
|
|
922
|
-
append(
|
|
924
|
+
append(text2.slice(from));
|
|
923
925
|
return;
|
|
924
926
|
}
|
|
925
|
-
append(
|
|
927
|
+
append(text2.slice(from, newline));
|
|
926
928
|
const entry = takeLine();
|
|
927
929
|
if (entry !== null) yield entry;
|
|
928
930
|
from = newline + 1;
|
|
@@ -948,9 +950,9 @@ var textFields = (paths, accept) => {
|
|
|
948
950
|
return paths.map((path) => ({
|
|
949
951
|
path,
|
|
950
952
|
scalarOnly: true,
|
|
951
|
-
onChunk: (
|
|
953
|
+
onChunk: (text2) => {
|
|
952
954
|
begin();
|
|
953
|
-
accept(
|
|
955
|
+
accept(text2);
|
|
954
956
|
},
|
|
955
957
|
onEnd: () => {
|
|
956
958
|
begin();
|
|
@@ -968,16 +970,16 @@ var createHistoryRecordAccumulator = (layout) => {
|
|
|
968
970
|
const parser = new OversizedRecordParser(
|
|
969
971
|
[
|
|
970
972
|
...selected.fields,
|
|
971
|
-
...textFields(selected.textPaths, (
|
|
972
|
-
messageTotal +=
|
|
973
|
+
...textFields(selected.textPaths, (text2) => {
|
|
974
|
+
messageTotal += text2.length;
|
|
973
975
|
})
|
|
974
976
|
],
|
|
975
977
|
Number.MAX_SAFE_INTEGER,
|
|
976
978
|
{ pruneEmpty: true }
|
|
977
979
|
);
|
|
978
|
-
const accept = (
|
|
979
|
-
rawTotal +=
|
|
980
|
-
parser.write(
|
|
980
|
+
const accept = (text2) => {
|
|
981
|
+
rawTotal += text2.length;
|
|
982
|
+
parser.write(text2);
|
|
981
983
|
};
|
|
982
984
|
return {
|
|
983
985
|
write: (bytes) => {
|
|
@@ -1019,11 +1021,11 @@ async function* historyRecordWindows(path, info, mode, from, until, limit, layou
|
|
|
1019
1021
|
let offset = from;
|
|
1020
1022
|
let pending2 = "";
|
|
1021
1023
|
const ready = [];
|
|
1022
|
-
const accept = (
|
|
1024
|
+
const accept = (text2) => {
|
|
1023
1025
|
const begin = Math.max(0, from - seen);
|
|
1024
|
-
const end = Math.min(
|
|
1025
|
-
seen +=
|
|
1026
|
-
if (end > begin) pending2 +=
|
|
1026
|
+
const end = Math.min(text2.length, until - seen);
|
|
1027
|
+
seen += text2.length;
|
|
1028
|
+
if (end > begin) pending2 += text2.slice(begin, end);
|
|
1027
1029
|
while (pending2.length >= limit) {
|
|
1028
1030
|
let size = limit;
|
|
1029
1031
|
const code = pending2.charCodeAt(size - 1);
|
|
@@ -1037,9 +1039,9 @@ async function* historyRecordWindows(path, info, mode, from, until, limit, layou
|
|
|
1037
1039
|
const parser = mode === "raw" ? void 0 : new OversizedRecordParser(textFields(selected.textPaths, accept), Number.MAX_SAFE_INTEGER, {
|
|
1038
1040
|
pruneEmpty: true
|
|
1039
1041
|
});
|
|
1040
|
-
for await (const
|
|
1041
|
-
if (parser === void 0) accept(
|
|
1042
|
-
else parser.write(
|
|
1042
|
+
for await (const text2 of historyText(path, info.range, signal)) {
|
|
1043
|
+
if (parser === void 0) accept(text2);
|
|
1044
|
+
else parser.write(text2);
|
|
1043
1045
|
while (ready.length > 0) yield ready.shift();
|
|
1044
1046
|
if (seen >= until) break;
|
|
1045
1047
|
}
|
|
@@ -1051,7 +1053,7 @@ var verifyHistoryRecord = async (path, range, layout, signal) => {
|
|
|
1051
1053
|
pruneEmpty: true
|
|
1052
1054
|
});
|
|
1053
1055
|
try {
|
|
1054
|
-
for await (const
|
|
1056
|
+
for await (const text2 of historyText(path, range, signal)) parser.write(text2);
|
|
1055
1057
|
} catch (error) {
|
|
1056
1058
|
if (!range.terminated && error instanceof TypeError) return false;
|
|
1057
1059
|
throw error;
|
|
@@ -1090,7 +1092,7 @@ var width = (n) => String(n).padStart(20, "0");
|
|
|
1090
1092
|
var high = (n) => n >= 55296 && n <= 56319;
|
|
1091
1093
|
var low = (n) => n >= 56320 && n <= 57343;
|
|
1092
1094
|
var totalOf = (info, index) => info.items[index].text === "raw" ? info.rawTotal : info.messageTotal;
|
|
1093
|
-
var nativeItem = (identity, info, index, offset,
|
|
1095
|
+
var nativeItem = (identity, info, index, offset, text2) => {
|
|
1094
1096
|
const { text: _mode, ...item } = info.items[index];
|
|
1095
1097
|
const total = totalOf(info, index);
|
|
1096
1098
|
const position = { e: identity, p: info.range.start, k: index, h: info.hash };
|
|
@@ -1099,13 +1101,13 @@ var nativeItem = (identity, info, index, offset, text) => {
|
|
|
1099
1101
|
id: `${identity}:${info.range.start}:${index}`,
|
|
1100
1102
|
orderKey: `${width(info.range.start)}:${width(index)}`,
|
|
1101
1103
|
beforeCursor: encode({ ...position, o: offset }),
|
|
1102
|
-
afterCursor: encode({ ...position, o: offset +
|
|
1103
|
-
text,
|
|
1104
|
+
afterCursor: encode({ ...position, o: offset + text2.length }),
|
|
1105
|
+
text: text2,
|
|
1104
1106
|
textWindow: {
|
|
1105
1107
|
offset,
|
|
1106
|
-
returned:
|
|
1108
|
+
returned: text2.length,
|
|
1107
1109
|
total,
|
|
1108
|
-
nextOffset: offset +
|
|
1110
|
+
nextOffset: offset + text2.length < total ? offset + text2.length : null
|
|
1109
1111
|
}
|
|
1110
1112
|
};
|
|
1111
1113
|
};
|
|
@@ -1129,7 +1131,7 @@ var readWindow = async (path, info, index, from, until, layout, signal, cached)
|
|
|
1129
1131
|
cached.text = parts.join("");
|
|
1130
1132
|
cached.mode = mode;
|
|
1131
1133
|
}
|
|
1132
|
-
let
|
|
1134
|
+
let text2 = cached.mode === mode ? cached.text?.slice(base, end) ?? "" : "";
|
|
1133
1135
|
if (cached.mode !== mode) {
|
|
1134
1136
|
for await (const window2 of historyRecordWindows(
|
|
1135
1137
|
path,
|
|
@@ -1141,13 +1143,13 @@ var readWindow = async (path, info, index, from, until, layout, signal, cached)
|
|
|
1141
1143
|
layout,
|
|
1142
1144
|
signal
|
|
1143
1145
|
))
|
|
1144
|
-
|
|
1146
|
+
text2 += window2.text;
|
|
1145
1147
|
}
|
|
1146
1148
|
let startIndex = from - base;
|
|
1147
1149
|
let endIndex = until - base;
|
|
1148
|
-
if (low(
|
|
1149
|
-
if (low(
|
|
1150
|
-
return { offset: base + startIndex, text:
|
|
1150
|
+
if (low(text2.charCodeAt(startIndex)) && high(text2.charCodeAt(startIndex - 1))) startIndex -= 1;
|
|
1151
|
+
if (low(text2.charCodeAt(endIndex)) && high(text2.charCodeAt(endIndex - 1))) endIndex -= 1;
|
|
1152
|
+
return { offset: base + startIndex, text: text2.slice(startIndex, endIndex) };
|
|
1151
1153
|
};
|
|
1152
1154
|
async function openJsonlHistory(path, layout, signal) {
|
|
1153
1155
|
const controller = new AbortController();
|
|
@@ -1544,10 +1546,10 @@ async function readClaudeTranscriptDigest(filePath) {
|
|
|
1544
1546
|
continue;
|
|
1545
1547
|
}
|
|
1546
1548
|
if (typed.type !== "user") continue;
|
|
1547
|
-
const
|
|
1548
|
-
if (
|
|
1549
|
+
const text2 = textFromContent(typed.message?.content);
|
|
1550
|
+
if (text2.length === 0) continue;
|
|
1549
1551
|
turnCount += 1;
|
|
1550
|
-
if (preview === null) preview =
|
|
1552
|
+
if (preview === null) preview = text2;
|
|
1551
1553
|
}
|
|
1552
1554
|
} catch {
|
|
1553
1555
|
return null;
|
|
@@ -1729,20 +1731,20 @@ async function readClaudeSessionRecord(input) {
|
|
|
1729
1731
|
const content = message.content;
|
|
1730
1732
|
const blocks = typeof content === "string" ? [{ type: "text", text: content }] : Array.isArray(content) ? content : [];
|
|
1731
1733
|
const hasToolResult = blocks.some((block) => isRecord(block) && block.type === "tool_result");
|
|
1732
|
-
const
|
|
1734
|
+
const text2 = blocks.flatMap((block) => {
|
|
1733
1735
|
const typed = isRecord(block) ? block : void 0;
|
|
1734
1736
|
if (!typed) return [];
|
|
1735
1737
|
if (typed.type === "text" && typeof typed.text === "string") return [typed.text];
|
|
1736
1738
|
return [];
|
|
1737
1739
|
}).join("\n\n").trim();
|
|
1738
|
-
if (
|
|
1740
|
+
if (text2.length === 0) continue;
|
|
1739
1741
|
if (value.type === "user" && hasToolResult) continue;
|
|
1740
1742
|
const role = value.type === "assistant" ? "assistant" : "user";
|
|
1741
1743
|
if (role === "assistant" && typeof message.model === "string") model = message.model;
|
|
1742
1744
|
const timestamp = typeof value.timestamp === "string" ? Date.parse(value.timestamp) : typeof value.timestamp === "number" ? value.timestamp : void 0;
|
|
1743
1745
|
messages.push({
|
|
1744
1746
|
role,
|
|
1745
|
-
text,
|
|
1747
|
+
text: text2,
|
|
1746
1748
|
...timestamp !== void 0 && Number.isFinite(timestamp) ? { createdAt: timestamp } : {}
|
|
1747
1749
|
});
|
|
1748
1750
|
}
|
|
@@ -1789,8 +1791,8 @@ var claudeHistoryLayout = (input) => () => {
|
|
|
1789
1791
|
].map((key) => ({ path: [key], scalarOnly: true, maxChars: 2048 })),
|
|
1790
1792
|
{
|
|
1791
1793
|
path: ["message", "content", "*", "type"],
|
|
1792
|
-
onChunk: (
|
|
1793
|
-
blockType = (blockType +
|
|
1794
|
+
onChunk: (text2) => {
|
|
1795
|
+
blockType = (blockType + text2).slice(0, 128);
|
|
1794
1796
|
},
|
|
1795
1797
|
onEnd: () => {
|
|
1796
1798
|
hasTools ||= blockType === "tool_use" || blockType === "tool_result";
|
|
@@ -1800,20 +1802,20 @@ var claudeHistoryLayout = (input) => () => {
|
|
|
1800
1802
|
},
|
|
1801
1803
|
{
|
|
1802
1804
|
path: ["message", "content", "*", "name"],
|
|
1803
|
-
onChunk: (
|
|
1804
|
-
name = (name +
|
|
1805
|
+
onChunk: (text2) => {
|
|
1806
|
+
name = (name + text2).slice(0, 256);
|
|
1805
1807
|
}
|
|
1806
1808
|
},
|
|
1807
1809
|
{
|
|
1808
1810
|
path: ["message", "content", "*", "id"],
|
|
1809
|
-
onChunk: (
|
|
1810
|
-
toolCallId = (toolCallId +
|
|
1811
|
+
onChunk: (text2) => {
|
|
1812
|
+
toolCallId = (toolCallId + text2).slice(0, 256);
|
|
1811
1813
|
}
|
|
1812
1814
|
},
|
|
1813
1815
|
{
|
|
1814
1816
|
path: ["message", "content", "*", "tool_use_id"],
|
|
1815
|
-
onChunk: (
|
|
1816
|
-
toolCallId = (toolCallId +
|
|
1817
|
+
onChunk: (text2) => {
|
|
1818
|
+
toolCallId = (toolCallId + text2).slice(0, 256);
|
|
1817
1819
|
}
|
|
1818
1820
|
}
|
|
1819
1821
|
],
|
|
@@ -1867,7 +1869,7 @@ var openClaudeHistory = (input) => {
|
|
|
1867
1869
|
};
|
|
1868
1870
|
|
|
1869
1871
|
// src/claudeInstance.ts
|
|
1870
|
-
import * as
|
|
1872
|
+
import * as NodeOS10 from "node:os";
|
|
1871
1873
|
import * as NodePath19 from "node:path";
|
|
1872
1874
|
|
|
1873
1875
|
// ../../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
|
|
@@ -21301,15 +21303,19 @@ function HU(e, t) {
|
|
|
21301
21303
|
}
|
|
21302
21304
|
|
|
21303
21305
|
// src/claudeInstance.ts
|
|
21304
|
-
import { mergeLaunchEnv as
|
|
21306
|
+
import { mergeLaunchEnv as mergeLaunchEnv4 } from "@ycodium-ai/plugin-api/executor";
|
|
21307
|
+
import { isOperationCleanupError as isOperationCleanupError3 } from "@ycodium-ai/plugin-api/process-operation";
|
|
21305
21308
|
|
|
21306
21309
|
// src/claudeProbe.ts
|
|
21307
21310
|
import {
|
|
21308
21311
|
describeExecutorSpawnFailure,
|
|
21309
21312
|
ExecutorSpawnAbortedError,
|
|
21310
|
-
ExecutorSpawnRefusedError
|
|
21311
|
-
raceAbort
|
|
21313
|
+
ExecutorSpawnRefusedError
|
|
21312
21314
|
} from "@ycodium-ai/plugin-api/executor";
|
|
21315
|
+
import {
|
|
21316
|
+
runProcessOperation,
|
|
21317
|
+
isOperationCleanupError
|
|
21318
|
+
} from "@ycodium-ai/plugin-api/process-operation";
|
|
21313
21319
|
|
|
21314
21320
|
// src/claudeAccount.ts
|
|
21315
21321
|
import * as NodeFS4 from "node:fs";
|
|
@@ -21368,10 +21374,10 @@ function claudeCredentialCandidatePaths(input) {
|
|
|
21368
21374
|
NodePath5.join(input.homePath, ".credentials.json")
|
|
21369
21375
|
] : [NodePath5.join(input.credentialsDirPath, ".credentials.json")];
|
|
21370
21376
|
}
|
|
21371
|
-
function readClaudeAccount(credentialsDirPath) {
|
|
21377
|
+
function readClaudeAccount(credentialsDirPath, credentialCandidates) {
|
|
21372
21378
|
const accountDirectory = resolveClaudeAccountDirectory(credentialsDirPath);
|
|
21373
21379
|
const exists = directoryExists(accountDirectory);
|
|
21374
|
-
const candidates = claudeCredentialCandidatePaths({
|
|
21380
|
+
const candidates = credentialCandidates ?? claudeCredentialCandidatePaths({
|
|
21375
21381
|
homePath: NodeOS2.homedir(),
|
|
21376
21382
|
credentialsDirPath
|
|
21377
21383
|
});
|
|
@@ -21398,6 +21404,14 @@ function readClaudeAccount(credentialsDirPath) {
|
|
|
21398
21404
|
};
|
|
21399
21405
|
}
|
|
21400
21406
|
|
|
21407
|
+
// src/usageRead/quota.ts
|
|
21408
|
+
import * as NodeFS5 from "node:fs";
|
|
21409
|
+
import * as NodePath8 from "node:path";
|
|
21410
|
+
import { mergeLaunchEnv, setsOwnModelConnection } from "@ycodium-ai/plugin-api/executor";
|
|
21411
|
+
import {
|
|
21412
|
+
parseRetryAfterMs
|
|
21413
|
+
} from "@ycodium-ai/plugin-api/usage";
|
|
21414
|
+
|
|
21401
21415
|
// src/claudeHome.ts
|
|
21402
21416
|
import * as NodeOS4 from "node:os";
|
|
21403
21417
|
import * as NodePath7 from "node:path";
|
|
@@ -21547,9 +21561,171 @@ function claudeFailureHint(input) {
|
|
|
21547
21561
|
return void 0;
|
|
21548
21562
|
}
|
|
21549
21563
|
|
|
21564
|
+
// src/usageRead/quota.ts
|
|
21565
|
+
var CLAUDE_QUOTA_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
21566
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
21567
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
21568
|
+
var CLAUDE_QUOTA_WINDOWS = [
|
|
21569
|
+
{ field: "five_hour", id: "session", labelKey: "usage.window.session", windowMs: 5 * HOUR_MS },
|
|
21570
|
+
{ field: "seven_day", id: "weekly", labelKey: "usage.window.weekly", windowMs: 7 * 24 * HOUR_MS }
|
|
21571
|
+
];
|
|
21572
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21573
|
+
var launchEnvironment = (recipe) => mergeLaunchEnv({
|
|
21574
|
+
inherited: process.env,
|
|
21575
|
+
instanceTable: recipe.environment,
|
|
21576
|
+
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
21577
|
+
});
|
|
21578
|
+
var claudeCredentialFileCandidates = (recipe) => {
|
|
21579
|
+
const environment = launchEnvironment(recipe);
|
|
21580
|
+
const credentialsDir = resolveClaudeCredentialsDirPath(
|
|
21581
|
+
environment[CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE] ?? ""
|
|
21582
|
+
);
|
|
21583
|
+
if (credentialsDir !== null) return [NodePath8.join(credentialsDir, ".credentials.json")];
|
|
21584
|
+
const configDir = resolveClaudeConfigDirPath(recipe.homePath, environment);
|
|
21585
|
+
const home = resolveClaudeHomePath(recipe.homePath);
|
|
21586
|
+
return [
|
|
21587
|
+
.../* @__PURE__ */ new Set([
|
|
21588
|
+
NodePath8.join(configDir, ".credentials.json"),
|
|
21589
|
+
NodePath8.join(home, ".claude", ".credentials.json"),
|
|
21590
|
+
NodePath8.join(home, ".credentials.json")
|
|
21591
|
+
])
|
|
21592
|
+
];
|
|
21593
|
+
};
|
|
21594
|
+
var readString = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
21595
|
+
var readLoginCredential = (candidates) => {
|
|
21596
|
+
for (const path of candidates) {
|
|
21597
|
+
let raw;
|
|
21598
|
+
try {
|
|
21599
|
+
raw = NodeFS5.readFileSync(path, "utf8");
|
|
21600
|
+
} catch {
|
|
21601
|
+
continue;
|
|
21602
|
+
}
|
|
21603
|
+
if (raw.trim().length === 0) continue;
|
|
21604
|
+
let parsed;
|
|
21605
|
+
try {
|
|
21606
|
+
parsed = JSON.parse(raw);
|
|
21607
|
+
} catch {
|
|
21608
|
+
continue;
|
|
21609
|
+
}
|
|
21610
|
+
const oauth = isRecord3(parsed) ? parsed["claudeAiOauth"] : void 0;
|
|
21611
|
+
if (!isRecord3(oauth)) continue;
|
|
21612
|
+
const accessToken = readString(oauth["accessToken"]);
|
|
21613
|
+
if (accessToken === void 0) continue;
|
|
21614
|
+
return {
|
|
21615
|
+
accessToken,
|
|
21616
|
+
subscriptionType: readString(oauth["subscriptionType"]),
|
|
21617
|
+
rateLimitTier: readString(oauth["rateLimitTier"]),
|
|
21618
|
+
path
|
|
21619
|
+
};
|
|
21620
|
+
}
|
|
21621
|
+
return null;
|
|
21622
|
+
};
|
|
21623
|
+
var claudePlanName = (credential) => {
|
|
21624
|
+
const type4 = credential.subscriptionType;
|
|
21625
|
+
if (type4 === void 0) return void 0;
|
|
21626
|
+
const name = `${type4.charAt(0).toUpperCase()}${type4.slice(1)}`;
|
|
21627
|
+
const multiplier = /(?:^|_)(\d+x)$/.exec(credential.rateLimitTier ?? "")?.[1];
|
|
21628
|
+
return multiplier === void 0 ? name : `${name} ${multiplier}`;
|
|
21629
|
+
};
|
|
21630
|
+
var toIso = (value) => {
|
|
21631
|
+
if (typeof value !== "string") return null;
|
|
21632
|
+
const parsed = Date.parse(value);
|
|
21633
|
+
return Number.isNaN(parsed) ? null : new Date(parsed).toISOString();
|
|
21634
|
+
};
|
|
21635
|
+
var readClaudeQuotaWindows = (body) => CLAUDE_QUOTA_WINDOWS.flatMap((spec) => {
|
|
21636
|
+
const row = body[spec.field];
|
|
21637
|
+
if (!isRecord3(row)) return [];
|
|
21638
|
+
const utilization = row["utilization"];
|
|
21639
|
+
if (typeof utilization !== "number" || !Number.isFinite(utilization)) return [];
|
|
21640
|
+
return [
|
|
21641
|
+
{
|
|
21642
|
+
id: spec.id,
|
|
21643
|
+
label: { key: spec.labelKey },
|
|
21644
|
+
usedPercent: Math.min(100, Math.max(0, utilization)),
|
|
21645
|
+
resetsAt: toIso(row["resets_at"]),
|
|
21646
|
+
windowMs: spec.windowMs
|
|
21647
|
+
}
|
|
21648
|
+
];
|
|
21649
|
+
});
|
|
21650
|
+
var readClaudeQuota = async (request) => {
|
|
21651
|
+
const { recipe } = request;
|
|
21652
|
+
const connectivity = CLAUDE_CARD.modelConnectivity;
|
|
21653
|
+
const environmentRows = Object.entries(recipe.environment).map(([name, value]) => ({
|
|
21654
|
+
name,
|
|
21655
|
+
value
|
|
21656
|
+
}));
|
|
21657
|
+
if (connectivity !== void 0 && setsOwnModelConnection(connectivity, environmentRows)) {
|
|
21658
|
+
const changesEndpoint = setsOwnModelConnection(
|
|
21659
|
+
{
|
|
21660
|
+
baseUrlEnvKey: connectivity.baseUrlEnvKey,
|
|
21661
|
+
backendSwitchEnvKeys: connectivity.backendSwitchEnvKeys
|
|
21662
|
+
},
|
|
21663
|
+
environmentRows
|
|
21664
|
+
);
|
|
21665
|
+
return {
|
|
21666
|
+
status: "unavailable",
|
|
21667
|
+
reason: changesEndpoint ? "customEndpoint" : "unsupportedLogin"
|
|
21668
|
+
};
|
|
21669
|
+
}
|
|
21670
|
+
const credential = readLoginCredential(claudeCredentialFileCandidates(recipe));
|
|
21671
|
+
if (credential === null) return { status: "unavailable", reason: "missingCredentials" };
|
|
21672
|
+
const now = request.now ?? Date.now;
|
|
21673
|
+
let response;
|
|
21674
|
+
try {
|
|
21675
|
+
response = await request.fetch(CLAUDE_QUOTA_URL, {
|
|
21676
|
+
method: "GET",
|
|
21677
|
+
headers: {
|
|
21678
|
+
Accept: "application/json",
|
|
21679
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
21680
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
21681
|
+
},
|
|
21682
|
+
redirect: "error",
|
|
21683
|
+
signal: request.signal === void 0 ? AbortSignal.timeout(REQUEST_TIMEOUT_MS) : AbortSignal.any([request.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)])
|
|
21684
|
+
});
|
|
21685
|
+
} catch (cause) {
|
|
21686
|
+
if (request.signal?.aborted === true) throw cause;
|
|
21687
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
21688
|
+
}
|
|
21689
|
+
const release = () => {
|
|
21690
|
+
void response.body?.cancel().catch(() => void 0);
|
|
21691
|
+
};
|
|
21692
|
+
if (response.status === 429) {
|
|
21693
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("Retry-After"), now());
|
|
21694
|
+
release();
|
|
21695
|
+
return {
|
|
21696
|
+
status: "unavailable",
|
|
21697
|
+
reason: "rateLimited",
|
|
21698
|
+
...retryAfterMs === null ? {} : { retryAfterMs }
|
|
21699
|
+
};
|
|
21700
|
+
}
|
|
21701
|
+
if (response.status === 401 || response.status === 403) {
|
|
21702
|
+
release();
|
|
21703
|
+
return { status: "unavailable", reason: "authRejected" };
|
|
21704
|
+
}
|
|
21705
|
+
if (response.status < 200 || response.status >= 300) {
|
|
21706
|
+
release();
|
|
21707
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
21708
|
+
}
|
|
21709
|
+
let body;
|
|
21710
|
+
try {
|
|
21711
|
+
body = JSON.parse(await response.text());
|
|
21712
|
+
} catch {
|
|
21713
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
21714
|
+
}
|
|
21715
|
+
if (!isRecord3(body)) return { status: "unavailable", reason: "unreachable" };
|
|
21716
|
+
const plan = claudePlanName(credential);
|
|
21717
|
+
return {
|
|
21718
|
+
status: "available",
|
|
21719
|
+
...plan === void 0 ? {} : { plan },
|
|
21720
|
+
windows: readClaudeQuotaWindows(body),
|
|
21721
|
+
balances: [],
|
|
21722
|
+
accountKey: credential.path
|
|
21723
|
+
};
|
|
21724
|
+
};
|
|
21725
|
+
|
|
21550
21726
|
// src/claudeSkills.ts
|
|
21551
21727
|
import * as NodeFSP3 from "node:fs/promises";
|
|
21552
|
-
import * as
|
|
21728
|
+
import * as NodePath9 from "node:path";
|
|
21553
21729
|
import * as NodeProcess3 from "node:process";
|
|
21554
21730
|
var FRONT_MATTER_KEY = /^(description|disable-model-invocation|user-invocable|argument-hint):[ \t]*(.*)$/;
|
|
21555
21731
|
var BLOCK_SCALAR = /^[|>][+-]?$/;
|
|
@@ -21615,7 +21791,7 @@ function claudeManagedSettingsPath(platform4, environment) {
|
|
|
21615
21791
|
}
|
|
21616
21792
|
if (platform4 === "win32") {
|
|
21617
21793
|
const programData = environment["PROGRAMDATA"]?.trim();
|
|
21618
|
-
return programData ?
|
|
21794
|
+
return programData ? NodePath9.join(programData, "ClaudeCode", "managed-settings.json") : void 0;
|
|
21619
21795
|
}
|
|
21620
21796
|
return "/etc/claude-code/managed-settings.json";
|
|
21621
21797
|
}
|
|
@@ -21623,44 +21799,44 @@ function skillOverrideSettingsPaths(configDirPath, cwd, platform4, environment,
|
|
|
21623
21799
|
const managedPath = claudeManagedSettingsPath(platform4, environment);
|
|
21624
21800
|
const root = repositoryRoot !== void 0 && repositoryRoot !== cwd ? repositoryRoot : void 0;
|
|
21625
21801
|
return [
|
|
21626
|
-
|
|
21802
|
+
NodePath9.join(configDirPath, "settings.json"),
|
|
21627
21803
|
...cwd ? [
|
|
21628
|
-
|
|
21629
|
-
|
|
21804
|
+
NodePath9.join(cwd, ".claude", "settings.json"),
|
|
21805
|
+
NodePath9.join(cwd, ".claude", "settings.local.json")
|
|
21630
21806
|
] : [],
|
|
21631
|
-
...root ? [
|
|
21807
|
+
...root ? [NodePath9.join(root, ".claude", "settings.local.json")] : [],
|
|
21632
21808
|
...managedPath ? [managedPath] : []
|
|
21633
21809
|
];
|
|
21634
21810
|
}
|
|
21635
21811
|
async function findRepositoryRoot(cwd) {
|
|
21636
|
-
let current =
|
|
21812
|
+
let current = NodePath9.resolve(cwd);
|
|
21637
21813
|
for (; ; ) {
|
|
21638
|
-
const found = await NodeFSP3.stat(
|
|
21814
|
+
const found = await NodeFSP3.stat(NodePath9.join(current, ".git")).then(
|
|
21639
21815
|
() => true,
|
|
21640
21816
|
() => false
|
|
21641
21817
|
);
|
|
21642
21818
|
if (found) return current;
|
|
21643
|
-
const parent =
|
|
21819
|
+
const parent = NodePath9.dirname(current);
|
|
21644
21820
|
if (parent === current) return void 0;
|
|
21645
21821
|
current = parent;
|
|
21646
21822
|
}
|
|
21647
21823
|
}
|
|
21648
|
-
function parseLenientJson(
|
|
21824
|
+
function parseLenientJson(text2) {
|
|
21649
21825
|
let output = "";
|
|
21650
21826
|
let index = 0;
|
|
21651
|
-
while (index <
|
|
21652
|
-
const char =
|
|
21653
|
-
const next =
|
|
21827
|
+
while (index < text2.length) {
|
|
21828
|
+
const char = text2[index];
|
|
21829
|
+
const next = text2[index + 1];
|
|
21654
21830
|
if (char === '"') {
|
|
21655
21831
|
let end = index + 1;
|
|
21656
|
-
while (end <
|
|
21657
|
-
output +=
|
|
21832
|
+
while (end < text2.length && text2[end] !== '"') end += text2[end] === "\\" ? 2 : 1;
|
|
21833
|
+
output += text2.slice(index, end + 1);
|
|
21658
21834
|
index = end + 1;
|
|
21659
21835
|
} else if (char === "/" && next === "/") {
|
|
21660
|
-
while (index <
|
|
21836
|
+
while (index < text2.length && text2[index] !== "\n") index += 1;
|
|
21661
21837
|
} else if (char === "/" && next === "*") {
|
|
21662
|
-
const end =
|
|
21663
|
-
index = end === -1 ?
|
|
21838
|
+
const end = text2.indexOf("*/", index + 2);
|
|
21839
|
+
index = end === -1 ? text2.length : end + 2;
|
|
21664
21840
|
} else {
|
|
21665
21841
|
output += char;
|
|
21666
21842
|
index += 1;
|
|
@@ -21675,10 +21851,10 @@ var SKILL_OVERRIDE_BY_VALUE = {
|
|
|
21675
21851
|
on: { enabled: true, userInvocationOnly: false },
|
|
21676
21852
|
"name-only": { enabled: true, userInvocationOnly: false }
|
|
21677
21853
|
};
|
|
21678
|
-
function readOverridesFromSettings(
|
|
21854
|
+
function readOverridesFromSettings(text2) {
|
|
21679
21855
|
let parsed;
|
|
21680
21856
|
try {
|
|
21681
|
-
parsed = parseLenientJson(
|
|
21857
|
+
parsed = parseLenientJson(text2);
|
|
21682
21858
|
} catch {
|
|
21683
21859
|
return void 0;
|
|
21684
21860
|
}
|
|
@@ -21722,8 +21898,8 @@ async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
|
21722
21898
|
options.environment ?? NodeProcess3.env
|
|
21723
21899
|
);
|
|
21724
21900
|
const roots = [
|
|
21725
|
-
{ directory:
|
|
21726
|
-
...cwd ? [{ directory:
|
|
21901
|
+
{ directory: NodePath9.join(configDirPath, "skills"), scope: "user" },
|
|
21902
|
+
...cwd ? [{ directory: NodePath9.join(cwd, ".claude", "skills"), scope: "project" }] : []
|
|
21727
21903
|
];
|
|
21728
21904
|
const skills = /* @__PURE__ */ new Map();
|
|
21729
21905
|
for (const root of roots) {
|
|
@@ -21731,7 +21907,7 @@ async function discoverClaudeSkills(configDirPath, options = {}) {
|
|
|
21731
21907
|
for (const entry of entries.toSorted()) {
|
|
21732
21908
|
const name = entry.trim();
|
|
21733
21909
|
if (name.length === 0 || skills.has(name)) continue;
|
|
21734
|
-
const skillPath =
|
|
21910
|
+
const skillPath = NodePath9.join(root.directory, entry, "SKILL.md");
|
|
21735
21911
|
const contents = await NodeFSP3.readFile(skillPath, "utf8").catch(() => void 0);
|
|
21736
21912
|
if (contents === void 0) continue;
|
|
21737
21913
|
const frontMatter = parseSkillFrontMatter(contents);
|
|
@@ -21794,15 +21970,15 @@ function knownClaudeModelCapabilities(model, catalog, customModels) {
|
|
|
21794
21970
|
function claudeModelCapabilities(model, catalog, customModels) {
|
|
21795
21971
|
return knownClaudeModelCapabilities(model, catalog, customModels) ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES;
|
|
21796
21972
|
}
|
|
21797
|
-
function
|
|
21973
|
+
function isRecord4(value) {
|
|
21798
21974
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21799
21975
|
}
|
|
21800
21976
|
function getModelSelectionStringOptionValue(modelSelection, optionId) {
|
|
21801
|
-
if (!
|
|
21977
|
+
if (!isRecord4(modelSelection)) return void 0;
|
|
21802
21978
|
const options = modelSelection["options"];
|
|
21803
21979
|
if (!Array.isArray(options)) return void 0;
|
|
21804
21980
|
for (const entry of options) {
|
|
21805
|
-
if (!
|
|
21981
|
+
if (!isRecord4(entry)) continue;
|
|
21806
21982
|
if (entry["id"] === optionId && typeof entry["value"] === "string") {
|
|
21807
21983
|
const trimmed = entry["value"].trim();
|
|
21808
21984
|
if (trimmed.length > 0) return trimmed;
|
|
@@ -21811,11 +21987,11 @@ function getModelSelectionStringOptionValue(modelSelection, optionId) {
|
|
|
21811
21987
|
return void 0;
|
|
21812
21988
|
}
|
|
21813
21989
|
function getModelSelectionBooleanOptionValue(modelSelection, optionId) {
|
|
21814
|
-
if (!
|
|
21990
|
+
if (!isRecord4(modelSelection)) return void 0;
|
|
21815
21991
|
const options = modelSelection["options"];
|
|
21816
21992
|
if (!Array.isArray(options)) return void 0;
|
|
21817
21993
|
for (const entry of options) {
|
|
21818
|
-
if (!
|
|
21994
|
+
if (!isRecord4(entry)) continue;
|
|
21819
21995
|
if (entry["id"] === optionId && typeof entry["value"] === "boolean") {
|
|
21820
21996
|
return entry["value"];
|
|
21821
21997
|
}
|
|
@@ -21823,7 +21999,7 @@ function getModelSelectionBooleanOptionValue(modelSelection, optionId) {
|
|
|
21823
21999
|
return void 0;
|
|
21824
22000
|
}
|
|
21825
22001
|
function modelIdFromSelection(selection) {
|
|
21826
|
-
if (!
|
|
22002
|
+
if (!isRecord4(selection)) return void 0;
|
|
21827
22003
|
const model = selection["model"];
|
|
21828
22004
|
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
21829
22005
|
}
|
|
@@ -22065,16 +22241,12 @@ function claudeToolSearchNotice(version, environment) {
|
|
|
22065
22241
|
var CLAUDE_PROGRAM_NOT_CONFIGURED = "Claude program path is not configured";
|
|
22066
22242
|
function createClaudeProbe(input) {
|
|
22067
22243
|
const { recipe, host, modelCatalog } = input;
|
|
22068
|
-
const collectProcessText = async (stream) => {
|
|
22069
|
-
const chunks = [];
|
|
22070
|
-
for await (const chunk of stream) {
|
|
22071
|
-
chunks.push(Buffer.from(chunk));
|
|
22072
|
-
}
|
|
22073
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
22074
|
-
};
|
|
22075
22244
|
const probeAuth = () => {
|
|
22076
|
-
const
|
|
22077
|
-
|
|
22245
|
+
const native = modelCatalog.currentAuth?.();
|
|
22246
|
+
if (native !== void 0) return native;
|
|
22247
|
+
const environment = input.launchEnvironment();
|
|
22248
|
+
const hasEnvToken = (environment.ANTHROPIC_AUTH_TOKEN ?? "").trim().length > 0;
|
|
22249
|
+
const hasEnvApiKey = (environment.ANTHROPIC_API_KEY ?? "").trim().length > 0;
|
|
22078
22250
|
if (hasEnvToken || hasEnvApiKey) {
|
|
22079
22251
|
return {
|
|
22080
22252
|
status: "authenticated",
|
|
@@ -22082,13 +22254,15 @@ function createClaudeProbe(input) {
|
|
|
22082
22254
|
label: hasEnvToken ? "ANTHROPIC_AUTH_TOKEN" : "ANTHROPIC_API_KEY"
|
|
22083
22255
|
};
|
|
22084
22256
|
}
|
|
22085
|
-
const account = readClaudeAccount(
|
|
22257
|
+
const account = readClaudeAccount(
|
|
22258
|
+
resolveClaudeCredentialsDirPath(recipe.credentialsPath),
|
|
22259
|
+
claudeCredentialFileCandidates(recipe)
|
|
22260
|
+
);
|
|
22086
22261
|
switch (account.state) {
|
|
22087
22262
|
case "signed-in":
|
|
22088
|
-
case "expired":
|
|
22089
22263
|
return { status: "authenticated" };
|
|
22264
|
+
case "expired":
|
|
22090
22265
|
case "signed-out":
|
|
22091
|
-
return { status: "unauthenticated" };
|
|
22092
22266
|
case "unreadable":
|
|
22093
22267
|
return { status: "unknown" };
|
|
22094
22268
|
}
|
|
@@ -22107,16 +22281,31 @@ function createClaudeProbe(input) {
|
|
|
22107
22281
|
if (signal?.aborted) {
|
|
22108
22282
|
throw new ExecutorSpawnAbortedError();
|
|
22109
22283
|
}
|
|
22110
|
-
let
|
|
22284
|
+
let command;
|
|
22285
|
+
let commandStarted = false;
|
|
22286
|
+
const commandHost = {
|
|
22287
|
+
...host,
|
|
22288
|
+
process: {
|
|
22289
|
+
spawn: async (request) => {
|
|
22290
|
+
const handle = await host.process.spawn(request);
|
|
22291
|
+
commandStarted = true;
|
|
22292
|
+
return handle;
|
|
22293
|
+
}
|
|
22294
|
+
}
|
|
22295
|
+
};
|
|
22111
22296
|
try {
|
|
22112
|
-
|
|
22297
|
+
command = await runProcessOperation(commandHost, {
|
|
22113
22298
|
program: recipe.binaryPath,
|
|
22114
22299
|
args: ["--version"],
|
|
22300
|
+
timeoutMs: CLAUDE_VERSION_TIMEOUT_MS,
|
|
22301
|
+
maxOutputBytes: 64 * 1024,
|
|
22115
22302
|
owner: { bindingId: host.bindingId },
|
|
22116
22303
|
...signal === void 0 ? {} : { signal }
|
|
22117
22304
|
});
|
|
22118
22305
|
} catch (error) {
|
|
22119
|
-
if (error
|
|
22306
|
+
if (isOperationCleanupError(error)) throw error;
|
|
22307
|
+
if (signal?.aborted) throw new ExecutorSpawnAbortedError();
|
|
22308
|
+
if (commandStarted || error instanceof ExecutorSpawnRefusedError || error instanceof ExecutorSpawnAbortedError) {
|
|
22120
22309
|
throw error;
|
|
22121
22310
|
}
|
|
22122
22311
|
const failure = describeExecutorSpawnFailure(error);
|
|
@@ -22128,14 +22317,7 @@ function createClaudeProbe(input) {
|
|
|
22128
22317
|
detail: failure.detail
|
|
22129
22318
|
};
|
|
22130
22319
|
}
|
|
22131
|
-
const
|
|
22132
|
-
Promise.all([
|
|
22133
|
-
collectProcessText(handle.stdout),
|
|
22134
|
-
collectProcessText(handle.stderr),
|
|
22135
|
-
handle.exited
|
|
22136
|
-
]),
|
|
22137
|
-
signal
|
|
22138
|
-
);
|
|
22320
|
+
const { stdout, stderr, exitCode } = command;
|
|
22139
22321
|
if (signal?.aborted) throw new ExecutorSpawnAbortedError();
|
|
22140
22322
|
const version = parseGenericCliVersion(`${stdout}
|
|
22141
22323
|
${stderr}`);
|
|
@@ -22195,49 +22377,29 @@ ${stderr}`);
|
|
|
22195
22377
|
}
|
|
22196
22378
|
var CLAUDE_VERSION_TIMEOUT_MS = 15e3;
|
|
22197
22379
|
async function readClaudeCliVersion(input) {
|
|
22380
|
+
input.signal?.throwIfAborted();
|
|
22198
22381
|
if (input.recipe.binaryPath.length === 0) return null;
|
|
22199
|
-
let handle;
|
|
22200
22382
|
try {
|
|
22201
|
-
|
|
22383
|
+
const { stdout, stderr } = await runProcessOperation(input.host, {
|
|
22202
22384
|
program: input.recipe.binaryPath,
|
|
22203
22385
|
args: ["--version"],
|
|
22204
|
-
owner: { bindingId: input.host.bindingId }
|
|
22386
|
+
owner: { bindingId: input.host.bindingId },
|
|
22387
|
+
signal: input.signal,
|
|
22388
|
+
timeoutMs: CLAUDE_VERSION_TIMEOUT_MS,
|
|
22389
|
+
maxOutputBytes: 64 * 1024
|
|
22205
22390
|
});
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
const chunks = [];
|
|
22211
|
-
for await (const chunk of stream) chunks.push(Buffer.from(chunk));
|
|
22212
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
22213
|
-
};
|
|
22214
|
-
const collected = Promise.all([collect(handle.stdout), collect(handle.stderr), handle.exited]);
|
|
22215
|
-
let timer;
|
|
22216
|
-
const timeout = new Promise((resolve5) => {
|
|
22217
|
-
timer = setTimeout(() => resolve5("timeout"), CLAUDE_VERSION_TIMEOUT_MS);
|
|
22218
|
-
timer.unref?.();
|
|
22219
|
-
});
|
|
22220
|
-
try {
|
|
22221
|
-
const settled = await Promise.race([collected, timeout]);
|
|
22222
|
-
if (settled === "timeout") {
|
|
22223
|
-
collected.catch(() => void 0);
|
|
22224
|
-
return null;
|
|
22225
|
-
}
|
|
22226
|
-
const [stdout, stderr] = settled;
|
|
22227
|
-
return parseGenericCliVersion(`${stdout}
|
|
22228
|
-
${stderr}`);
|
|
22229
|
-
} catch {
|
|
22391
|
+
return parseGenericCliVersion(stdout + "\n" + stderr);
|
|
22392
|
+
} catch (error) {
|
|
22393
|
+
if (isOperationCleanupError(error)) throw error;
|
|
22394
|
+
input.signal?.throwIfAborted();
|
|
22230
22395
|
return null;
|
|
22231
|
-
} finally {
|
|
22232
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
22233
|
-
await handle.kill("SIGTERM").catch(() => void 0);
|
|
22234
22396
|
}
|
|
22235
22397
|
}
|
|
22236
22398
|
|
|
22237
22399
|
// src/claudeExecutable.ts
|
|
22238
|
-
import * as
|
|
22400
|
+
import * as NodeFS6 from "node:fs";
|
|
22239
22401
|
import * as NodeOS5 from "node:os";
|
|
22240
|
-
import * as
|
|
22402
|
+
import * as NodePath10 from "node:path";
|
|
22241
22403
|
var WINDOWS_SHIM_EXTENSIONS = /* @__PURE__ */ new Set([".cmd", ".bat", ".ps1"]);
|
|
22242
22404
|
var NPM_PACKAGE_ENTRY_CANDIDATES = [
|
|
22243
22405
|
["node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe"],
|
|
@@ -22245,7 +22407,7 @@ var NPM_PACKAGE_ENTRY_CANDIDATES = [
|
|
|
22245
22407
|
];
|
|
22246
22408
|
function isExistingFile(filePath) {
|
|
22247
22409
|
try {
|
|
22248
|
-
return
|
|
22410
|
+
return NodeFS6.statSync(filePath).isFile();
|
|
22249
22411
|
} catch {
|
|
22250
22412
|
return false;
|
|
22251
22413
|
}
|
|
@@ -22255,13 +22417,13 @@ function resolveClaudeSdkExecutablePath(binaryPath, environment = process.env, i
|
|
|
22255
22417
|
return binaryPath;
|
|
22256
22418
|
}
|
|
22257
22419
|
const resolved = resolveWindowsExecutable(binaryPath, environment) ?? binaryPath;
|
|
22258
|
-
const extension =
|
|
22420
|
+
const extension = NodePath10.win32.extname(resolved).toLowerCase();
|
|
22259
22421
|
if (!WINDOWS_SHIM_EXTENSIONS.has(extension)) {
|
|
22260
22422
|
return resolved;
|
|
22261
22423
|
}
|
|
22262
|
-
const shimDirectory =
|
|
22424
|
+
const shimDirectory = NodePath10.win32.dirname(resolved);
|
|
22263
22425
|
for (const entrySegments of NPM_PACKAGE_ENTRY_CANDIDATES) {
|
|
22264
|
-
const candidate =
|
|
22426
|
+
const candidate = NodePath10.win32.join(shimDirectory, ...entrySegments);
|
|
22265
22427
|
if (isFile(candidate)) {
|
|
22266
22428
|
return candidate;
|
|
22267
22429
|
}
|
|
@@ -22271,14 +22433,14 @@ function resolveClaudeSdkExecutablePath(binaryPath, environment = process.env, i
|
|
|
22271
22433
|
function resolveWindowsExecutable(binaryPath, environment) {
|
|
22272
22434
|
const trimmed = binaryPath.trim();
|
|
22273
22435
|
if (trimmed.length === 0) return void 0;
|
|
22274
|
-
if (
|
|
22436
|
+
if (NodePath10.win32.isAbsolute(trimmed) && isExistingFile(trimmed)) return trimmed;
|
|
22275
22437
|
const pathValue = environment.PATH ?? environment.Path ?? "";
|
|
22276
22438
|
const pathext = environment.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
22277
22439
|
const extensions = pathext.split(";").filter((ext) => ext.length > 0);
|
|
22278
|
-
const hasExt =
|
|
22440
|
+
const hasExt = NodePath10.win32.extname(trimmed).length > 0;
|
|
22279
22441
|
for (const dir of pathValue.split(";")) {
|
|
22280
22442
|
if (dir.trim().length === 0) continue;
|
|
22281
|
-
const candidates = hasExt ? [
|
|
22443
|
+
const candidates = hasExt ? [NodePath10.win32.join(dir, trimmed)] : extensions.map((ext) => NodePath10.win32.join(dir, `${trimmed}${ext}`));
|
|
22282
22444
|
for (const candidate of candidates) {
|
|
22283
22445
|
if (isExistingFile(candidate)) return candidate;
|
|
22284
22446
|
}
|
|
@@ -22328,7 +22490,7 @@ function asStringField(input, key) {
|
|
|
22328
22490
|
const value = input[key];
|
|
22329
22491
|
return typeof value === "string" ? value : void 0;
|
|
22330
22492
|
}
|
|
22331
|
-
function
|
|
22493
|
+
function readString2(value) {
|
|
22332
22494
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
22333
22495
|
}
|
|
22334
22496
|
function readStringArray(value) {
|
|
@@ -22498,14 +22660,14 @@ function readRangeSuffix(input) {
|
|
|
22498
22660
|
function loneStringValue(input) {
|
|
22499
22661
|
let found;
|
|
22500
22662
|
for (const value of Object.values(input)) {
|
|
22501
|
-
const
|
|
22502
|
-
if (
|
|
22663
|
+
const text2 = asTrimmedString(value);
|
|
22664
|
+
if (text2 === void 0) {
|
|
22503
22665
|
continue;
|
|
22504
22666
|
}
|
|
22505
22667
|
if (found !== void 0) {
|
|
22506
22668
|
return void 0;
|
|
22507
22669
|
}
|
|
22508
|
-
found =
|
|
22670
|
+
found = text2;
|
|
22509
22671
|
}
|
|
22510
22672
|
return found;
|
|
22511
22673
|
}
|
|
@@ -23320,11 +23482,11 @@ var makeAssistantText = (emitter) => {
|
|
|
23320
23482
|
blockIndex: block.blockIndex,
|
|
23321
23483
|
block
|
|
23322
23484
|
}));
|
|
23323
|
-
for (const [position,
|
|
23485
|
+
for (const [position, text2] of snapshotTextBlocks.entries()) {
|
|
23324
23486
|
const existingEntry = orderedBlocks[position];
|
|
23325
23487
|
let entry = existingEntry;
|
|
23326
23488
|
if (!entry) {
|
|
23327
|
-
const created = await createSyntheticAssistantTextBlock(context,
|
|
23489
|
+
const created = await createSyntheticAssistantTextBlock(context, text2);
|
|
23328
23490
|
if (created) {
|
|
23329
23491
|
orderedBlocks.push(created);
|
|
23330
23492
|
}
|
|
@@ -23334,7 +23496,7 @@ var makeAssistantText = (emitter) => {
|
|
|
23334
23496
|
continue;
|
|
23335
23497
|
}
|
|
23336
23498
|
if (entry.block.fallbackText.length === 0) {
|
|
23337
|
-
entry.block.fallbackText =
|
|
23499
|
+
entry.block.fallbackText = text2;
|
|
23338
23500
|
}
|
|
23339
23501
|
if (entry.block.streamClosed && !entry.block.completionEmitted) {
|
|
23340
23502
|
await completeAssistantTextBlock(context, entry.block, {
|
|
@@ -23432,8 +23594,8 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
23432
23594
|
continue;
|
|
23433
23595
|
}
|
|
23434
23596
|
const task2 = entry;
|
|
23435
|
-
const id2 =
|
|
23436
|
-
const subject2 =
|
|
23597
|
+
const id2 = readString2(task2.id);
|
|
23598
|
+
const subject2 = readString2(task2.subject);
|
|
23437
23599
|
if (!id2 || !subject2) {
|
|
23438
23600
|
continue;
|
|
23439
23601
|
}
|
|
@@ -23448,8 +23610,8 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
23448
23610
|
}
|
|
23449
23611
|
if (tool.toolName === "TaskCreate") {
|
|
23450
23612
|
const resultTask = readClaudeTaskFromResult(result);
|
|
23451
|
-
const id2 =
|
|
23452
|
-
const subject2 =
|
|
23613
|
+
const id2 = readString2(resultTask?.id);
|
|
23614
|
+
const subject2 = readString2(resultTask?.subject) ?? readString2(tool.input.subject);
|
|
23453
23615
|
if (!id2 || !subject2) {
|
|
23454
23616
|
return false;
|
|
23455
23617
|
}
|
|
@@ -23461,7 +23623,7 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
23461
23623
|
});
|
|
23462
23624
|
return true;
|
|
23463
23625
|
}
|
|
23464
|
-
const taskId =
|
|
23626
|
+
const taskId = readString2(tool.input.taskId) ?? readString2(result?.taskId);
|
|
23465
23627
|
if (!taskId) {
|
|
23466
23628
|
return false;
|
|
23467
23629
|
}
|
|
@@ -23469,7 +23631,7 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
23469
23631
|
if (!task) {
|
|
23470
23632
|
return false;
|
|
23471
23633
|
}
|
|
23472
|
-
const subject =
|
|
23634
|
+
const subject = readString2(tool.input.subject);
|
|
23473
23635
|
if (subject && task.subject !== subject) {
|
|
23474
23636
|
task.subject = subject;
|
|
23475
23637
|
changed = true;
|
|
@@ -23880,23 +24042,23 @@ function tokenizeShellWords(value) {
|
|
|
23880
24042
|
|
|
23881
24043
|
// src/config.ts
|
|
23882
24044
|
var CLAUDE_AUTO_COMPACT_WINDOW_PATTERN = /^(?:|[1-9]\d{5}|1000000)$/;
|
|
23883
|
-
function
|
|
24045
|
+
function isRecord5(value) {
|
|
23884
24046
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23885
24047
|
}
|
|
23886
|
-
function
|
|
24048
|
+
function readString3(value) {
|
|
23887
24049
|
return typeof value === "string" ? value : "";
|
|
23888
24050
|
}
|
|
23889
24051
|
function readTrimmed(value) {
|
|
23890
|
-
return
|
|
24052
|
+
return readString3(value).trim();
|
|
23891
24053
|
}
|
|
23892
24054
|
function readEnvironment(value) {
|
|
23893
24055
|
if (!Array.isArray(value)) return {};
|
|
23894
24056
|
const env2 = {};
|
|
23895
24057
|
for (const entry of value) {
|
|
23896
|
-
if (!
|
|
24058
|
+
if (!isRecord5(entry)) continue;
|
|
23897
24059
|
const name = readTrimmed(entry["name"]);
|
|
23898
24060
|
if (name.length === 0) continue;
|
|
23899
|
-
env2[name] =
|
|
24061
|
+
env2[name] = readString3(entry["value"]);
|
|
23900
24062
|
}
|
|
23901
24063
|
return env2;
|
|
23902
24064
|
}
|
|
@@ -23909,12 +24071,12 @@ function readCustomModels(value) {
|
|
|
23909
24071
|
if (slug2.length > 0) models.push({ slug: slug2 });
|
|
23910
24072
|
continue;
|
|
23911
24073
|
}
|
|
23912
|
-
if (!
|
|
24074
|
+
if (!isRecord5(entry)) continue;
|
|
23913
24075
|
const slug = readTrimmed(entry["slug"]);
|
|
23914
24076
|
if (slug.length === 0) continue;
|
|
23915
24077
|
const thinkingRaw = entry["thinkingOptions"];
|
|
23916
24078
|
const thinkingOptions = Array.isArray(thinkingRaw) ? thinkingRaw.flatMap((option) => {
|
|
23917
|
-
if (!
|
|
24079
|
+
if (!isRecord5(option)) return [];
|
|
23918
24080
|
const id2 = readTrimmed(option["id"]) || readTrimmed(option["value"]);
|
|
23919
24081
|
const label = readTrimmed(option["label"]) || id2;
|
|
23920
24082
|
if (id2.length === 0) return [];
|
|
@@ -23947,7 +24109,7 @@ function readAutoCompactWindow(value) {
|
|
|
23947
24109
|
return CLAUDE_AUTO_COMPACT_WINDOW_PATTERN.test(trimmed) ? trimmed : "";
|
|
23948
24110
|
}
|
|
23949
24111
|
function parseClaudeInstanceConfig(config) {
|
|
23950
|
-
if (!
|
|
24112
|
+
if (!isRecord5(config)) {
|
|
23951
24113
|
return {
|
|
23952
24114
|
binaryPath: "",
|
|
23953
24115
|
homePath: "",
|
|
@@ -23960,13 +24122,13 @@ function parseClaudeInstanceConfig(config) {
|
|
|
23960
24122
|
envelopeDriver: void 0
|
|
23961
24123
|
};
|
|
23962
24124
|
}
|
|
23963
|
-
const nested =
|
|
24125
|
+
const nested = isRecord5(config["config"]) ? config["config"] : void 0;
|
|
23964
24126
|
const settings = nested ?? config;
|
|
23965
24127
|
return {
|
|
23966
24128
|
binaryPath: readTrimmed(settings["binaryPath"]),
|
|
23967
24129
|
homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
|
|
23968
24130
|
credentialsPath: readTrimmed(settings["credentialsPath"]) || readTrimmed(config["credentialsPath"]),
|
|
23969
|
-
launchArgs:
|
|
24131
|
+
launchArgs: readString3(settings["launchArgs"]),
|
|
23970
24132
|
autoCompactWindow: readAutoCompactWindow(settings["autoCompactWindow"]),
|
|
23971
24133
|
customModels: readCustomModels(settings["customModels"]),
|
|
23972
24134
|
enabled: settings["enabled"] !== false,
|
|
@@ -24015,91 +24177,295 @@ function parseCliArgs(args, options) {
|
|
|
24015
24177
|
return { flags, positionals, variadicArgs };
|
|
24016
24178
|
}
|
|
24017
24179
|
|
|
24180
|
+
// src/adapter/modelCatalog.ts
|
|
24181
|
+
import {
|
|
24182
|
+
raceAbort
|
|
24183
|
+
} from "@ycodium-ai/plugin-api/executor";
|
|
24184
|
+
|
|
24018
24185
|
// src/sdkModels.ts
|
|
24019
24186
|
import * as NodeOS6 from "node:os";
|
|
24020
24187
|
import { REASONING_OPTION_LABEL as REASONING_OPTION_LABEL2, reasoningEffortShortLabel } from "@ycodium-ai/plugin-api/executor";
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24024
|
-
var
|
|
24025
|
-
|
|
24026
|
-
|
|
24027
|
-
|
|
24028
|
-
|
|
24029
|
-
|
|
24030
|
-
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
|
|
24034
|
-
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
|
|
24188
|
+
import { OperationCleanupError } from "@ycodium-ai/plugin-api/process-operation";
|
|
24189
|
+
|
|
24190
|
+
// src/sdkAccount.ts
|
|
24191
|
+
var text = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
24192
|
+
function claudeAuthFromSdk(value) {
|
|
24193
|
+
if (value === void 0) return void 0;
|
|
24194
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
24195
|
+
return { status: "unknown" };
|
|
24196
|
+
const account = value;
|
|
24197
|
+
const token = text(account.tokenSource);
|
|
24198
|
+
const key = text(account.apiKeySource);
|
|
24199
|
+
const hasToken = token !== void 0 && token !== "none";
|
|
24200
|
+
const hasKey = key !== void 0 && key !== "none";
|
|
24201
|
+
if (hasToken || hasKey) {
|
|
24202
|
+
const email2 = text(account.email);
|
|
24203
|
+
const label2 = text(account.subscriptionType) ?? text(account.organization);
|
|
24204
|
+
return {
|
|
24205
|
+
status: "authenticated",
|
|
24206
|
+
type: hasToken ? "oauth" : "api-key",
|
|
24207
|
+
...email2 === void 0 ? {} : { email: email2 },
|
|
24208
|
+
...label2 === void 0 ? {} : { label: label2 }
|
|
24209
|
+
};
|
|
24038
24210
|
}
|
|
24039
|
-
|
|
24040
|
-
|
|
24041
|
-
|
|
24042
|
-
|
|
24043
|
-
|
|
24044
|
-
|
|
24045
|
-
|
|
24046
|
-
|
|
24047
|
-
const seen = /* @__PURE__ */ new Set();
|
|
24048
|
-
const out = [];
|
|
24049
|
-
for (const info of models) {
|
|
24050
|
-
if (typeof info.value !== "string" || info.value.trim().length === 0) continue;
|
|
24051
|
-
if (seen.has(info.value)) continue;
|
|
24052
|
-
seen.add(info.value);
|
|
24053
|
-
out.push(claudeCatalogModelFromSdk(info));
|
|
24211
|
+
const provider = text(account.apiProvider);
|
|
24212
|
+
if (provider !== void 0 && provider !== "firstParty")
|
|
24213
|
+
return { status: "unknown", type: provider };
|
|
24214
|
+
if (token === "none" && key === "none") return { status: "unauthenticated" };
|
|
24215
|
+
const email = text(account.email);
|
|
24216
|
+
const label = text(account.subscriptionType);
|
|
24217
|
+
if (provider === "firstParty" && email !== void 0) {
|
|
24218
|
+
return { status: "authenticated", email, ...label === void 0 ? {} : { label } };
|
|
24054
24219
|
}
|
|
24055
|
-
return
|
|
24056
|
-
}
|
|
24057
|
-
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
24061
|
-
|
|
24062
|
-
|
|
24063
|
-
|
|
24064
|
-
|
|
24065
|
-
|
|
24066
|
-
|
|
24067
|
-
|
|
24068
|
-
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24073
|
-
|
|
24074
|
-
|
|
24075
|
-
|
|
24076
|
-
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
|
|
24083
|
-
|
|
24084
|
-
|
|
24085
|
-
|
|
24086
|
-
|
|
24087
|
-
|
|
24088
|
-
|
|
24089
|
-
});
|
|
24090
|
-
|
|
24091
|
-
|
|
24092
|
-
|
|
24093
|
-
|
|
24094
|
-
|
|
24095
|
-
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
24101
|
-
}
|
|
24220
|
+
return { status: "unknown" };
|
|
24221
|
+
}
|
|
24222
|
+
|
|
24223
|
+
// src/sdkRead.ts
|
|
24224
|
+
import { withProcessOperation } from "@ycodium-ai/plugin-api/process-operation";
|
|
24225
|
+
|
|
24226
|
+
// src/claudeProcess.ts
|
|
24227
|
+
import * as NodeEvents from "node:events";
|
|
24228
|
+
import * as NodeStream from "node:stream";
|
|
24229
|
+
import { adoptChildStdin, nodeWritableFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
|
|
24230
|
+
var asError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
|
|
24231
|
+
var ClaudeProcess = class extends NodeEvents.EventEmitter {
|
|
24232
|
+
stdin;
|
|
24233
|
+
stdout;
|
|
24234
|
+
killed = false;
|
|
24235
|
+
exitCode = null;
|
|
24236
|
+
handle;
|
|
24237
|
+
ended = false;
|
|
24238
|
+
constructor(host, options, stderr, cleanup) {
|
|
24239
|
+
super();
|
|
24240
|
+
const env2 = {
|
|
24241
|
+
...Object.fromEntries(Object.keys(process.env).map((key) => [key, void 0])),
|
|
24242
|
+
...options.env
|
|
24243
|
+
};
|
|
24244
|
+
const ready = host.process.spawn({
|
|
24245
|
+
program: options.command,
|
|
24246
|
+
args: options.args,
|
|
24247
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
24248
|
+
env: env2,
|
|
24249
|
+
owner: { bindingId: host.bindingId }
|
|
24250
|
+
});
|
|
24251
|
+
this.stdin = nodeWritableFromHandle({
|
|
24252
|
+
writeStdin: (chunk) => ready.then((handle) => handle.writeStdin(chunk)),
|
|
24253
|
+
closeStdin: () => ready.then((handle) => handle.closeStdin())
|
|
24254
|
+
});
|
|
24255
|
+
this.stdout = NodeStream.Readable.from(
|
|
24256
|
+
(async function* () {
|
|
24257
|
+
const handle = await ready.catch(() => void 0);
|
|
24258
|
+
if (handle) yield* handle.stdout;
|
|
24259
|
+
})(),
|
|
24260
|
+
{ objectMode: false }
|
|
24261
|
+
);
|
|
24262
|
+
adoptChildStdin(this.stdin, {
|
|
24263
|
+
onError: (error) => {
|
|
24264
|
+
this.emit("error", error);
|
|
24265
|
+
}
|
|
24266
|
+
});
|
|
24267
|
+
this.stdout.on("error", (error) => this.emit("error", error));
|
|
24268
|
+
this.requestKill = (signal) => {
|
|
24269
|
+
void ready.then((handle) => this.ended ? void 0 : handle.kill(signal)).catch((cause) => this.emit("error", asError(cause)));
|
|
24270
|
+
};
|
|
24271
|
+
const abort = () => {
|
|
24272
|
+
this.kill("SIGTERM");
|
|
24273
|
+
};
|
|
24274
|
+
options.signal.addEventListener("abort", abort, { once: true });
|
|
24275
|
+
if (options.signal.aborted) abort();
|
|
24276
|
+
void ready.then(async (handle) => {
|
|
24277
|
+
this.handle = handle;
|
|
24278
|
+
const drainStderr = (async () => {
|
|
24279
|
+
const decoder = new TextDecoder();
|
|
24280
|
+
for await (const chunk of handle.stderr) stderr(decoder.decode(chunk, { stream: true }));
|
|
24281
|
+
const tail = decoder.decode();
|
|
24282
|
+
if (tail) stderr(tail);
|
|
24283
|
+
})();
|
|
24284
|
+
void drainStderr.catch((cause) => this.emit("error", asError(cause)));
|
|
24285
|
+
try {
|
|
24286
|
+
const code = await handle.exited;
|
|
24287
|
+
this.ended = true;
|
|
24288
|
+
this.handle = void 0;
|
|
24289
|
+
this.exitCode = code;
|
|
24290
|
+
await cleanup();
|
|
24291
|
+
this.emit("exit", code, null);
|
|
24292
|
+
} finally {
|
|
24293
|
+
options.signal.removeEventListener("abort", abort);
|
|
24294
|
+
}
|
|
24295
|
+
}).catch(async (cause) => {
|
|
24296
|
+
this.ended = true;
|
|
24297
|
+
this.handle = void 0;
|
|
24298
|
+
options.signal.removeEventListener("abort", abort);
|
|
24299
|
+
await cleanup();
|
|
24300
|
+
this.emit("error", asError(cause));
|
|
24301
|
+
});
|
|
24302
|
+
}
|
|
24303
|
+
requestKill;
|
|
24304
|
+
kill(signal) {
|
|
24305
|
+
if (this.ended || signal !== "SIGTERM" && signal !== "SIGKILL") return false;
|
|
24306
|
+
this.killed = true;
|
|
24307
|
+
this.requestKill(signal);
|
|
24308
|
+
return true;
|
|
24309
|
+
}
|
|
24310
|
+
};
|
|
24311
|
+
function makeClaudeProcessSpawner(host, stderr, config = {}) {
|
|
24312
|
+
const cleanup = config.cleanup ?? (async () => {
|
|
24313
|
+
});
|
|
24314
|
+
let process2;
|
|
24315
|
+
let launch;
|
|
24316
|
+
return {
|
|
24317
|
+
spawn: (options) => {
|
|
24318
|
+
const args = [...options.args, ...config.mcpConfigArgs ?? []];
|
|
24319
|
+
if (config.mcpConfigPath !== void 0) {
|
|
24320
|
+
const flag = args.findLastIndex(
|
|
24321
|
+
(arg) => arg === "--mcp-config" || arg.startsWith("--mcp-config=")
|
|
24322
|
+
);
|
|
24323
|
+
if (flag === -1) args.push("--mcp-config", config.mcpConfigPath);
|
|
24324
|
+
else {
|
|
24325
|
+
let end = flag + 1;
|
|
24326
|
+
while (end < args.length && !args[end].startsWith("-")) end++;
|
|
24327
|
+
args.splice(end, 0, config.mcpConfigPath);
|
|
24328
|
+
}
|
|
24329
|
+
}
|
|
24330
|
+
launch = { ...options, args };
|
|
24331
|
+
process2 = new ClaudeProcess(host, launch, stderr, cleanup);
|
|
24332
|
+
return process2;
|
|
24333
|
+
},
|
|
24334
|
+
current: () => process2?.handle && launch ? { handle: process2.handle, command: launch.command, args: launch.args } : void 0,
|
|
24335
|
+
clear: () => {
|
|
24336
|
+
process2 = void 0;
|
|
24337
|
+
launch = void 0;
|
|
24338
|
+
return cleanup();
|
|
24339
|
+
}
|
|
24340
|
+
};
|
|
24341
|
+
}
|
|
24342
|
+
|
|
24343
|
+
// src/sdkRead.ts
|
|
24344
|
+
var silentPrompt = (signal) => ({
|
|
24345
|
+
[Symbol.asyncIterator]: () => ({
|
|
24346
|
+
next: () => new Promise((resolve5) => {
|
|
24347
|
+
if (signal.aborted) {
|
|
24348
|
+
resolve5({ done: true, value: void 0 });
|
|
24349
|
+
return;
|
|
24350
|
+
}
|
|
24351
|
+
signal.addEventListener("abort", () => resolve5({ done: true, value: void 0 }), {
|
|
24352
|
+
once: true
|
|
24353
|
+
});
|
|
24354
|
+
}),
|
|
24355
|
+
return: async () => ({ done: true, value: void 0 })
|
|
24356
|
+
})
|
|
24357
|
+
});
|
|
24358
|
+
async function withClaudeSdkRead(input, read) {
|
|
24359
|
+
return withProcessOperation(
|
|
24360
|
+
input.host,
|
|
24361
|
+
{
|
|
24362
|
+
signal: input.signal,
|
|
24363
|
+
timeoutMs: input.timeoutMs ?? 2e4
|
|
24364
|
+
},
|
|
24365
|
+
async (operation) => {
|
|
24366
|
+
const processHost = {
|
|
24367
|
+
...input.host,
|
|
24368
|
+
process: {
|
|
24369
|
+
spawn: (options) => operation.spawn(options).then(
|
|
24370
|
+
(handle) => input.stdin === void 0 ? handle : {
|
|
24371
|
+
...handle,
|
|
24372
|
+
writeStdin: input.stdin(handle.writeStdin)
|
|
24373
|
+
}
|
|
24374
|
+
)
|
|
24375
|
+
}
|
|
24376
|
+
};
|
|
24377
|
+
const spawner = makeClaudeProcessSpawner(processHost, () => {
|
|
24378
|
+
});
|
|
24379
|
+
operation.defer(() => spawner.clear());
|
|
24380
|
+
const flags = input.options.extraArgs ?? {};
|
|
24381
|
+
if (["resume", "continue", "fork-session", "session-id", "prompt", "print"].some(
|
|
24382
|
+
(key) => key in flags
|
|
24383
|
+
)) {
|
|
24384
|
+
throw new Error("Read-only SDK queries cannot resume a session");
|
|
24385
|
+
}
|
|
24386
|
+
const runtime = input.createQuery({
|
|
24387
|
+
prompt: silentPrompt(operation.signal),
|
|
24388
|
+
options: {
|
|
24389
|
+
...input.options,
|
|
24390
|
+
persistSession: false,
|
|
24391
|
+
tools: [],
|
|
24392
|
+
mcpServers: {},
|
|
24393
|
+
strictMcpConfig: true,
|
|
24394
|
+
extraArgs: {
|
|
24395
|
+
...flags,
|
|
24396
|
+
"no-session-persistence": null,
|
|
24397
|
+
tools: "",
|
|
24398
|
+
"mcp-config": JSON.stringify({ mcpServers: {} }),
|
|
24399
|
+
"strict-mcp-config": null,
|
|
24400
|
+
"disable-slash-commands": null
|
|
24401
|
+
},
|
|
24402
|
+
abortController: operation.abortController,
|
|
24403
|
+
spawnClaudeCodeProcess: spawner.spawn
|
|
24404
|
+
}
|
|
24405
|
+
});
|
|
24406
|
+
operation.defer(() => runtime.close());
|
|
24407
|
+
return operation.track(read(runtime));
|
|
24102
24408
|
}
|
|
24409
|
+
);
|
|
24410
|
+
}
|
|
24411
|
+
|
|
24412
|
+
// src/sdkModels.ts
|
|
24413
|
+
var CLAUDE_SDK_MODELS_TIMEOUT_MS = 2e4;
|
|
24414
|
+
var CLAUDE_SDK_MODELS_TTL_MS = 30 * 6e4;
|
|
24415
|
+
var CLAUDE_SDK_MODELS_RETRY_MS = 2 * 6e4;
|
|
24416
|
+
var effortLabel = (level) => reasoningEffortShortLabel(level) ?? `${level.slice(0, 1).toUpperCase()}${level.slice(1)}`;
|
|
24417
|
+
var claudeCatalogModelFromSdk = (info) => {
|
|
24418
|
+
const descriptors = [];
|
|
24419
|
+
const levels = info.supportsEffort === false ? [] : info.supportedEffortLevels ?? [];
|
|
24420
|
+
if (levels.length > 0) {
|
|
24421
|
+
descriptors.push({
|
|
24422
|
+
type: "select",
|
|
24423
|
+
id: "effort",
|
|
24424
|
+
label: REASONING_OPTION_LABEL2,
|
|
24425
|
+
options: levels.map((level) => ({ id: level, label: effortLabel(level) }))
|
|
24426
|
+
});
|
|
24427
|
+
}
|
|
24428
|
+
if (info.supportsFastMode === true) {
|
|
24429
|
+
descriptors.push({ type: "boolean", id: "fastMode", label: "Fast Mode" });
|
|
24430
|
+
}
|
|
24431
|
+
return {
|
|
24432
|
+
slug: info.value,
|
|
24433
|
+
name: info.displayName.trim().length > 0 ? info.displayName : info.value,
|
|
24434
|
+
isCustom: false,
|
|
24435
|
+
capabilities: { optionDescriptors: descriptors }
|
|
24436
|
+
};
|
|
24437
|
+
};
|
|
24438
|
+
var claudeCatalogFromSdk = (models) => {
|
|
24439
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24440
|
+
const out = [];
|
|
24441
|
+
for (const info of models) {
|
|
24442
|
+
if (typeof info.value !== "string" || info.value.trim().length === 0) continue;
|
|
24443
|
+
if (seen.has(info.value)) continue;
|
|
24444
|
+
seen.add(info.value);
|
|
24445
|
+
out.push(claudeCatalogModelFromSdk(info));
|
|
24446
|
+
}
|
|
24447
|
+
return out;
|
|
24448
|
+
};
|
|
24449
|
+
var readClaudeSdkProbe = async (input) => {
|
|
24450
|
+
try {
|
|
24451
|
+
return await withClaudeSdkRead(
|
|
24452
|
+
{
|
|
24453
|
+
...input,
|
|
24454
|
+
timeoutMs: input.timeoutMs ?? CLAUDE_SDK_MODELS_TIMEOUT_MS
|
|
24455
|
+
},
|
|
24456
|
+
async (runtime) => {
|
|
24457
|
+
if (runtime.supportedModels === void 0) throw new Error("SDK model probe unavailable");
|
|
24458
|
+
const [models, account] = await Promise.all([
|
|
24459
|
+
runtime.supportedModels(),
|
|
24460
|
+
runtime.accountInfo?.()
|
|
24461
|
+
]);
|
|
24462
|
+
return { models, auth: claudeAuthFromSdk(account) };
|
|
24463
|
+
}
|
|
24464
|
+
);
|
|
24465
|
+
} catch (cause) {
|
|
24466
|
+
if (cause instanceof OperationCleanupError) throw cause;
|
|
24467
|
+
input.signal?.throwIfAborted();
|
|
24468
|
+
return void 0;
|
|
24103
24469
|
}
|
|
24104
24470
|
};
|
|
24105
24471
|
function claudeModelProbeEnvironment(environment) {
|
|
@@ -24132,10 +24498,12 @@ var makeClaudeModelCatalog = (deps) => {
|
|
|
24132
24498
|
let modelCatalogRead;
|
|
24133
24499
|
let modelCatalogFailedAt;
|
|
24134
24500
|
let catalogReadOk = false;
|
|
24501
|
+
let auth;
|
|
24135
24502
|
let successfulReadAt;
|
|
24136
24503
|
let skipPairedRefresh = false;
|
|
24137
24504
|
const current = () => modelCatalog?.models ?? [];
|
|
24138
24505
|
const refresh = (input) => {
|
|
24506
|
+
input?.signal?.throwIfAborted();
|
|
24139
24507
|
if (input?.paired === true && skipPairedRefresh) {
|
|
24140
24508
|
skipPairedRefresh = false;
|
|
24141
24509
|
return Promise.resolve();
|
|
@@ -24149,10 +24517,11 @@ var makeClaudeModelCatalog = (deps) => {
|
|
|
24149
24517
|
catalogReadOk = false;
|
|
24150
24518
|
return Promise.resolve();
|
|
24151
24519
|
}
|
|
24152
|
-
if (modelCatalogRead !== void 0) return modelCatalogRead;
|
|
24520
|
+
if (modelCatalogRead !== void 0) return raceAbort(modelCatalogRead, input?.signal);
|
|
24153
24521
|
const read = (async () => {
|
|
24154
24522
|
const extraArgs = parseCliArgs(deps.recipe.launchArgs).flags;
|
|
24155
|
-
const
|
|
24523
|
+
const probe = await readClaudeSdkProbe({
|
|
24524
|
+
host: deps.host,
|
|
24156
24525
|
createQuery: deps.createQuery,
|
|
24157
24526
|
signal: input?.signal,
|
|
24158
24527
|
options: {
|
|
@@ -24163,7 +24532,9 @@ var makeClaudeModelCatalog = (deps) => {
|
|
|
24163
24532
|
...Object.keys(extraArgs).length > 0 ? { extraArgs } : {}
|
|
24164
24533
|
}
|
|
24165
24534
|
});
|
|
24166
|
-
|
|
24535
|
+
input?.signal?.throwIfAborted();
|
|
24536
|
+
auth = probe?.auth;
|
|
24537
|
+
if (probe === void 0) {
|
|
24167
24538
|
modelCatalogFailedAt = deps.now();
|
|
24168
24539
|
catalogReadOk = false;
|
|
24169
24540
|
successfulReadAt = void 0;
|
|
@@ -24172,7 +24543,7 @@ var makeClaudeModelCatalog = (deps) => {
|
|
|
24172
24543
|
modelCatalogFailedAt = void 0;
|
|
24173
24544
|
catalogReadOk = true;
|
|
24174
24545
|
successfulReadAt = readAt;
|
|
24175
|
-
modelCatalog = { models: claudeCatalogFromSdk(models), readAt };
|
|
24546
|
+
modelCatalog = { models: claudeCatalogFromSdk(probe.models), readAt };
|
|
24176
24547
|
}
|
|
24177
24548
|
})().finally(() => {
|
|
24178
24549
|
modelCatalogRead = void 0;
|
|
@@ -24182,6 +24553,7 @@ var makeClaudeModelCatalog = (deps) => {
|
|
|
24182
24553
|
};
|
|
24183
24554
|
return {
|
|
24184
24555
|
current,
|
|
24556
|
+
currentAuth: () => catalogReadOk ? auth : void 0,
|
|
24185
24557
|
refresh,
|
|
24186
24558
|
/** 此刻正在进行的那次读取;没有就是 undefined。起会话等它读完,不为此另起一次。 */
|
|
24187
24559
|
pendingRead: () => modelCatalogRead,
|
|
@@ -24317,8 +24689,8 @@ var SKILL_TOKEN_REGEX = new RegExp(
|
|
|
24317
24689
|
String.raw`(^|\s)([$/])(${SKILL_TOKEN_NAME_PATTERN})(?=\s|$)`,
|
|
24318
24690
|
"g"
|
|
24319
24691
|
);
|
|
24320
|
-
function findSkillTokens(
|
|
24321
|
-
return [...
|
|
24692
|
+
function findSkillTokens(text2) {
|
|
24693
|
+
return [...text2.matchAll(SKILL_TOKEN_REGEX)].map((match) => {
|
|
24322
24694
|
const start = (match.index ?? 0) + (match[1]?.length ?? 0);
|
|
24323
24695
|
const name = match[3] ?? "";
|
|
24324
24696
|
return { sigil: match[2], name, start, end: start + name.length + 1 };
|
|
@@ -24339,9 +24711,9 @@ function lookupSkill(name, index) {
|
|
|
24339
24711
|
return session?.scope === SESSION_SKILL_NAMESPACE ? session : void 0;
|
|
24340
24712
|
}
|
|
24341
24713
|
var SLASH_SKILL_TOKEN = new RegExp(String.raw`^/(${SKILL_TOKEN_NAME_PATTERN})$`);
|
|
24342
|
-
function matchSkillTokens(
|
|
24714
|
+
function matchSkillTokens(text2, index) {
|
|
24343
24715
|
if (index.size === 0) return [];
|
|
24344
|
-
return findSkillTokens(
|
|
24716
|
+
return findSkillTokens(text2).flatMap((token) => {
|
|
24345
24717
|
const skill = lookupSkill(token.name, index);
|
|
24346
24718
|
return skill === void 0 ? [] : [{ ...token, skill }];
|
|
24347
24719
|
});
|
|
@@ -24355,7 +24727,7 @@ import { EXECUTOR_SEND_TURN_MAX_INPUT_CHARS as EXECUTOR_SEND_TURN_MAX_INPUT_CHAR
|
|
|
24355
24727
|
|
|
24356
24728
|
// src/claudeInlineSkill.ts
|
|
24357
24729
|
import * as NodeFSP4 from "node:fs/promises";
|
|
24358
|
-
import * as
|
|
24730
|
+
import * as NodePath11 from "node:path";
|
|
24359
24731
|
import { EXECUTOR_SEND_TURN_MAX_INPUT_CHARS } from "@ycodium-ai/plugin-api/executor";
|
|
24360
24732
|
|
|
24361
24733
|
// src/claudeSkillArguments.ts
|
|
@@ -24466,7 +24838,7 @@ var notLoadedBlock = (name, reason) => skillBlock(name, [
|
|
|
24466
24838
|
`The user invoked the skill "${name}" in this message, but it could not be included: ${reason}. It is not applied; don't assume its instructions.`
|
|
24467
24839
|
]);
|
|
24468
24840
|
var renderLoaded = (invocation, source, variables) => {
|
|
24469
|
-
const skillDir =
|
|
24841
|
+
const skillDir = NodePath11.dirname(invocation.path);
|
|
24470
24842
|
const known = {
|
|
24471
24843
|
CLAUDE_SKILL_DIR: skillDir,
|
|
24472
24844
|
CLAUDE_PROJECT_DIR: variables.projectDir,
|
|
@@ -24617,14 +24989,14 @@ function assertSteeringTarget(expectedTurnId, turnState) {
|
|
|
24617
24989
|
}
|
|
24618
24990
|
|
|
24619
24991
|
// src/hostMcpAllowRules.ts
|
|
24620
|
-
import { setsOwnModelConnection } from "@ycodium-ai/plugin-api/executor";
|
|
24992
|
+
import { setsOwnModelConnection as setsOwnModelConnection2 } from "@ycodium-ai/plugin-api/executor";
|
|
24621
24993
|
function claudeHostMcpAllowRules(servers) {
|
|
24622
24994
|
return (servers ?? []).filter((server) => server.hostOwned === true).map((server) => `mcp__${server.name}`);
|
|
24623
24995
|
}
|
|
24624
24996
|
function claudeUsesOfficialChannel(env2) {
|
|
24625
24997
|
const connectivity = CLAUDE_CARD.modelConnectivity;
|
|
24626
24998
|
const rows = Object.entries(env2).map(([name, value]) => ({ name, value }));
|
|
24627
|
-
if (
|
|
24999
|
+
if (setsOwnModelConnection2({ backendSwitchEnvKeys: connectivity?.backendSwitchEnvKeys }, rows))
|
|
24628
25000
|
return false;
|
|
24629
25001
|
const key = connectivity?.baseUrlEnvKey;
|
|
24630
25002
|
const baseUrl = key === void 0 ? void 0 : env2[key]?.trim();
|
|
@@ -25432,6 +25804,19 @@ var makeSessionControls = (deps) => {
|
|
|
25432
25804
|
};
|
|
25433
25805
|
};
|
|
25434
25806
|
|
|
25807
|
+
// src/workingDirectories.ts
|
|
25808
|
+
var ADDITIONAL_DIRECTORIES_CLAUDE_MD_ENV = "CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD";
|
|
25809
|
+
function claudeWorkingDirectories(cwd, others) {
|
|
25810
|
+
const hasOthers = (others?.length ?? 0) > 0;
|
|
25811
|
+
return {
|
|
25812
|
+
directories: [...cwd ? [cwd] : [], ...others ?? []],
|
|
25813
|
+
env: hasOthers ? { [ADDITIONAL_DIRECTORIES_CLAUDE_MD_ENV]: "1" } : {}
|
|
25814
|
+
};
|
|
25815
|
+
}
|
|
25816
|
+
function sameWorkingDirectories(previous, next) {
|
|
25817
|
+
return previous.length === next.length && previous.every((directory, i) => directory === next[i]);
|
|
25818
|
+
}
|
|
25819
|
+
|
|
25435
25820
|
// src/adapter/sessionLifecycle.ts
|
|
25436
25821
|
var RESULT_CLAIM_WAIT_MS = 1e3;
|
|
25437
25822
|
var makeSessionLifecycle = (deps) => {
|
|
@@ -25575,7 +25960,7 @@ var makeSessionLifecycle = (deps) => {
|
|
|
25575
25960
|
context.spawnEnvironment,
|
|
25576
25961
|
desired.spawnEnvironment
|
|
25577
25962
|
);
|
|
25578
|
-
const reusable = !context.stopped && context.session.status !== "closed" && context.session.cwd === input.cwd && context.session.runtimeMode === input.runtimeMode && context.basePermissionMode === desired.permissionMode && context.launchEffort === desired.effectiveEffort && context.sessionSkills?.pluginDir === input.skills?.pluginDir && (resumeTarget === void 0 || resumeTarget === context.resumeSessionId) && changedEnvironmentKeys.length === 0;
|
|
25963
|
+
const reusable = !context.stopped && context.session.status !== "closed" && context.session.cwd === input.cwd && sameWorkingDirectories(context.additionalDirectories, desired.additionalDirectories) && context.session.runtimeMode === input.runtimeMode && context.basePermissionMode === desired.permissionMode && context.launchEffort === desired.effectiveEffort && context.sessionSkills?.pluginDir === input.skills?.pluginDir && (resumeTarget === void 0 || resumeTarget === context.resumeSessionId) && changedEnvironmentKeys.length === 0;
|
|
25579
25964
|
if (!reusable) {
|
|
25580
25965
|
if (changedEnvironmentKeys.length > 0) {
|
|
25581
25966
|
log.info("claude.session.environment-changed", {
|
|
@@ -25584,177 +25969,60 @@ var makeSessionLifecycle = (deps) => {
|
|
|
25584
25969
|
});
|
|
25585
25970
|
}
|
|
25586
25971
|
return void 0;
|
|
25587
|
-
}
|
|
25588
|
-
if (context.currentApiModelId !== desired.apiModelId) {
|
|
25589
|
-
try {
|
|
25590
|
-
await context.query.setModel(desired.apiModelId);
|
|
25591
|
-
} catch (cause) {
|
|
25592
|
-
throw toRequestError(context.session.threadId, "session/setModel", cause);
|
|
25593
|
-
}
|
|
25594
|
-
context.currentApiModelId = desired.apiModelId;
|
|
25595
|
-
}
|
|
25596
|
-
const settingsPatch = diffClaudeSessionSettings(context.currentSettings, desired.settings);
|
|
25597
|
-
if (settingsPatch) {
|
|
25598
|
-
try {
|
|
25599
|
-
await context.query.applyFlagSettings(settingsPatch);
|
|
25600
|
-
} catch (cause) {
|
|
25601
|
-
throw toRequestError(context.session.threadId, "session/applyFlagSettings", cause);
|
|
25602
|
-
}
|
|
25603
|
-
context.currentSettings = desired.settings;
|
|
25604
|
-
}
|
|
25605
|
-
const updatedAt = nowIso();
|
|
25606
|
-
context.session = {
|
|
25607
|
-
...context.session,
|
|
25608
|
-
...desired.model ? { model: desired.model } : {},
|
|
25609
|
-
updatedAt
|
|
25610
|
-
};
|
|
25611
|
-
const configuredStamp = await makeEventStamp();
|
|
25612
|
-
offerRuntimeEvent(context, {
|
|
25613
|
-
type: "session.configured",
|
|
25614
|
-
...eventHeader(context, configuredStamp),
|
|
25615
|
-
payload: {
|
|
25616
|
-
config: {
|
|
25617
|
-
...desired.apiModelId ? { model: desired.apiModelId } : {},
|
|
25618
|
-
...input.cwd ? { cwd: input.cwd } : {},
|
|
25619
|
-
...desired.effectiveEffort ? { effort: desired.effectiveEffort } : {},
|
|
25620
|
-
...desired.permissionMode ? { permissionMode: desired.permissionMode } : {},
|
|
25621
|
-
...desired.settings.fastMode ? { fastMode: true } : {}
|
|
25622
|
-
}
|
|
25623
|
-
},
|
|
25624
|
-
providerRefs: {}
|
|
25625
|
-
});
|
|
25626
|
-
return withProcessGeneration(context.session, context);
|
|
25627
|
-
};
|
|
25628
|
-
return {
|
|
25629
|
-
sessions,
|
|
25630
|
-
stopSessionInternal,
|
|
25631
|
-
requireSession,
|
|
25632
|
-
withProcessGeneration,
|
|
25633
|
-
reconfigureSession
|
|
25634
|
-
};
|
|
25635
|
-
};
|
|
25636
|
-
|
|
25637
|
-
// src/claudeProcess.ts
|
|
25638
|
-
import * as NodeEvents from "node:events";
|
|
25639
|
-
import * as NodeStream from "node:stream";
|
|
25640
|
-
import { adoptChildStdin, nodeWritableFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
|
|
25641
|
-
var asError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
|
|
25642
|
-
var ClaudeProcess = class extends NodeEvents.EventEmitter {
|
|
25643
|
-
stdin;
|
|
25644
|
-
stdout;
|
|
25645
|
-
killed = false;
|
|
25646
|
-
exitCode = null;
|
|
25647
|
-
handle;
|
|
25648
|
-
ended = false;
|
|
25649
|
-
constructor(host, options, stderr, cleanup) {
|
|
25650
|
-
super();
|
|
25651
|
-
const env2 = {
|
|
25652
|
-
...Object.fromEntries(Object.keys(process.env).map((key) => [key, void 0])),
|
|
25653
|
-
...options.env
|
|
25654
|
-
};
|
|
25655
|
-
const ready = host.process.spawn({
|
|
25656
|
-
program: options.command,
|
|
25657
|
-
args: options.args,
|
|
25658
|
-
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
25659
|
-
env: env2,
|
|
25660
|
-
owner: { bindingId: host.bindingId }
|
|
25661
|
-
});
|
|
25662
|
-
this.stdin = nodeWritableFromHandle({
|
|
25663
|
-
writeStdin: (chunk) => ready.then((handle) => handle.writeStdin(chunk)),
|
|
25664
|
-
closeStdin: () => ready.then((handle) => handle.closeStdin())
|
|
25665
|
-
});
|
|
25666
|
-
this.stdout = NodeStream.Readable.from(
|
|
25667
|
-
(async function* () {
|
|
25668
|
-
const handle = await ready.catch(() => void 0);
|
|
25669
|
-
if (handle) yield* handle.stdout;
|
|
25670
|
-
})(),
|
|
25671
|
-
{ objectMode: false }
|
|
25672
|
-
);
|
|
25673
|
-
adoptChildStdin(this.stdin, {
|
|
25674
|
-
onError: (error) => {
|
|
25675
|
-
this.emit("error", error);
|
|
25676
|
-
}
|
|
25677
|
-
});
|
|
25678
|
-
this.stdout.on("error", (error) => this.emit("error", error));
|
|
25679
|
-
this.requestKill = (signal) => {
|
|
25680
|
-
void ready.then((handle) => this.ended ? void 0 : handle.kill(signal)).catch((cause) => this.emit("error", asError(cause)));
|
|
25681
|
-
};
|
|
25682
|
-
const abort = () => {
|
|
25683
|
-
this.kill("SIGTERM");
|
|
25684
|
-
};
|
|
25685
|
-
options.signal.addEventListener("abort", abort, { once: true });
|
|
25686
|
-
if (options.signal.aborted) abort();
|
|
25687
|
-
void ready.then(async (handle) => {
|
|
25688
|
-
this.handle = handle;
|
|
25689
|
-
const drainStderr = (async () => {
|
|
25690
|
-
const decoder = new TextDecoder();
|
|
25691
|
-
for await (const chunk of handle.stderr) stderr(decoder.decode(chunk, { stream: true }));
|
|
25692
|
-
const tail = decoder.decode();
|
|
25693
|
-
if (tail) stderr(tail);
|
|
25694
|
-
})();
|
|
25695
|
-
void drainStderr.catch((cause) => this.emit("error", asError(cause)));
|
|
25696
|
-
try {
|
|
25697
|
-
const code = await handle.exited;
|
|
25698
|
-
this.ended = true;
|
|
25699
|
-
this.handle = void 0;
|
|
25700
|
-
this.exitCode = code;
|
|
25701
|
-
await cleanup();
|
|
25702
|
-
this.emit("exit", code, null);
|
|
25703
|
-
} finally {
|
|
25704
|
-
options.signal.removeEventListener("abort", abort);
|
|
25705
|
-
}
|
|
25706
|
-
}).catch(async (cause) => {
|
|
25707
|
-
this.ended = true;
|
|
25708
|
-
this.handle = void 0;
|
|
25709
|
-
options.signal.removeEventListener("abort", abort);
|
|
25710
|
-
await cleanup();
|
|
25711
|
-
this.emit("error", asError(cause));
|
|
25712
|
-
});
|
|
25713
|
-
}
|
|
25714
|
-
requestKill;
|
|
25715
|
-
kill(signal) {
|
|
25716
|
-
if (this.ended || signal !== "SIGTERM" && signal !== "SIGKILL") return false;
|
|
25717
|
-
this.killed = true;
|
|
25718
|
-
this.requestKill(signal);
|
|
25719
|
-
return true;
|
|
25720
|
-
}
|
|
25721
|
-
};
|
|
25722
|
-
function makeClaudeProcessSpawner(host, stderr, config = {}) {
|
|
25723
|
-
const cleanup = config.cleanup ?? (async () => {
|
|
25724
|
-
});
|
|
25725
|
-
let process2;
|
|
25726
|
-
let launch;
|
|
25727
|
-
return {
|
|
25728
|
-
spawn: (options) => {
|
|
25729
|
-
const args = [...options.args, ...config.mcpConfigArgs ?? []];
|
|
25730
|
-
if (config.mcpConfigPath !== void 0) {
|
|
25731
|
-
const flag = args.findLastIndex(
|
|
25732
|
-
(arg) => arg === "--mcp-config" || arg.startsWith("--mcp-config=")
|
|
25733
|
-
);
|
|
25734
|
-
if (flag === -1) args.push("--mcp-config", config.mcpConfigPath);
|
|
25735
|
-
else {
|
|
25736
|
-
let end = flag + 1;
|
|
25737
|
-
while (end < args.length && !args[end].startsWith("-")) end++;
|
|
25738
|
-
args.splice(end, 0, config.mcpConfigPath);
|
|
25739
|
-
}
|
|
25972
|
+
}
|
|
25973
|
+
if (context.currentApiModelId !== desired.apiModelId) {
|
|
25974
|
+
try {
|
|
25975
|
+
await context.query.setModel(desired.apiModelId);
|
|
25976
|
+
} catch (cause) {
|
|
25977
|
+
throw toRequestError(context.session.threadId, "session/setModel", cause);
|
|
25740
25978
|
}
|
|
25741
|
-
|
|
25742
|
-
process2 = new ClaudeProcess(host, launch, stderr, cleanup);
|
|
25743
|
-
return process2;
|
|
25744
|
-
},
|
|
25745
|
-
current: () => process2?.handle && launch ? { handle: process2.handle, command: launch.command, args: launch.args } : void 0,
|
|
25746
|
-
clear: () => {
|
|
25747
|
-
process2 = void 0;
|
|
25748
|
-
launch = void 0;
|
|
25749
|
-
return cleanup();
|
|
25979
|
+
context.currentApiModelId = desired.apiModelId;
|
|
25750
25980
|
}
|
|
25981
|
+
const settingsPatch = diffClaudeSessionSettings(context.currentSettings, desired.settings);
|
|
25982
|
+
if (settingsPatch) {
|
|
25983
|
+
try {
|
|
25984
|
+
await context.query.applyFlagSettings(settingsPatch);
|
|
25985
|
+
} catch (cause) {
|
|
25986
|
+
throw toRequestError(context.session.threadId, "session/applyFlagSettings", cause);
|
|
25987
|
+
}
|
|
25988
|
+
context.currentSettings = desired.settings;
|
|
25989
|
+
}
|
|
25990
|
+
const updatedAt = nowIso();
|
|
25991
|
+
context.session = {
|
|
25992
|
+
...context.session,
|
|
25993
|
+
...desired.model ? { model: desired.model } : {},
|
|
25994
|
+
updatedAt
|
|
25995
|
+
};
|
|
25996
|
+
const configuredStamp = await makeEventStamp();
|
|
25997
|
+
offerRuntimeEvent(context, {
|
|
25998
|
+
type: "session.configured",
|
|
25999
|
+
...eventHeader(context, configuredStamp),
|
|
26000
|
+
payload: {
|
|
26001
|
+
config: {
|
|
26002
|
+
...desired.apiModelId ? { model: desired.apiModelId } : {},
|
|
26003
|
+
...input.cwd ? { cwd: input.cwd } : {},
|
|
26004
|
+
...desired.effectiveEffort ? { effort: desired.effectiveEffort } : {},
|
|
26005
|
+
...desired.permissionMode ? { permissionMode: desired.permissionMode } : {},
|
|
26006
|
+
...desired.settings.fastMode ? { fastMode: true } : {}
|
|
26007
|
+
}
|
|
26008
|
+
},
|
|
26009
|
+
providerRefs: {}
|
|
26010
|
+
});
|
|
26011
|
+
return withProcessGeneration(context.session, context);
|
|
25751
26012
|
};
|
|
25752
|
-
|
|
26013
|
+
return {
|
|
26014
|
+
sessions,
|
|
26015
|
+
stopSessionInternal,
|
|
26016
|
+
requireSession,
|
|
26017
|
+
withProcessGeneration,
|
|
26018
|
+
reconfigureSession
|
|
26019
|
+
};
|
|
26020
|
+
};
|
|
25753
26021
|
|
|
25754
26022
|
// src/claudeMcpConfig.ts
|
|
25755
26023
|
import * as NodeFSP5 from "node:fs/promises";
|
|
25756
26024
|
import * as NodeOS7 from "node:os";
|
|
25757
|
-
import * as
|
|
26025
|
+
import * as NodePath12 from "node:path";
|
|
25758
26026
|
import * as NodeProcess4 from "node:process";
|
|
25759
26027
|
async function createClaudeMcpConfig(mcpServers, log) {
|
|
25760
26028
|
let directory;
|
|
@@ -25769,8 +26037,8 @@ async function createClaudeMcpConfig(mcpServers, log) {
|
|
|
25769
26037
|
return { path: void 0, cleanup };
|
|
25770
26038
|
}
|
|
25771
26039
|
try {
|
|
25772
|
-
directory = await NodeFSP5.mkdtemp(
|
|
25773
|
-
const file =
|
|
26040
|
+
directory = await NodeFSP5.mkdtemp(NodePath12.join(NodeOS7.tmpdir(), "ycodium-claude-mcp-"));
|
|
26041
|
+
const file = NodePath12.join(directory, "mcp.json");
|
|
25774
26042
|
await NodeFSP5.writeFile(file, JSON.stringify({ mcpServers }), { mode: 384 });
|
|
25775
26043
|
await NodeFSP5.chmod(file, 384).catch((cause) => {
|
|
25776
26044
|
if (NodeProcess4.platform !== "win32") throw cause;
|
|
@@ -25910,8 +26178,10 @@ var makeStartSession = (deps) => {
|
|
|
25910
26178
|
ultracode,
|
|
25911
26179
|
autoCompactWindow: recipe.autoCompactWindow
|
|
25912
26180
|
});
|
|
26181
|
+
const workingDirectories = claudeWorkingDirectories(input.cwd, input.additionalDirectories);
|
|
26182
|
+
const additionalDirectories = workingDirectories.directories;
|
|
25913
26183
|
const spawnEnvironment = {
|
|
25914
|
-
processEnv: compactEnv(buildLaunchEnvironment())
|
|
26184
|
+
processEnv: { ...compactEnv(buildLaunchEnvironment()), ...workingDirectories.env }
|
|
25915
26185
|
};
|
|
25916
26186
|
const existingContext = sessions.get(input.threadId);
|
|
25917
26187
|
if (existingContext) {
|
|
@@ -25921,7 +26191,8 @@ var makeStartSession = (deps) => {
|
|
|
25921
26191
|
...effectiveEffort ? { effectiveEffort } : {},
|
|
25922
26192
|
...modelSelection?.model ? { model: modelSelection.model } : {},
|
|
25923
26193
|
settings,
|
|
25924
|
-
spawnEnvironment
|
|
26194
|
+
spawnEnvironment,
|
|
26195
|
+
additionalDirectories
|
|
25925
26196
|
});
|
|
25926
26197
|
if (reconfigured) {
|
|
25927
26198
|
return reconfigured;
|
|
@@ -25971,7 +26242,6 @@ var makeStartSession = (deps) => {
|
|
|
25971
26242
|
contextAfterCompaction: input.contextAfterCompaction,
|
|
25972
26243
|
log
|
|
25973
26244
|
});
|
|
25974
|
-
const additionalDirectories = input.cwd ? [input.cwd] : [];
|
|
25975
26245
|
const mcpServers = toClaudeMcpServers(input.mcpServers);
|
|
25976
26246
|
const querySettings = { ...settings };
|
|
25977
26247
|
const permissionRules = {
|
|
@@ -26045,7 +26315,7 @@ var makeStartSession = (deps) => {
|
|
|
26045
26315
|
},
|
|
26046
26316
|
supportedDialogKinds: ["resume_return"],
|
|
26047
26317
|
env: { ...spawnEnvironment.processEnv },
|
|
26048
|
-
additionalDirectories,
|
|
26318
|
+
additionalDirectories: [...additionalDirectories],
|
|
26049
26319
|
...Object.keys(extraArgs).length > 0 ? { extraArgs } : {},
|
|
26050
26320
|
...claudeSessionPlugins(input.skills)
|
|
26051
26321
|
};
|
|
@@ -26098,6 +26368,7 @@ var makeStartSession = (deps) => {
|
|
|
26098
26368
|
launchEffort: effectiveEffort ?? void 0,
|
|
26099
26369
|
sessionSkills: input.skills,
|
|
26100
26370
|
spawnEnvironment,
|
|
26371
|
+
additionalDirectories,
|
|
26101
26372
|
currentSettings: settings,
|
|
26102
26373
|
permissionRules,
|
|
26103
26374
|
currentPermissionAllow: permissionAllow,
|
|
@@ -26433,7 +26704,7 @@ var makeStreamEventHandler = (deps) => {
|
|
|
26433
26704
|
|
|
26434
26705
|
// src/claudeWorkspaceInventory.ts
|
|
26435
26706
|
import * as NodeFSP6 from "node:fs/promises";
|
|
26436
|
-
import * as
|
|
26707
|
+
import * as NodePath13 from "node:path";
|
|
26437
26708
|
var MAX_COMMAND_DEPTH = 5;
|
|
26438
26709
|
var MAX_COMMAND_FILES = 500;
|
|
26439
26710
|
var MAX_DESCRIPTION_LENGTH = 200;
|
|
@@ -26451,7 +26722,7 @@ var firstBodyLine = (contents) => {
|
|
|
26451
26722
|
return void 0;
|
|
26452
26723
|
};
|
|
26453
26724
|
var scanCommands = async (claudeDir) => {
|
|
26454
|
-
const root =
|
|
26725
|
+
const root = NodePath13.join(claudeDir, "commands");
|
|
26455
26726
|
const commands = /* @__PURE__ */ new Map();
|
|
26456
26727
|
const watched = [root];
|
|
26457
26728
|
let level = [root];
|
|
@@ -26461,7 +26732,7 @@ var scanCommands = async (claudeDir) => {
|
|
|
26461
26732
|
for (const directory of level) {
|
|
26462
26733
|
const entries = await NodeFSP6.readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
26463
26734
|
for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
|
|
26464
|
-
const entryPath =
|
|
26735
|
+
const entryPath = NodePath13.join(directory, entry.name);
|
|
26465
26736
|
if (entry.isDirectory()) {
|
|
26466
26737
|
next.push(entryPath);
|
|
26467
26738
|
watched.push(entryPath);
|
|
@@ -26489,13 +26760,13 @@ var scanCommands = async (claudeDir) => {
|
|
|
26489
26760
|
return { commands: [...commands.values()], watched };
|
|
26490
26761
|
};
|
|
26491
26762
|
var watchSkillsRoot = async (claudeDir) => {
|
|
26492
|
-
const root =
|
|
26763
|
+
const root = NodePath13.join(claudeDir, "skills");
|
|
26493
26764
|
const entries = await NodeFSP6.readdir(root).catch(() => []);
|
|
26494
26765
|
return [
|
|
26495
26766
|
root,
|
|
26496
26767
|
...entries.flatMap((entry) => [
|
|
26497
|
-
|
|
26498
|
-
|
|
26768
|
+
NodePath13.join(root, entry),
|
|
26769
|
+
NodePath13.join(root, entry, "SKILL.md")
|
|
26499
26770
|
])
|
|
26500
26771
|
];
|
|
26501
26772
|
};
|
|
@@ -26506,7 +26777,7 @@ var mergeByName = (base, preferred) => {
|
|
|
26506
26777
|
return [...merged.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
26507
26778
|
};
|
|
26508
26779
|
var discoverClaudeWorkspaceInventory = async (input) => {
|
|
26509
|
-
const projectClaudeDir =
|
|
26780
|
+
const projectClaudeDir = NodePath13.join(input.cwd, ".claude");
|
|
26510
26781
|
const [userCommands, projectCommands, skills, userSkillWatch, projectSkillWatch] = await Promise.all([
|
|
26511
26782
|
scanCommands(input.configDirPath),
|
|
26512
26783
|
scanCommands(projectClaudeDir),
|
|
@@ -26528,9 +26799,9 @@ var discoverClaudeWorkspaceInventory = async (input) => {
|
|
|
26528
26799
|
...userSkillWatch,
|
|
26529
26800
|
...projectSkillWatch,
|
|
26530
26801
|
// `skillOverrides` 在这几个设置文件里:开关一个技能也要重查。
|
|
26531
|
-
|
|
26532
|
-
|
|
26533
|
-
|
|
26802
|
+
NodePath13.join(input.configDirPath, "settings.json"),
|
|
26803
|
+
NodePath13.join(projectClaudeDir, "settings.json"),
|
|
26804
|
+
NodePath13.join(projectClaudeDir, "settings.local.json")
|
|
26534
26805
|
]
|
|
26535
26806
|
};
|
|
26536
26807
|
};
|
|
@@ -26654,8 +26925,8 @@ var makeSystemMessageHandler = (deps) => {
|
|
|
26654
26925
|
case "model_refusal_no_fallback": {
|
|
26655
26926
|
const explanation = typeof record2.api_refusal_explanation === "string" ? record2.api_refusal_explanation.trim() : "";
|
|
26656
26927
|
const content = typeof record2.content === "string" ? record2.content : "";
|
|
26657
|
-
const
|
|
26658
|
-
if (
|
|
26928
|
+
const text2 = explanation || content;
|
|
26929
|
+
if (text2.length > 0) await emitRuntimeWarning(context, text2, message);
|
|
26659
26930
|
return;
|
|
26660
26931
|
}
|
|
26661
26932
|
}
|
|
@@ -27297,7 +27568,7 @@ var makeTurnLifecycle = (deps) => {
|
|
|
27297
27568
|
};
|
|
27298
27569
|
|
|
27299
27570
|
// src/adapter/turnMessages.ts
|
|
27300
|
-
import * as
|
|
27571
|
+
import * as NodePath14 from "node:path";
|
|
27301
27572
|
var makeTurnMessageHandlers = (deps) => {
|
|
27302
27573
|
const {
|
|
27303
27574
|
emitter,
|
|
@@ -27563,7 +27834,7 @@ var makeTurnMessageHandlers = (deps) => {
|
|
|
27563
27834
|
claudeFailureHint({
|
|
27564
27835
|
authenticationFailed: context.turnState?.authenticationFailed === true,
|
|
27565
27836
|
environment: buildLaunchEnvironment(),
|
|
27566
|
-
cwd:
|
|
27837
|
+
cwd: NodePath14.resolve(context.session.cwd ?? "."),
|
|
27567
27838
|
...context.turnState === void 0 ? {} : {
|
|
27568
27839
|
usageLimit: {
|
|
27569
27840
|
rejected: context.turnState.rejectedRateLimits,
|
|
@@ -27667,8 +27938,13 @@ function buildTurnSummaryPrompt(raw) {
|
|
|
27667
27938
|
// src/textGeneration.ts
|
|
27668
27939
|
import * as NodeFSP7 from "node:fs/promises";
|
|
27669
27940
|
import * as NodeOS8 from "node:os";
|
|
27670
|
-
import * as
|
|
27671
|
-
import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
|
|
27941
|
+
import * as NodePath15 from "node:path";
|
|
27942
|
+
import { mergeLaunchEnv as mergeLaunchEnv2 } from "@ycodium-ai/plugin-api/executor";
|
|
27943
|
+
import {
|
|
27944
|
+
OperationCleanupError as OperationCleanupError2,
|
|
27945
|
+
isOperationCleanupError as isOperationCleanupError2,
|
|
27946
|
+
runProcessOperation as runProcessOperation2
|
|
27947
|
+
} from "@ycodium-ai/plugin-api/process-operation";
|
|
27672
27948
|
|
|
27673
27949
|
// src/textGenerationUtils.ts
|
|
27674
27950
|
function limitSection(value, maxChars) {
|
|
@@ -27714,14 +27990,14 @@ function unwrapNestedTitleObject(raw) {
|
|
|
27714
27990
|
return raw;
|
|
27715
27991
|
}
|
|
27716
27992
|
var MAX_THREAD_TITLE_CHARS = 120;
|
|
27717
|
-
function limitTitleMessage(
|
|
27993
|
+
function limitTitleMessage(text2, budget) {
|
|
27718
27994
|
const marker = "\n[Content truncated]\n";
|
|
27719
|
-
if (
|
|
27995
|
+
if (text2.length <= budget) return text2;
|
|
27720
27996
|
if (budget <= marker.length) return "";
|
|
27721
27997
|
const available = budget - marker.length;
|
|
27722
27998
|
const head = Math.ceil(available / 2);
|
|
27723
27999
|
const tail = available - head;
|
|
27724
|
-
return `${
|
|
28000
|
+
return `${text2.slice(0, head)}${marker}${tail > 0 ? text2.slice(-tail) : ""}`;
|
|
27725
28001
|
}
|
|
27726
28002
|
function sanitizeThreadTitle(raw) {
|
|
27727
28003
|
const normalized = unwrapNestedTitleObject(raw).trim().split(/\r?\n/g)[0]?.trim().replace(/^['"`]+|['"`]+$/g, "").trim().replace(/\s+/g, " ");
|
|
@@ -28032,19 +28308,12 @@ function buildHandoverSummaryPrompt(input) {
|
|
|
28032
28308
|
|
|
28033
28309
|
// src/textGeneration.ts
|
|
28034
28310
|
var CLAUDE_TIMEOUT_MS = 18e4;
|
|
28035
|
-
function
|
|
28311
|
+
function isRecord6(value) {
|
|
28036
28312
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28037
28313
|
}
|
|
28038
|
-
function
|
|
28314
|
+
function readString4(value) {
|
|
28039
28315
|
return typeof value === "string" ? value : "";
|
|
28040
28316
|
}
|
|
28041
|
-
async function collectText(stream) {
|
|
28042
|
-
const chunks = [];
|
|
28043
|
-
for await (const chunk of stream) {
|
|
28044
|
-
chunks.push(Buffer.from(chunk));
|
|
28045
|
-
}
|
|
28046
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
28047
|
-
}
|
|
28048
28317
|
function decodeStructuredOutput(stdout, operation) {
|
|
28049
28318
|
let parsed;
|
|
28050
28319
|
try {
|
|
@@ -28054,19 +28323,20 @@ function decodeStructuredOutput(stdout, operation) {
|
|
|
28054
28323
|
cause: error
|
|
28055
28324
|
});
|
|
28056
28325
|
}
|
|
28057
|
-
const envelope = Array.isArray(parsed) ? parsed.findLast((message) =>
|
|
28058
|
-
if (!
|
|
28326
|
+
const envelope = Array.isArray(parsed) ? parsed.findLast((message) => isRecord6(message) && message["type"] === "result") : parsed;
|
|
28327
|
+
if (!isRecord6(envelope) || !("structured_output" in envelope)) {
|
|
28059
28328
|
throw new Error(`${operation}: Claude CLI returned unexpected output format.`);
|
|
28060
28329
|
}
|
|
28061
28330
|
return envelope["structured_output"];
|
|
28062
28331
|
}
|
|
28063
28332
|
function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
28064
28333
|
const runClaudeJson = async (input) => {
|
|
28065
|
-
|
|
28334
|
+
input.signal?.throwIfAborted();
|
|
28335
|
+
const processEnv = mergeLaunchEnv2({
|
|
28066
28336
|
instanceTable: recipe.environment,
|
|
28067
28337
|
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
28068
28338
|
});
|
|
28069
|
-
const modelSelection =
|
|
28339
|
+
const modelSelection = isRecord6(input.modelSelection) ? input.modelSelection : {};
|
|
28070
28340
|
const requestedModel = modelIdFromSelection(modelSelection) ?? "claude-haiku-4-5";
|
|
28071
28341
|
const caps = claudeModelCapabilities(requestedModel, modelCatalog(), recipe.customModels);
|
|
28072
28342
|
const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort");
|
|
@@ -28102,52 +28372,46 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28102
28372
|
"--strict-mcp-config"
|
|
28103
28373
|
];
|
|
28104
28374
|
const program = recipe.binaryPath.trim() || "claude";
|
|
28375
|
+
let safeToRemove = true;
|
|
28105
28376
|
const runIn = async (cwd) => {
|
|
28106
|
-
|
|
28107
|
-
|
|
28108
|
-
|
|
28109
|
-
|
|
28110
|
-
|
|
28111
|
-
|
|
28112
|
-
|
|
28113
|
-
|
|
28114
|
-
|
|
28115
|
-
|
|
28116
|
-
|
|
28117
|
-
|
|
28118
|
-
|
|
28119
|
-
|
|
28120
|
-
|
|
28121
|
-
|
|
28122
|
-
|
|
28123
|
-
|
|
28124
|
-
|
|
28125
|
-
|
|
28126
|
-
|
|
28127
|
-
if (signal.aborted && !input.signal?.aborted) {
|
|
28128
|
-
throw new Error(`${input.operation}: Claude CLI request timed out.`);
|
|
28129
|
-
}
|
|
28130
|
-
if (exitCode !== 0) {
|
|
28131
|
-
const detail = stderr.trim() || stdout.trim();
|
|
28132
|
-
throw new Error(
|
|
28133
|
-
detail.length > 0 ? `Claude CLI command failed: ${detail}` : `Claude CLI command failed with code ${exitCode}.`
|
|
28134
|
-
);
|
|
28377
|
+
try {
|
|
28378
|
+
const { stdout, stderr, exitCode } = await runProcessOperation2(host, {
|
|
28379
|
+
program,
|
|
28380
|
+
args,
|
|
28381
|
+
cwd,
|
|
28382
|
+
env: processEnv,
|
|
28383
|
+
owner: { bindingId: host.bindingId },
|
|
28384
|
+
signal: input.signal,
|
|
28385
|
+
timeoutMs: CLAUDE_TIMEOUT_MS,
|
|
28386
|
+
input: input.prompt
|
|
28387
|
+
});
|
|
28388
|
+
if (exitCode !== 0) {
|
|
28389
|
+
const detail = stderr.trim() || stdout.trim();
|
|
28390
|
+
throw new Error(
|
|
28391
|
+
detail.length > 0 ? `Claude CLI command failed: ${detail}` : `Claude CLI command failed with code ${exitCode}.`
|
|
28392
|
+
);
|
|
28393
|
+
}
|
|
28394
|
+
return decodeStructuredOutput(stdout, input.operation);
|
|
28395
|
+
} catch (cause) {
|
|
28396
|
+
if (cause instanceof OperationCleanupError2) safeToRemove = false;
|
|
28397
|
+
throw cause;
|
|
28135
28398
|
}
|
|
28136
|
-
return decodeStructuredOutput(stdout, input.operation);
|
|
28137
28399
|
};
|
|
28138
28400
|
if (input.operation !== "generateThreadTitle" && input.operation !== "summarizeTurn")
|
|
28139
28401
|
return runIn(input.cwd);
|
|
28140
28402
|
const scratchDirectory = await NodeFSP7.mkdtemp(
|
|
28141
|
-
|
|
28403
|
+
NodePath15.join(NodeOS8.tmpdir(), "ycodium-claude-title-")
|
|
28142
28404
|
);
|
|
28143
28405
|
try {
|
|
28144
28406
|
return await runIn(scratchDirectory);
|
|
28145
28407
|
} finally {
|
|
28146
|
-
|
|
28408
|
+
if (safeToRemove) {
|
|
28409
|
+
await NodeFSP7.rm(scratchDirectory, { recursive: true, force: true }).catch(() => void 0);
|
|
28410
|
+
}
|
|
28147
28411
|
}
|
|
28148
28412
|
};
|
|
28149
28413
|
const asRecord2 = (value, operation) => {
|
|
28150
|
-
if (!
|
|
28414
|
+
if (!isRecord6(value))
|
|
28151
28415
|
throw new Error(`${operation}: Claude returned invalid structured output.`);
|
|
28152
28416
|
return value;
|
|
28153
28417
|
};
|
|
@@ -28158,15 +28422,15 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28158
28422
|
const includeBranch = input["includeBranch"] === true;
|
|
28159
28423
|
const { prompt, outputSchema } = buildCommitMessagePrompt({
|
|
28160
28424
|
branch: typeof input["branch"] === "string" ? input["branch"] : null,
|
|
28161
|
-
stagedSummary:
|
|
28162
|
-
stagedPatch:
|
|
28425
|
+
stagedSummary: readString4(input["stagedSummary"]),
|
|
28426
|
+
stagedPatch: readString4(input["stagedPatch"]),
|
|
28163
28427
|
includeBranch,
|
|
28164
|
-
...
|
|
28428
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
28165
28429
|
});
|
|
28166
28430
|
const generated = asRecord2(
|
|
28167
28431
|
await runClaudeJson({
|
|
28168
28432
|
operation: "generateCommitMessage",
|
|
28169
|
-
cwd:
|
|
28433
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28170
28434
|
prompt,
|
|
28171
28435
|
outputSchema,
|
|
28172
28436
|
modelSelection: input["modelSelection"],
|
|
@@ -28175,11 +28439,12 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28175
28439
|
"generateCommitMessage"
|
|
28176
28440
|
);
|
|
28177
28441
|
return {
|
|
28178
|
-
subject: sanitizeCommitSubject(
|
|
28179
|
-
body:
|
|
28442
|
+
subject: sanitizeCommitSubject(readString4(generated["subject"])),
|
|
28443
|
+
body: readString4(generated["body"]).trim(),
|
|
28180
28444
|
...typeof generated["branch"] === "string" ? { branch: sanitizeFeatureBranchName(generated["branch"]) } : {}
|
|
28181
28445
|
};
|
|
28182
28446
|
} catch (error) {
|
|
28447
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28183
28448
|
throw normalizeCliError("claude", error, "Failed to generate commit message");
|
|
28184
28449
|
}
|
|
28185
28450
|
},
|
|
@@ -28187,18 +28452,18 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28187
28452
|
try {
|
|
28188
28453
|
const input = asRecord2(raw, "generatePrContent");
|
|
28189
28454
|
const { prompt, outputSchema } = buildPrContentPrompt({
|
|
28190
|
-
baseBranch:
|
|
28191
|
-
headBranch:
|
|
28192
|
-
commitSummary:
|
|
28193
|
-
diffSummary:
|
|
28194
|
-
diffPatch:
|
|
28455
|
+
baseBranch: readString4(input["baseBranch"]),
|
|
28456
|
+
headBranch: readString4(input["headBranch"]),
|
|
28457
|
+
commitSummary: readString4(input["commitSummary"]),
|
|
28458
|
+
diffSummary: readString4(input["diffSummary"]),
|
|
28459
|
+
diffPatch: readString4(input["diffPatch"]),
|
|
28195
28460
|
...typeof input["changeRequestTemplate"] === "string" ? { changeRequestTemplate: input["changeRequestTemplate"] } : {},
|
|
28196
|
-
...
|
|
28461
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
28197
28462
|
});
|
|
28198
28463
|
const generated = asRecord2(
|
|
28199
28464
|
await runClaudeJson({
|
|
28200
28465
|
operation: "generatePrContent",
|
|
28201
|
-
cwd:
|
|
28466
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28202
28467
|
prompt,
|
|
28203
28468
|
outputSchema,
|
|
28204
28469
|
modelSelection: input["modelSelection"],
|
|
@@ -28207,10 +28472,11 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28207
28472
|
"generatePrContent"
|
|
28208
28473
|
);
|
|
28209
28474
|
return {
|
|
28210
|
-
title: sanitizePrTitle(
|
|
28211
|
-
body:
|
|
28475
|
+
title: sanitizePrTitle(readString4(generated["title"])),
|
|
28476
|
+
body: readString4(generated["body"]).trim()
|
|
28212
28477
|
};
|
|
28213
28478
|
} catch (error) {
|
|
28479
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28214
28480
|
throw normalizeCliError("claude", error, "Failed to generate change request content");
|
|
28215
28481
|
}
|
|
28216
28482
|
},
|
|
@@ -28218,14 +28484,14 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28218
28484
|
try {
|
|
28219
28485
|
const input = asRecord2(raw, "generateBranchName");
|
|
28220
28486
|
const { prompt, outputSchema } = buildBranchNamePrompt({
|
|
28221
|
-
message:
|
|
28487
|
+
message: readString4(input["message"]),
|
|
28222
28488
|
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
28223
|
-
...
|
|
28489
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
28224
28490
|
});
|
|
28225
28491
|
const generated = asRecord2(
|
|
28226
28492
|
await runClaudeJson({
|
|
28227
28493
|
operation: "generateBranchName",
|
|
28228
|
-
cwd:
|
|
28494
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28229
28495
|
prompt,
|
|
28230
28496
|
outputSchema,
|
|
28231
28497
|
modelSelection: input["modelSelection"],
|
|
@@ -28233,8 +28499,9 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28233
28499
|
}),
|
|
28234
28500
|
"generateBranchName"
|
|
28235
28501
|
);
|
|
28236
|
-
return { branch: sanitizeBranchFragment(
|
|
28502
|
+
return { branch: sanitizeBranchFragment(readString4(generated["branch"])) };
|
|
28237
28503
|
} catch (error) {
|
|
28504
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28238
28505
|
throw normalizeCliError("claude", error, "Failed to generate branch name");
|
|
28239
28506
|
}
|
|
28240
28507
|
},
|
|
@@ -28242,16 +28509,16 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28242
28509
|
try {
|
|
28243
28510
|
const input = asRecord2(raw, "generateThreadTitle");
|
|
28244
28511
|
const { prompt, outputSchema } = buildThreadTitlePrompt({
|
|
28245
|
-
message:
|
|
28512
|
+
message: readString4(input["message"]),
|
|
28246
28513
|
...typeof input["linkedContext"] === "string" && input["linkedContext"].length > 0 ? { linkedContext: input["linkedContext"] } : {},
|
|
28247
28514
|
...typeof input["previousTitle"] === "string" ? { previousTitle: input["previousTitle"] } : {},
|
|
28248
28515
|
...Array.isArray(input["attachments"]) ? { attachments: input["attachments"] } : {},
|
|
28249
|
-
...
|
|
28516
|
+
...isRecord6(input["policy"]) ? { policy: input["policy"] } : {}
|
|
28250
28517
|
});
|
|
28251
28518
|
const generated = asRecord2(
|
|
28252
28519
|
await runClaudeJson({
|
|
28253
28520
|
operation: "generateThreadTitle",
|
|
28254
|
-
cwd:
|
|
28521
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28255
28522
|
prompt,
|
|
28256
28523
|
outputSchema,
|
|
28257
28524
|
modelSelection: input["modelSelection"],
|
|
@@ -28260,10 +28527,11 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28260
28527
|
"generateThreadTitle"
|
|
28261
28528
|
);
|
|
28262
28529
|
return {
|
|
28263
|
-
title: sanitizeThreadTitle(
|
|
28530
|
+
title: sanitizeThreadTitle(readString4(generated["title"])),
|
|
28264
28531
|
...generated["needsRefinement"] === true ? { needsRefinement: true } : {}
|
|
28265
28532
|
};
|
|
28266
28533
|
} catch (error) {
|
|
28534
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28267
28535
|
throw normalizeCliError("claude", error, "Failed to generate thread title");
|
|
28268
28536
|
}
|
|
28269
28537
|
},
|
|
@@ -28273,7 +28541,7 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28273
28541
|
const generated = asRecord2(
|
|
28274
28542
|
await runClaudeJson({
|
|
28275
28543
|
operation: "summarizeTurn",
|
|
28276
|
-
cwd:
|
|
28544
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28277
28545
|
prompt: buildTurnSummaryPrompt(input),
|
|
28278
28546
|
outputSchema: {
|
|
28279
28547
|
type: "object",
|
|
@@ -28286,8 +28554,9 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28286
28554
|
}),
|
|
28287
28555
|
"summarizeTurn"
|
|
28288
28556
|
);
|
|
28289
|
-
return { summary:
|
|
28557
|
+
return { summary: readString4(generated["summary"]).trim() };
|
|
28290
28558
|
} catch (error) {
|
|
28559
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28291
28560
|
throw normalizeCliError("claude", error, "Failed to summarize turn");
|
|
28292
28561
|
}
|
|
28293
28562
|
},
|
|
@@ -28295,12 +28564,12 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28295
28564
|
try {
|
|
28296
28565
|
const input = asRecord2(raw, "summarizeHandover");
|
|
28297
28566
|
const { prompt, outputSchema } = buildHandoverSummaryPrompt({
|
|
28298
|
-
transcript:
|
|
28567
|
+
transcript: readString4(input["transcript"])
|
|
28299
28568
|
});
|
|
28300
28569
|
const generated = asRecord2(
|
|
28301
28570
|
await runClaudeJson({
|
|
28302
28571
|
operation: "summarizeHandover",
|
|
28303
|
-
cwd:
|
|
28572
|
+
cwd: readString4(input["cwd"]) || ".",
|
|
28304
28573
|
prompt,
|
|
28305
28574
|
outputSchema,
|
|
28306
28575
|
modelSelection: input["modelSelection"],
|
|
@@ -28308,8 +28577,9 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28308
28577
|
}),
|
|
28309
28578
|
"summarizeHandover"
|
|
28310
28579
|
);
|
|
28311
|
-
return { summary:
|
|
28580
|
+
return { summary: readString4(generated["summary"]).trim() };
|
|
28312
28581
|
} catch (error) {
|
|
28582
|
+
if (isOperationCleanupError2(error)) throw error;
|
|
28313
28583
|
throw normalizeCliError("claude", error, "Failed to summarize handover");
|
|
28314
28584
|
}
|
|
28315
28585
|
}
|
|
@@ -28319,179 +28589,99 @@ function createClaudeTextGeneration(recipe, host, modelCatalog) {
|
|
|
28319
28589
|
// src/usageRead/index.ts
|
|
28320
28590
|
import * as NodePath18 from "node:path";
|
|
28321
28591
|
|
|
28322
|
-
// src/usageRead/
|
|
28323
|
-
import * as
|
|
28324
|
-
import
|
|
28325
|
-
|
|
28326
|
-
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
|
|
28330
|
-
|
|
28331
|
-
|
|
28332
|
-
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28336
|
-
|
|
28337
|
-
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28341
|
-
});
|
|
28342
|
-
var claudeCredentialFileCandidates = (recipe) => {
|
|
28343
|
-
const environment = launchEnvironment(recipe);
|
|
28344
|
-
const credentialsDir = resolveClaudeCredentialsDirPath(
|
|
28345
|
-
environment[CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE] ?? ""
|
|
28346
|
-
);
|
|
28347
|
-
if (credentialsDir !== null) return [NodePath15.join(credentialsDir, ".credentials.json")];
|
|
28348
|
-
const configDir = resolveClaudeConfigDirPath(recipe.homePath, environment);
|
|
28349
|
-
const home = resolveClaudeHomePath(recipe.homePath);
|
|
28350
|
-
return [
|
|
28351
|
-
.../* @__PURE__ */ new Set([
|
|
28352
|
-
NodePath15.join(configDir, ".credentials.json"),
|
|
28353
|
-
NodePath15.join(home, ".claude", ".credentials.json"),
|
|
28354
|
-
NodePath15.join(home, ".credentials.json")
|
|
28355
|
-
])
|
|
28356
|
-
];
|
|
28357
|
-
};
|
|
28358
|
-
var readString4 = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
28359
|
-
var readLoginCredential = (candidates) => {
|
|
28360
|
-
for (const path of candidates) {
|
|
28361
|
-
let raw;
|
|
28362
|
-
try {
|
|
28363
|
-
raw = NodeFS6.readFileSync(path, "utf8");
|
|
28364
|
-
} catch {
|
|
28365
|
-
continue;
|
|
28366
|
-
}
|
|
28367
|
-
if (raw.trim().length === 0) continue;
|
|
28368
|
-
let parsed;
|
|
28369
|
-
try {
|
|
28370
|
-
parsed = JSON.parse(raw);
|
|
28371
|
-
} catch {
|
|
28372
|
-
continue;
|
|
28373
|
-
}
|
|
28374
|
-
const oauth = isRecord6(parsed) ? parsed["claudeAiOauth"] : void 0;
|
|
28375
|
-
if (!isRecord6(oauth)) continue;
|
|
28376
|
-
const accessToken = readString4(oauth["accessToken"]);
|
|
28377
|
-
if (accessToken === void 0) continue;
|
|
28378
|
-
return {
|
|
28379
|
-
accessToken,
|
|
28380
|
-
subscriptionType: readString4(oauth["subscriptionType"]),
|
|
28381
|
-
rateLimitTier: readString4(oauth["rateLimitTier"]),
|
|
28382
|
-
path
|
|
28383
|
-
};
|
|
28384
|
-
}
|
|
28385
|
-
return null;
|
|
28386
|
-
};
|
|
28387
|
-
var claudePlanName = (credential) => {
|
|
28388
|
-
const type4 = credential.subscriptionType;
|
|
28389
|
-
if (type4 === void 0) return void 0;
|
|
28390
|
-
const name = `${type4.charAt(0).toUpperCase()}${type4.slice(1)}`;
|
|
28391
|
-
const multiplier = /(?:^|_)(\d+x)$/.exec(credential.rateLimitTier ?? "")?.[1];
|
|
28392
|
-
return multiplier === void 0 ? name : `${name} ${multiplier}`;
|
|
28393
|
-
};
|
|
28394
|
-
var toIso = (value) => {
|
|
28395
|
-
if (typeof value !== "string") return null;
|
|
28396
|
-
const parsed = Date.parse(value);
|
|
28397
|
-
return Number.isNaN(parsed) ? null : new Date(parsed).toISOString();
|
|
28398
|
-
};
|
|
28399
|
-
var readWindows = (body) => CLAUDE_QUOTA_WINDOWS.flatMap((spec) => {
|
|
28400
|
-
const row = body[spec.field];
|
|
28401
|
-
if (!isRecord6(row)) return [];
|
|
28402
|
-
const utilization = row["utilization"];
|
|
28403
|
-
if (typeof utilization !== "number" || !Number.isFinite(utilization)) return [];
|
|
28404
|
-
return [
|
|
28405
|
-
{
|
|
28406
|
-
id: spec.id,
|
|
28407
|
-
label: { key: spec.labelKey },
|
|
28408
|
-
usedPercent: Math.min(100, Math.max(0, utilization)),
|
|
28409
|
-
resetsAt: toIso(row["resets_at"]),
|
|
28410
|
-
windowMs: spec.windowMs
|
|
28592
|
+
// src/usageRead/nativeQuota.ts
|
|
28593
|
+
import * as NodeOS9 from "node:os";
|
|
28594
|
+
import { mergeLaunchEnv as mergeLaunchEnv3 } from "@ycodium-ai/plugin-api/executor";
|
|
28595
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28596
|
+
function quotaWriter(write) {
|
|
28597
|
+
const decoder = new TextDecoder();
|
|
28598
|
+
let pending2 = "";
|
|
28599
|
+
return async (chunk) => {
|
|
28600
|
+
pending2 += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
28601
|
+
let end;
|
|
28602
|
+
while ((end = pending2.indexOf("\n")) !== -1) {
|
|
28603
|
+
const line = pending2.slice(0, end);
|
|
28604
|
+
pending2 = pending2.slice(end + 1);
|
|
28605
|
+
if (line.trim().length === 0) continue;
|
|
28606
|
+
const frame = JSON.parse(line);
|
|
28607
|
+
if (isRecord7(frame) && frame.type === "control_request" && isRecord7(frame.request) && frame.request.subtype === "get_usage") {
|
|
28608
|
+
frame.request = { ...frame.request, skip_behaviors: true };
|
|
28609
|
+
}
|
|
28610
|
+
await write(JSON.stringify(frame) + "\n");
|
|
28411
28611
|
}
|
|
28412
|
-
];
|
|
28413
|
-
});
|
|
28414
|
-
var readClaudeQuota = async (request) => {
|
|
28415
|
-
const { recipe } = request;
|
|
28416
|
-
const connectivity = CLAUDE_CARD.modelConnectivity;
|
|
28417
|
-
const environmentRows = Object.entries(recipe.environment).map(([name, value]) => ({
|
|
28418
|
-
name,
|
|
28419
|
-
value
|
|
28420
|
-
}));
|
|
28421
|
-
if (connectivity !== void 0 && setsOwnModelConnection2(connectivity, environmentRows)) {
|
|
28422
|
-
const changesEndpoint = setsOwnModelConnection2(
|
|
28423
|
-
{
|
|
28424
|
-
baseUrlEnvKey: connectivity.baseUrlEnvKey,
|
|
28425
|
-
backendSwitchEnvKeys: connectivity.backendSwitchEnvKeys
|
|
28426
|
-
},
|
|
28427
|
-
environmentRows
|
|
28428
|
-
);
|
|
28429
|
-
return {
|
|
28430
|
-
status: "unavailable",
|
|
28431
|
-
reason: changesEndpoint ? "customEndpoint" : "unsupportedLogin"
|
|
28432
|
-
};
|
|
28433
|
-
}
|
|
28434
|
-
const credential = readLoginCredential(claudeCredentialFileCandidates(recipe));
|
|
28435
|
-
if (credential === null) return { status: "unavailable", reason: "missingCredentials" };
|
|
28436
|
-
const now = request.now ?? Date.now;
|
|
28437
|
-
let response;
|
|
28438
|
-
try {
|
|
28439
|
-
response = await request.fetch(CLAUDE_QUOTA_URL, {
|
|
28440
|
-
method: "GET",
|
|
28441
|
-
headers: {
|
|
28442
|
-
Accept: "application/json",
|
|
28443
|
-
"anthropic-beta": "oauth-2025-04-20",
|
|
28444
|
-
Authorization: `Bearer ${credential.accessToken}`
|
|
28445
|
-
},
|
|
28446
|
-
redirect: "error",
|
|
28447
|
-
signal: request.signal === void 0 ? AbortSignal.timeout(REQUEST_TIMEOUT_MS) : AbortSignal.any([request.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)])
|
|
28448
|
-
});
|
|
28449
|
-
} catch (cause) {
|
|
28450
|
-
if (request.signal?.aborted === true) throw cause;
|
|
28451
|
-
return { status: "unavailable", reason: "unreachable" };
|
|
28452
|
-
}
|
|
28453
|
-
const release = () => {
|
|
28454
|
-
void response.body?.cancel().catch(() => void 0);
|
|
28455
28612
|
};
|
|
28456
|
-
|
|
28457
|
-
|
|
28458
|
-
|
|
28459
|
-
|
|
28460
|
-
|
|
28461
|
-
reason: "rateLimited",
|
|
28462
|
-
...retryAfterMs === null ? {} : { retryAfterMs }
|
|
28463
|
-
};
|
|
28464
|
-
}
|
|
28465
|
-
if (response.status === 401 || response.status === 403) {
|
|
28466
|
-
release();
|
|
28467
|
-
return { status: "unavailable", reason: "authRejected" };
|
|
28468
|
-
}
|
|
28469
|
-
if (response.status < 200 || response.status >= 300) {
|
|
28470
|
-
release();
|
|
28471
|
-
return { status: "unavailable", reason: "unreachable" };
|
|
28613
|
+
}
|
|
28614
|
+
function quotaReading(value) {
|
|
28615
|
+
if (!isRecord7(value)) return { status: "unavailable", reason: "unreachable" };
|
|
28616
|
+
if (value.rate_limits_available === false) {
|
|
28617
|
+
return { status: "unavailable", reason: "unsupportedLogin" };
|
|
28472
28618
|
}
|
|
28473
|
-
|
|
28474
|
-
try {
|
|
28475
|
-
body = JSON.parse(await response.text());
|
|
28476
|
-
} catch {
|
|
28619
|
+
if (value.rate_limits_available !== true || !isRecord7(value.rate_limits)) {
|
|
28477
28620
|
return { status: "unavailable", reason: "unreachable" };
|
|
28478
28621
|
}
|
|
28479
|
-
|
|
28480
|
-
|
|
28622
|
+
const plan = claudePlanName({
|
|
28623
|
+
subscriptionType: typeof value.subscription_type === "string" ? value.subscription_type : void 0,
|
|
28624
|
+
rateLimitTier: void 0
|
|
28625
|
+
});
|
|
28481
28626
|
return {
|
|
28482
28627
|
status: "available",
|
|
28483
28628
|
...plan === void 0 ? {} : { plan },
|
|
28484
|
-
windows:
|
|
28485
|
-
balances: []
|
|
28486
|
-
accountKey: credential.path
|
|
28629
|
+
windows: readClaudeQuotaWindows(value.rate_limits),
|
|
28630
|
+
balances: []
|
|
28487
28631
|
};
|
|
28488
|
-
}
|
|
28632
|
+
}
|
|
28633
|
+
async function readClaudeNativeQuota(input) {
|
|
28634
|
+
const { recipe, host, signal } = input;
|
|
28635
|
+
signal?.throwIfAborted();
|
|
28636
|
+
if (!recipe.binaryPath) return void 0;
|
|
28637
|
+
try {
|
|
28638
|
+
const environment = mergeLaunchEnv3({
|
|
28639
|
+
inherited: process.env,
|
|
28640
|
+
instanceTable: recipe.environment,
|
|
28641
|
+
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
28642
|
+
});
|
|
28643
|
+
const { flags, positionals } = parseCliArgs(recipe.launchArgs);
|
|
28644
|
+
if (positionals.length > 0 || ["resume", "continue", "fork-session", "session-id", "prompt", "print"].some(
|
|
28645
|
+
(key) => key in flags
|
|
28646
|
+
)) {
|
|
28647
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
28648
|
+
}
|
|
28649
|
+
const result = await withClaudeSdkRead(
|
|
28650
|
+
{
|
|
28651
|
+
host,
|
|
28652
|
+
signal,
|
|
28653
|
+
timeoutMs: input.timeoutMs,
|
|
28654
|
+
createQuery: XAe,
|
|
28655
|
+
stdin: quotaWriter,
|
|
28656
|
+
options: {
|
|
28657
|
+
cwd: NodeOS9.tmpdir(),
|
|
28658
|
+
pathToClaudeCodeExecutable: resolveClaudeSdkExecutablePath(
|
|
28659
|
+
recipe.binaryPath,
|
|
28660
|
+
environment
|
|
28661
|
+
),
|
|
28662
|
+
env: compactEnv(claudeModelProbeEnvironment(environment)),
|
|
28663
|
+
settingSources: [...CLAUDE_SETTING_SOURCES],
|
|
28664
|
+
extraArgs: flags
|
|
28665
|
+
}
|
|
28666
|
+
},
|
|
28667
|
+
(runtime) => runtime.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET()
|
|
28668
|
+
);
|
|
28669
|
+
return quotaReading(result);
|
|
28670
|
+
} catch (error) {
|
|
28671
|
+
signal?.throwIfAborted();
|
|
28672
|
+
const message = error instanceof Error ? error.message : "";
|
|
28673
|
+
if (/get_usage/i.test(message) && /not supported|unknown|unrecognized|unsupported/i.test(message)) {
|
|
28674
|
+
return void 0;
|
|
28675
|
+
}
|
|
28676
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
28677
|
+
}
|
|
28678
|
+
}
|
|
28489
28679
|
|
|
28490
28680
|
// src/usageRead/rateLimitEvent.ts
|
|
28491
|
-
var
|
|
28681
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28492
28682
|
var claudeQuotaFromRateLimitEvent = (message) => {
|
|
28493
|
-
const info =
|
|
28494
|
-
if (!
|
|
28683
|
+
const info = isRecord8(message) ? message["rate_limit_info"] : void 0;
|
|
28684
|
+
if (!isRecord8(info)) return null;
|
|
28495
28685
|
const spec = CLAUDE_QUOTA_WINDOWS.find((window2) => window2.field === info["rateLimitType"]);
|
|
28496
28686
|
const utilization = info["utilization"];
|
|
28497
28687
|
if (spec === void 0 || typeof utilization !== "number" || !Number.isFinite(utilization)) {
|
|
@@ -28899,7 +29089,7 @@ var createClaudeTokenReader = (options) => {
|
|
|
28899
29089
|
status: "missing",
|
|
28900
29090
|
scannedFiles: 0,
|
|
28901
29091
|
skippedFiles: 0,
|
|
28902
|
-
message: "No Claude Code session records found
|
|
29092
|
+
message: "No Claude Code session records found in the configured directory."
|
|
28903
29093
|
}
|
|
28904
29094
|
};
|
|
28905
29095
|
}
|
|
@@ -28996,7 +29186,12 @@ var createClaudeUsage = (input) => {
|
|
|
28996
29186
|
cache: input.cache
|
|
28997
29187
|
});
|
|
28998
29188
|
return {
|
|
28999
|
-
readQuota: ({ signal }) =>
|
|
29189
|
+
readQuota: async ({ signal }) => {
|
|
29190
|
+
const native = await readClaudeNativeQuota({ recipe, host, signal });
|
|
29191
|
+
if (native !== void 0) return native;
|
|
29192
|
+
const fallback = await readClaudeQuota({ recipe, fetch: host.fetch, signal });
|
|
29193
|
+
return recipe.binaryPath && fallback.status === "unavailable" && fallback.reason === "missingCredentials" ? { status: "unavailable", reason: "unreachable" } : fallback;
|
|
29194
|
+
},
|
|
29000
29195
|
quotaFromRateLimits: claudeQuotaFromRateLimitEvent,
|
|
29001
29196
|
readTokenUsage: tokens.readTokenUsage
|
|
29002
29197
|
};
|
|
@@ -29067,12 +29262,13 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
29067
29262
|
if (recipe.binaryPath.length === 0) throw new Error(CLAUDE_PROGRAM_NOT_CONFIGURED);
|
|
29068
29263
|
return sdkCreateQuery(input);
|
|
29069
29264
|
};
|
|
29070
|
-
const buildLaunchEnvironment = () =>
|
|
29265
|
+
const buildLaunchEnvironment = () => mergeLaunchEnv4({
|
|
29071
29266
|
inherited: { ...process.env, ...options?.environment },
|
|
29072
29267
|
instanceTable: recipe.environment,
|
|
29073
29268
|
handOverrides: claudeHomeVariables(resolveClaudeHomeLayout(recipe))
|
|
29074
29269
|
});
|
|
29075
29270
|
const modelCatalog = makeClaudeModelCatalog({
|
|
29271
|
+
host,
|
|
29076
29272
|
recipe,
|
|
29077
29273
|
now,
|
|
29078
29274
|
createQuery,
|
|
@@ -29220,6 +29416,7 @@ function createClaudeAdapter(recipe, host, options) {
|
|
|
29220
29416
|
modelCatalog: {
|
|
29221
29417
|
refresh: modelCatalog.refresh,
|
|
29222
29418
|
current: currentModelCatalog,
|
|
29419
|
+
currentAuth: modelCatalog.currentAuth,
|
|
29223
29420
|
lastRefreshOk: modelCatalog.lastRefreshOk,
|
|
29224
29421
|
notePairedRefresh: modelCatalog.notePairedRefresh
|
|
29225
29422
|
},
|
|
@@ -29282,18 +29479,25 @@ function createClaudeInstance(config, host, attachments, overrides, usageCache)
|
|
|
29282
29479
|
};
|
|
29283
29480
|
return {
|
|
29284
29481
|
probe,
|
|
29285
|
-
readCliVersion: () => readClaudeCliVersion({ recipe, host }),
|
|
29482
|
+
readCliVersion: (signal) => readClaudeCliVersion({ recipe, host, ...signal ? { signal } : {} }),
|
|
29286
29483
|
// `force: false` 立刻返回。每天那次探测自己按清单 TTL 决定要不要读;这里只服务「版本变了」和手动刷新。
|
|
29287
|
-
refreshModelCatalog: async ({ force }) => {
|
|
29484
|
+
refreshModelCatalog: async ({ force, signal }) => {
|
|
29485
|
+
signal?.throwIfAborted();
|
|
29288
29486
|
if (!force) return;
|
|
29487
|
+
let cleanupFailed = false;
|
|
29289
29488
|
try {
|
|
29290
|
-
await adapter.modelCatalog.refresh({ force: true });
|
|
29489
|
+
await adapter.modelCatalog.refresh({ force: true, signal });
|
|
29291
29490
|
} catch (error) {
|
|
29491
|
+
if (isOperationCleanupError3(error)) {
|
|
29492
|
+
cleanupFailed = true;
|
|
29493
|
+
throw error;
|
|
29494
|
+
}
|
|
29495
|
+
signal?.throwIfAborted();
|
|
29292
29496
|
host.log.warn("claude model catalog refresh failed", {
|
|
29293
29497
|
detail: error instanceof Error ? error.message : String(error)
|
|
29294
29498
|
});
|
|
29295
29499
|
} finally {
|
|
29296
|
-
adapter.modelCatalog.notePairedRefresh();
|
|
29500
|
+
if (!signal?.aborted && !cleanupFailed) adapter.modelCatalog.notePairedRefresh();
|
|
29297
29501
|
}
|
|
29298
29502
|
},
|
|
29299
29503
|
startSession: adapter.startSession,
|
|
@@ -29349,7 +29553,7 @@ function createClaudeInstance(config, host, attachments, overrides, usageCache)
|
|
|
29349
29553
|
start: async () => {
|
|
29350
29554
|
const command = claudeSignInCommand(
|
|
29351
29555
|
recipe.credentialsPath,
|
|
29352
|
-
|
|
29556
|
+
NodeOS10.type() === "Windows_NT" ? "win32" : "linux"
|
|
29353
29557
|
);
|
|
29354
29558
|
return {
|
|
29355
29559
|
operationId: `claude-sign-in-${crypto.randomUUID()}`,
|
|
@@ -29358,7 +29562,11 @@ function createClaudeInstance(config, host, attachments, overrides, usageCache)
|
|
|
29358
29562
|
},
|
|
29359
29563
|
cancel: async () => {
|
|
29360
29564
|
},
|
|
29361
|
-
verify: async (signal) =>
|
|
29565
|
+
verify: async (signal) => {
|
|
29566
|
+
await adapter.modelCatalog.refresh({ signal, force: true });
|
|
29567
|
+
adapter.modelCatalog.notePairedRefresh();
|
|
29568
|
+
return probe(signal);
|
|
29569
|
+
}
|
|
29362
29570
|
}
|
|
29363
29571
|
};
|
|
29364
29572
|
}
|
|
@@ -29377,7 +29585,7 @@ var executors = [
|
|
|
29377
29585
|
];
|
|
29378
29586
|
var index_default = definePlugin({
|
|
29379
29587
|
id: "agent-claude",
|
|
29380
|
-
apiVersion:
|
|
29588
|
+
apiVersion: 41,
|
|
29381
29589
|
executors,
|
|
29382
29590
|
activate(ctx) {
|
|
29383
29591
|
capturedAttachments = ctx.attachments;
|