@creative-dswork/dscode 0.2.6 → 0.2.7
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 +44 -34
- package/dist/dscode.mjs +784 -369
- package/dist/web/assets/index-BETLH5IB.css +1 -0
- package/dist/web/assets/index-U_3WqyQ1.js +76 -0
- package/dist/web/index.html +2 -2
- package/package.json +4 -4
- package/dist/web/assets/index-CE2n4z2t.css +0 -1
- package/dist/web/assets/index-Ch46uOv1.js +0 -78
package/dist/dscode.mjs
CHANGED
|
@@ -115,6 +115,33 @@ var init_qwen = __esm({
|
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
// src/models/kimi.ts
|
|
119
|
+
var KIMI_BASE_URL, KIMI_MODELS;
|
|
120
|
+
var init_kimi = __esm({
|
|
121
|
+
"src/models/kimi.ts"() {
|
|
122
|
+
"use strict";
|
|
123
|
+
KIMI_BASE_URL = "https://api.moonshot.cn/v1";
|
|
124
|
+
KIMI_MODELS = {
|
|
125
|
+
"kimi-k3": {
|
|
126
|
+
api: "openai-completions",
|
|
127
|
+
provider: "kimi",
|
|
128
|
+
baseUrl: KIMI_BASE_URL,
|
|
129
|
+
reasoning: true,
|
|
130
|
+
thinkingLevelMap: { low: null, medium: null, high: null, max: "max" },
|
|
131
|
+
input: ["text", "image"],
|
|
132
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
133
|
+
contextWindow: 1048576,
|
|
134
|
+
maxTokens: 131072,
|
|
135
|
+
compat: {
|
|
136
|
+
supportsDeveloperRole: false,
|
|
137
|
+
thinkingFormat: "deepseek",
|
|
138
|
+
deferredToolsMode: "kimi"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
118
145
|
// src/models/registry.ts
|
|
119
146
|
import { builtinModels } from "@earendil-works/pi-ai/providers/all";
|
|
120
147
|
import { createProvider, lazyApi, envApiKeyAuth } from "@earendil-works/pi-ai";
|
|
@@ -155,8 +182,13 @@ function resolveModel(provider, modelId) {
|
|
|
155
182
|
function getThinkingLevel(provider, modelId) {
|
|
156
183
|
try {
|
|
157
184
|
const model = resolveModel(provider, modelId);
|
|
158
|
-
if (model.reasoning) return "
|
|
159
|
-
|
|
185
|
+
if (!model.reasoning) return "off";
|
|
186
|
+
if (model.thinkingLevelMap) {
|
|
187
|
+
const supportedLevels = Object.entries(model.thinkingLevelMap).filter(([, v]) => v !== null);
|
|
188
|
+
if (supportedLevels.length === 0) return "off";
|
|
189
|
+
if (supportedLevels.length === 1 && supportedLevels[0][0] === "max") return "max";
|
|
190
|
+
}
|
|
191
|
+
return "high";
|
|
160
192
|
} catch {
|
|
161
193
|
}
|
|
162
194
|
if (modelId.includes("thinking")) return "high";
|
|
@@ -179,11 +211,12 @@ function getEnvApiKey(provider) {
|
|
|
179
211
|
}
|
|
180
212
|
return void 0;
|
|
181
213
|
}
|
|
182
|
-
var providerFactories, customModelDefs, models, qwenProvider, API_KEY_ENV_VARS;
|
|
214
|
+
var providerFactories, customModelDefs, models, qwenProvider, kimiProvider, API_KEY_ENV_VARS;
|
|
183
215
|
var init_registry = __esm({
|
|
184
216
|
"src/models/registry.ts"() {
|
|
185
217
|
"use strict";
|
|
186
218
|
init_qwen();
|
|
219
|
+
init_kimi();
|
|
187
220
|
providerFactories = /* @__PURE__ */ new Map();
|
|
188
221
|
customModelDefs = /* @__PURE__ */ new Map();
|
|
189
222
|
models = builtinModels();
|
|
@@ -195,6 +228,15 @@ var init_registry = __esm({
|
|
|
195
228
|
models: Object.entries(QWEN_MODELS).map(([id, def]) => ({ id, name: `Qwen: ${id}`, ...def })),
|
|
196
229
|
api: lazyApi(() => import("@earendil-works/pi-ai/api/openai-completions"))
|
|
197
230
|
});
|
|
231
|
+
kimiProvider = createProvider({
|
|
232
|
+
id: "kimi",
|
|
233
|
+
name: "Kimi (Moonshot)",
|
|
234
|
+
baseUrl: KIMI_BASE_URL,
|
|
235
|
+
auth: { apiKey: envApiKeyAuth("Kimi API key", ["KIMI_API_KEY", "MOONSHOT_API_KEY"]) },
|
|
236
|
+
models: Object.entries(KIMI_MODELS).map(([id, def]) => ({ id, name: `Kimi ${id}`, ...def })),
|
|
237
|
+
api: lazyApi(() => import("@earendil-works/pi-ai/api/openai-completions"))
|
|
238
|
+
});
|
|
239
|
+
models.setProvider(kimiProvider);
|
|
198
240
|
models.setProvider(qwenProvider);
|
|
199
241
|
API_KEY_ENV_VARS = {
|
|
200
242
|
deepseek: "DEEPSEEK_API_KEY",
|
|
@@ -207,6 +249,7 @@ var init_registry = __esm({
|
|
|
207
249
|
openrouter: "OPENROUTER_API_KEY",
|
|
208
250
|
"vercel-ai-gateway": "AI_GATEWAY_API_KEY",
|
|
209
251
|
zai: "ZAI_API_KEY",
|
|
252
|
+
"kimi": "KIMI_API_KEY",
|
|
210
253
|
"zai-coding-cn": "ZAI_CODING_CN_API_KEY",
|
|
211
254
|
mistral: "MISTRAL_API_KEY",
|
|
212
255
|
minimax: "MINIMAX_API_KEY",
|
|
@@ -453,7 +496,7 @@ function loadConfig(cliCwd) {
|
|
|
453
496
|
const userCommandsDir = join(configDir, "commands");
|
|
454
497
|
const projectCommandsDir = join(projectPath, ".dscode", "commands");
|
|
455
498
|
const defaultThinkingLevel = getThinkingLevel(provider, modelId);
|
|
456
|
-
const validThinkingLevels = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh"]);
|
|
499
|
+
const validThinkingLevels = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
457
500
|
const rawThinkingLevel = process.env.AGENT_THINKING_LEVEL ?? userConfig.thinkingLevel ?? merged.thinkingLevel;
|
|
458
501
|
const thinkingLevel = rawThinkingLevel !== void 0 && validThinkingLevels.has(rawThinkingLevel) ? rawThinkingLevel : defaultThinkingLevel;
|
|
459
502
|
const retryFromEnv = {
|
|
@@ -531,6 +574,7 @@ var init_config = __esm({
|
|
|
531
574
|
PROVIDER_ENV_VARS = {
|
|
532
575
|
deepseek: "DEEPSEEK_API_KEY",
|
|
533
576
|
"kimi-coding": "KIMI_API_KEY",
|
|
577
|
+
"kimi": "KIMI_API_KEY",
|
|
534
578
|
openai: "OPENAI_API_KEY",
|
|
535
579
|
anthropic: "ANTHROPIC_API_KEY",
|
|
536
580
|
google: "GEMINI_API_KEY",
|
|
@@ -538,7 +582,8 @@ var init_config = __esm({
|
|
|
538
582
|
groq: "GROQ_API_KEY",
|
|
539
583
|
openrouter: "OPENROUTER_API_KEY",
|
|
540
584
|
mistral: "MISTRAL_API_KEY",
|
|
541
|
-
qwen: "DASHSCOPE_API_KEY"
|
|
585
|
+
qwen: "DASHSCOPE_API_KEY",
|
|
586
|
+
"moonshotai-cn": "MOONSHOT_API_KEY"
|
|
542
587
|
};
|
|
543
588
|
}
|
|
544
589
|
});
|
|
@@ -547,17 +592,17 @@ var init_config = __esm({
|
|
|
547
592
|
import { appendFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
548
593
|
import { join as join2 } from "node:path";
|
|
549
594
|
import { homedir as homedir2 } from "node:os";
|
|
550
|
-
function formatLine(level,
|
|
595
|
+
function formatLine(level, agentType, agentId, tag, message) {
|
|
551
596
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
552
|
-
return `[${ts}] [${level.toUpperCase()}] [${
|
|
597
|
+
return `[${ts}] [${level.toUpperCase()}] [${agentType}/${agentId}] [${tag}] ${message}`;
|
|
553
598
|
}
|
|
554
599
|
function ensureDir() {
|
|
555
600
|
if (!existsSync2(LOG_DIR)) {
|
|
556
601
|
mkdirSync2(LOG_DIR, { recursive: true });
|
|
557
602
|
}
|
|
558
603
|
}
|
|
559
|
-
function
|
|
560
|
-
return join2(LOG_DIR,
|
|
604
|
+
function filePath() {
|
|
605
|
+
return join2(LOG_DIR, "dscode.log");
|
|
561
606
|
}
|
|
562
607
|
var LEVEL_RANK, Logger, LOG_DIR;
|
|
563
608
|
var init_logger = __esm({
|
|
@@ -579,32 +624,32 @@ var init_logger = __esm({
|
|
|
579
624
|
this.minLevel = LEVEL_RANK[options.level ?? "debug"];
|
|
580
625
|
}
|
|
581
626
|
// ── Public API ──
|
|
582
|
-
debug(
|
|
583
|
-
this.write("debug",
|
|
627
|
+
debug(tag, message) {
|
|
628
|
+
this.write("debug", tag, message);
|
|
584
629
|
}
|
|
585
|
-
info(
|
|
586
|
-
this.write("info",
|
|
630
|
+
info(tag, message) {
|
|
631
|
+
this.write("info", tag, message);
|
|
587
632
|
}
|
|
588
|
-
warn(
|
|
589
|
-
this.write("warn",
|
|
633
|
+
warn(tag, message) {
|
|
634
|
+
this.write("warn", tag, message);
|
|
590
635
|
}
|
|
591
|
-
error(
|
|
592
|
-
this.write("error",
|
|
636
|
+
error(tag, message) {
|
|
637
|
+
this.write("error", tag, message);
|
|
593
638
|
}
|
|
594
|
-
clear(
|
|
639
|
+
clear() {
|
|
595
640
|
try {
|
|
596
641
|
ensureDir();
|
|
597
|
-
writeFileSync2(
|
|
642
|
+
writeFileSync2(filePath(), "", "utf-8");
|
|
598
643
|
} catch {
|
|
599
644
|
}
|
|
600
645
|
}
|
|
601
646
|
// ── Internal ──
|
|
602
|
-
write(level,
|
|
647
|
+
write(level, tag, message) {
|
|
603
648
|
if (LEVEL_RANK[level] < this.minLevel) return;
|
|
604
|
-
const line = formatLine(level,
|
|
649
|
+
const line = formatLine(level, this.type, this.id, tag, message);
|
|
605
650
|
try {
|
|
606
651
|
ensureDir();
|
|
607
|
-
appendFileSync(
|
|
652
|
+
appendFileSync(filePath(), line + "\n", "utf8");
|
|
608
653
|
} catch {
|
|
609
654
|
}
|
|
610
655
|
}
|
|
@@ -626,7 +671,7 @@ async function getSharp() {
|
|
|
626
671
|
return sharpInstance;
|
|
627
672
|
} catch {
|
|
628
673
|
sharpAvailable = false;
|
|
629
|
-
_cacheLogger.warn("
|
|
674
|
+
_cacheLogger.warn("ImageCache", "sharp not available, images will be stored uncompressed");
|
|
630
675
|
return null;
|
|
631
676
|
}
|
|
632
677
|
}
|
|
@@ -685,7 +730,7 @@ var init_cache = __esm({
|
|
|
685
730
|
await pipeline.png().toFile(filepath);
|
|
686
731
|
return { type: "image_ref", hash: filename, mimeType: "image/png" };
|
|
687
732
|
} catch (err) {
|
|
688
|
-
_cacheLogger.warn("
|
|
733
|
+
_cacheLogger.warn("ImageCache", `sharp processing failed, storing original: ${String(err)}`);
|
|
689
734
|
}
|
|
690
735
|
}
|
|
691
736
|
if (!existsSync3(filepath)) {
|
|
@@ -830,20 +875,20 @@ var init_store = __esm({
|
|
|
830
875
|
const projPath = join4(this.projectDir, `${id}.json`);
|
|
831
876
|
const globalPath = join4(this.globalDir, `${id}.json`);
|
|
832
877
|
let raw;
|
|
833
|
-
let
|
|
878
|
+
let filePath2;
|
|
834
879
|
if (existsSync4(projPath)) {
|
|
835
|
-
|
|
880
|
+
filePath2 = projPath;
|
|
836
881
|
} else if (existsSync4(globalPath)) {
|
|
837
|
-
|
|
882
|
+
filePath2 = globalPath;
|
|
838
883
|
} else {
|
|
839
884
|
throw new SessionValidateError(`Session not found: ${id}`);
|
|
840
885
|
}
|
|
841
|
-
const stat4 = existsSync4(
|
|
886
|
+
const stat4 = existsSync4(filePath2);
|
|
842
887
|
if (!stat4) {
|
|
843
888
|
throw new SessionValidateError(`Session not found: ${id}`);
|
|
844
889
|
}
|
|
845
890
|
try {
|
|
846
|
-
raw = JSON.parse(readFileSync3(
|
|
891
|
+
raw = JSON.parse(readFileSync3(filePath2, "utf8"));
|
|
847
892
|
} catch {
|
|
848
893
|
throw new SessionValidateError("Session file is corrupted: invalid JSON");
|
|
849
894
|
}
|
|
@@ -853,16 +898,16 @@ var init_store = __esm({
|
|
|
853
898
|
async loadSessionFile(sessionId) {
|
|
854
899
|
const projPath = join4(this.projectDir, `${sessionId}.json`);
|
|
855
900
|
const globalPath = join4(this.globalDir, `${sessionId}.json`);
|
|
856
|
-
let
|
|
901
|
+
let filePath2;
|
|
857
902
|
if (existsSync4(projPath)) {
|
|
858
|
-
|
|
903
|
+
filePath2 = projPath;
|
|
859
904
|
} else if (existsSync4(globalPath)) {
|
|
860
|
-
|
|
905
|
+
filePath2 = globalPath;
|
|
861
906
|
} else {
|
|
862
907
|
return null;
|
|
863
908
|
}
|
|
864
909
|
try {
|
|
865
|
-
const raw = JSON.parse(readFileSync3(
|
|
910
|
+
const raw = JSON.parse(readFileSync3(filePath2, "utf8"));
|
|
866
911
|
return validateSession(raw, sessionId);
|
|
867
912
|
} catch {
|
|
868
913
|
return null;
|
|
@@ -1228,7 +1273,7 @@ var init_manager = __esm({
|
|
|
1228
1273
|
try {
|
|
1229
1274
|
this.saveSession(agent, pendingPermission);
|
|
1230
1275
|
} catch (err) {
|
|
1231
|
-
this.logger.error("
|
|
1276
|
+
this.logger.error("Save", `trySaveSession failed: ${String(err)}`);
|
|
1232
1277
|
}
|
|
1233
1278
|
}
|
|
1234
1279
|
async loadSession(id, agent) {
|
|
@@ -9124,11 +9169,11 @@ ${lanes.join("\n")}
|
|
|
9124
9169
|
const toCanonicalName = createGetCanonicalFileName(useCaseSensitiveFileNames2);
|
|
9125
9170
|
return nonPollingWatchFile;
|
|
9126
9171
|
function nonPollingWatchFile(fileName, callback, _pollingInterval, fallbackOptions) {
|
|
9127
|
-
const
|
|
9128
|
-
if (fileWatcherCallbacks.add(
|
|
9129
|
-
fileTimestamps.set(
|
|
9172
|
+
const filePath2 = toCanonicalName(fileName);
|
|
9173
|
+
if (fileWatcherCallbacks.add(filePath2, callback).length === 1 && fileTimestamps) {
|
|
9174
|
+
fileTimestamps.set(filePath2, getModifiedTime3(fileName) || missingFileModifiedTime);
|
|
9130
9175
|
}
|
|
9131
|
-
const dirPath = getDirectoryPath(
|
|
9176
|
+
const dirPath = getDirectoryPath(filePath2) || ".";
|
|
9132
9177
|
const watcher = dirWatchers.get(dirPath) || createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions);
|
|
9133
9178
|
watcher.referenceCount++;
|
|
9134
9179
|
return {
|
|
@@ -9139,7 +9184,7 @@ ${lanes.join("\n")}
|
|
|
9139
9184
|
} else {
|
|
9140
9185
|
watcher.referenceCount--;
|
|
9141
9186
|
}
|
|
9142
|
-
fileWatcherCallbacks.remove(
|
|
9187
|
+
fileWatcherCallbacks.remove(filePath2, callback);
|
|
9143
9188
|
}
|
|
9144
9189
|
};
|
|
9145
9190
|
}
|
|
@@ -9150,19 +9195,19 @@ ${lanes.join("\n")}
|
|
|
9150
9195
|
(eventName, relativeFileName) => {
|
|
9151
9196
|
if (!isString2(relativeFileName)) return;
|
|
9152
9197
|
const fileName = getNormalizedAbsolutePath(relativeFileName, dirName);
|
|
9153
|
-
const
|
|
9154
|
-
const callbacks = fileName && fileWatcherCallbacks.get(
|
|
9198
|
+
const filePath2 = toCanonicalName(fileName);
|
|
9199
|
+
const callbacks = fileName && fileWatcherCallbacks.get(filePath2);
|
|
9155
9200
|
if (callbacks) {
|
|
9156
9201
|
let currentModifiedTime;
|
|
9157
9202
|
let eventKind = 1;
|
|
9158
9203
|
if (fileTimestamps) {
|
|
9159
|
-
const existingTime = fileTimestamps.get(
|
|
9204
|
+
const existingTime = fileTimestamps.get(filePath2);
|
|
9160
9205
|
if (eventName === "change") {
|
|
9161
9206
|
currentModifiedTime = getModifiedTime3(fileName) || missingFileModifiedTime;
|
|
9162
9207
|
if (currentModifiedTime.getTime() === existingTime.getTime()) return;
|
|
9163
9208
|
}
|
|
9164
9209
|
currentModifiedTime || (currentModifiedTime = getModifiedTime3(fileName) || missingFileModifiedTime);
|
|
9165
|
-
fileTimestamps.set(
|
|
9210
|
+
fileTimestamps.set(filePath2, currentModifiedTime);
|
|
9166
9211
|
if (existingTime === missingFileModifiedTime) eventKind = 0;
|
|
9167
9212
|
else if (currentModifiedTime === missingFileModifiedTime) eventKind = 2;
|
|
9168
9213
|
}
|
|
@@ -16645,20 +16690,20 @@ ${lanes.join("\n")}
|
|
|
16645
16690
|
function trySetLanguageAndTerritory(language2, territory2, errors2) {
|
|
16646
16691
|
const compilerFilePath = normalizePath2(sys2.getExecutingFilePath());
|
|
16647
16692
|
const containingDirectoryPath = getDirectoryPath(compilerFilePath);
|
|
16648
|
-
let
|
|
16693
|
+
let filePath2 = combinePaths(containingDirectoryPath, language2);
|
|
16649
16694
|
if (territory2) {
|
|
16650
|
-
|
|
16695
|
+
filePath2 = filePath2 + "-" + territory2;
|
|
16651
16696
|
}
|
|
16652
|
-
|
|
16653
|
-
if (!sys2.fileExists(
|
|
16697
|
+
filePath2 = sys2.resolvePath(combinePaths(filePath2, "diagnosticMessages.generated.json"));
|
|
16698
|
+
if (!sys2.fileExists(filePath2)) {
|
|
16654
16699
|
return false;
|
|
16655
16700
|
}
|
|
16656
16701
|
let fileContents = "";
|
|
16657
16702
|
try {
|
|
16658
|
-
fileContents = sys2.readFile(
|
|
16703
|
+
fileContents = sys2.readFile(filePath2);
|
|
16659
16704
|
} catch {
|
|
16660
16705
|
if (errors2) {
|
|
16661
|
-
errors2.push(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0,
|
|
16706
|
+
errors2.push(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0, filePath2));
|
|
16662
16707
|
}
|
|
16663
16708
|
return false;
|
|
16664
16709
|
}
|
|
@@ -16666,7 +16711,7 @@ ${lanes.join("\n")}
|
|
|
16666
16711
|
setLocalizedDiagnosticMessages(JSON.parse(fileContents));
|
|
16667
16712
|
} catch {
|
|
16668
16713
|
if (errors2) {
|
|
16669
|
-
errors2.push(createCompilerDiagnostic(Diagnostics.Corrupted_locale_file_0,
|
|
16714
|
+
errors2.push(createCompilerDiagnostic(Diagnostics.Corrupted_locale_file_0, filePath2));
|
|
16670
16715
|
}
|
|
16671
16716
|
return false;
|
|
16672
16717
|
}
|
|
@@ -22118,10 +22163,10 @@ ${lanes.join("\n")}
|
|
|
22118
22163
|
function getExternalModuleNameFromPath(host, fileName, referencePath) {
|
|
22119
22164
|
const getCanonicalFileName = (f) => host.getCanonicalFileName(f);
|
|
22120
22165
|
const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName);
|
|
22121
|
-
const
|
|
22166
|
+
const filePath2 = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
|
|
22122
22167
|
const relativePath = getRelativePathToDirectoryOrUrl(
|
|
22123
22168
|
dir,
|
|
22124
|
-
|
|
22169
|
+
filePath2,
|
|
22125
22170
|
dir,
|
|
22126
22171
|
getCanonicalFileName,
|
|
22127
22172
|
/*isAbsolutePathAnUrl*/
|
|
@@ -22196,11 +22241,11 @@ ${lanes.join("\n")}
|
|
|
22196
22241
|
/* Js */
|
|
22197
22242
|
];
|
|
22198
22243
|
}
|
|
22199
|
-
function getPossibleOriginalInputPathWithoutChangingExt(
|
|
22244
|
+
function getPossibleOriginalInputPathWithoutChangingExt(filePath2, ignoreCase, outputDir, getCommonSourceDirectory2) {
|
|
22200
22245
|
return outputDir ? resolvePath2(
|
|
22201
22246
|
getCommonSourceDirectory2(),
|
|
22202
|
-
getRelativePathFromDirectory(outputDir,
|
|
22203
|
-
) :
|
|
22247
|
+
getRelativePathFromDirectory(outputDir, filePath2, ignoreCase)
|
|
22248
|
+
) : filePath2;
|
|
22204
22249
|
}
|
|
22205
22250
|
function getPathsBasePath(options, host) {
|
|
22206
22251
|
var _a;
|
|
@@ -131244,7 +131289,7 @@ ${lanes.join("\n")}
|
|
|
131244
131289
|
const sourceRoot = normalizeSlashes(mapOptions.sourceRoot || "");
|
|
131245
131290
|
return sourceRoot ? ensureTrailingDirectorySeparator(sourceRoot) : sourceRoot;
|
|
131246
131291
|
}
|
|
131247
|
-
function getSourceMapDirectory(mapOptions,
|
|
131292
|
+
function getSourceMapDirectory(mapOptions, filePath2, sourceFile) {
|
|
131248
131293
|
if (mapOptions.sourceRoot) return host.getCommonSourceDirectory();
|
|
131249
131294
|
if (mapOptions.mapRoot) {
|
|
131250
131295
|
let sourceMapDir = normalizeSlashes(mapOptions.mapRoot);
|
|
@@ -131256,9 +131301,9 @@ ${lanes.join("\n")}
|
|
|
131256
131301
|
}
|
|
131257
131302
|
return sourceMapDir;
|
|
131258
131303
|
}
|
|
131259
|
-
return getDirectoryPath(normalizePath2(
|
|
131304
|
+
return getDirectoryPath(normalizePath2(filePath2));
|
|
131260
131305
|
}
|
|
131261
|
-
function getSourceMappingURL(mapOptions, sourceMapGenerator,
|
|
131306
|
+
function getSourceMappingURL(mapOptions, sourceMapGenerator, filePath2, sourceMapFilePath, sourceFile) {
|
|
131262
131307
|
if (mapOptions.inlineSourceMap) {
|
|
131263
131308
|
const sourceMapText = sourceMapGenerator.toString();
|
|
131264
131309
|
const base64SourceMapText = base64encode(sys, sourceMapText);
|
|
@@ -131274,7 +131319,7 @@ ${lanes.join("\n")}
|
|
|
131274
131319
|
sourceMapDir = combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
|
|
131275
131320
|
return encodeURI(
|
|
131276
131321
|
getRelativePathToDirectoryOrUrl(
|
|
131277
|
-
getDirectoryPath(normalizePath2(
|
|
131322
|
+
getDirectoryPath(normalizePath2(filePath2)),
|
|
131278
131323
|
// get the relative sourceMapDir path based on jsFilePath
|
|
131279
131324
|
combinePaths(sourceMapDir, sourceMapFile),
|
|
131280
131325
|
// this is where user expects to see sourceMap
|
|
@@ -136253,11 +136298,11 @@ ${lanes.join("\n")}
|
|
|
136253
136298
|
}
|
|
136254
136299
|
return fsQueryResult;
|
|
136255
136300
|
}
|
|
136256
|
-
function addOrDeleteFile(fileName,
|
|
136301
|
+
function addOrDeleteFile(fileName, filePath2, eventKind) {
|
|
136257
136302
|
if (eventKind === 1) {
|
|
136258
136303
|
return;
|
|
136259
136304
|
}
|
|
136260
|
-
const parentResult = getCachedFileSystemEntriesForBaseDir(
|
|
136305
|
+
const parentResult = getCachedFileSystemEntriesForBaseDir(filePath2);
|
|
136261
136306
|
if (parentResult) {
|
|
136262
136307
|
updateFilesOfFileSystemEntry(
|
|
136263
136308
|
parentResult,
|
|
@@ -136266,7 +136311,7 @@ ${lanes.join("\n")}
|
|
|
136266
136311
|
/* Created */
|
|
136267
136312
|
);
|
|
136268
136313
|
} else {
|
|
136269
|
-
clearFirstAncestorEntry(
|
|
136314
|
+
clearFirstAncestorEntry(filePath2);
|
|
136270
136315
|
}
|
|
136271
136316
|
}
|
|
136272
136317
|
function updateFilesOfFileSystemEntry(parentResult, baseName, fileExists22) {
|
|
@@ -137800,7 +137845,7 @@ ${lanes.join("\n")}
|
|
|
137800
137845
|
function forEachResolution(resolutionCache, callback, file) {
|
|
137801
137846
|
var _a2;
|
|
137802
137847
|
if (file) (_a2 = resolutionCache == null ? void 0 : resolutionCache.get(file.path)) == null ? void 0 : _a2.forEach((resolution, name, mode) => callback(resolution, name, mode, file.path));
|
|
137803
|
-
else resolutionCache == null ? void 0 : resolutionCache.forEach((resolutions,
|
|
137848
|
+
else resolutionCache == null ? void 0 : resolutionCache.forEach((resolutions, filePath2) => resolutions.forEach((resolution, name, mode) => callback(resolution, name, mode, filePath2)));
|
|
137804
137849
|
}
|
|
137805
137850
|
function getPackagesMap() {
|
|
137806
137851
|
if (packageMap) return packageMap;
|
|
@@ -140139,26 +140184,26 @@ ${lanes.join("\n")}
|
|
|
140139
140184
|
if (options.noEmit) {
|
|
140140
140185
|
return false;
|
|
140141
140186
|
}
|
|
140142
|
-
const
|
|
140143
|
-
if (getSourceFileByPath(
|
|
140187
|
+
const filePath2 = toPath3(file);
|
|
140188
|
+
if (getSourceFileByPath(filePath2)) {
|
|
140144
140189
|
return false;
|
|
140145
140190
|
}
|
|
140146
140191
|
const out = options.outFile;
|
|
140147
140192
|
if (out) {
|
|
140148
|
-
return isSameFile(
|
|
140149
|
-
|
|
140193
|
+
return isSameFile(filePath2, out) || isSameFile(
|
|
140194
|
+
filePath2,
|
|
140150
140195
|
removeFileExtension(out) + ".d.ts"
|
|
140151
140196
|
/* Dts */
|
|
140152
140197
|
);
|
|
140153
140198
|
}
|
|
140154
|
-
if (options.declarationDir && containsPath(options.declarationDir,
|
|
140199
|
+
if (options.declarationDir && containsPath(options.declarationDir, filePath2, currentDirectory, !host.useCaseSensitiveFileNames())) {
|
|
140155
140200
|
return true;
|
|
140156
140201
|
}
|
|
140157
140202
|
if (options.outDir) {
|
|
140158
|
-
return containsPath(options.outDir,
|
|
140203
|
+
return containsPath(options.outDir, filePath2, currentDirectory, !host.useCaseSensitiveFileNames());
|
|
140159
140204
|
}
|
|
140160
|
-
if (fileExtensionIsOneOf(
|
|
140161
|
-
const filePathWithoutExtension = removeFileExtension(
|
|
140205
|
+
if (fileExtensionIsOneOf(filePath2, supportedJSExtensionsFlat) || isDeclarationFileName(filePath2)) {
|
|
140206
|
+
const filePathWithoutExtension = removeFileExtension(filePath2);
|
|
140162
140207
|
return !!getSourceFileByPath(
|
|
140163
140208
|
filePathWithoutExtension + ".ts"
|
|
140164
140209
|
/* Ts */
|
|
@@ -141570,9 +141615,9 @@ ${lanes.join("\n")}
|
|
|
141570
141615
|
const newSignature = Debug.checkDefined(state.fileInfos.get(path)).signature;
|
|
141571
141616
|
return newSignature !== oldSignature;
|
|
141572
141617
|
}
|
|
141573
|
-
function handleDtsMayChangeOfGlobalScope(state,
|
|
141618
|
+
function handleDtsMayChangeOfGlobalScope(state, filePath2, invalidateJsFiles, cancellationToken, host) {
|
|
141574
141619
|
var _a;
|
|
141575
|
-
if (!((_a = state.fileInfos.get(
|
|
141620
|
+
if (!((_a = state.fileInfos.get(filePath2)) == null ? void 0 : _a.affectsGlobalScope)) return false;
|
|
141576
141621
|
BuilderState.getAllFilesExcludingDefaultLibraryFile(
|
|
141577
141622
|
state,
|
|
141578
141623
|
state.program,
|
|
@@ -141638,9 +141683,9 @@ ${lanes.join("\n")}
|
|
|
141638
141683
|
(_b = state.referencedMap.getKeys(affectedFile.resolvedPath)) == null ? void 0 : _b.forEach((exportedFromPath) => {
|
|
141639
141684
|
if (handleDtsMayChangeOfGlobalScope(state, exportedFromPath, invalidateJsFiles, cancellationToken, host)) return true;
|
|
141640
141685
|
const references = state.referencedMap.getKeys(exportedFromPath);
|
|
141641
|
-
return references && forEachKey(references, (
|
|
141686
|
+
return references && forEachKey(references, (filePath2) => handleDtsMayChangeOfFileAndExportsOfFile(
|
|
141642
141687
|
state,
|
|
141643
|
-
|
|
141688
|
+
filePath2,
|
|
141644
141689
|
invalidateJsFiles,
|
|
141645
141690
|
seenFileAndExportsOfFile,
|
|
141646
141691
|
cancellationToken,
|
|
@@ -141648,12 +141693,12 @@ ${lanes.join("\n")}
|
|
|
141648
141693
|
));
|
|
141649
141694
|
});
|
|
141650
141695
|
}
|
|
141651
|
-
function handleDtsMayChangeOfFileAndExportsOfFile(state,
|
|
141696
|
+
function handleDtsMayChangeOfFileAndExportsOfFile(state, filePath2, invalidateJsFiles, seenFileAndExportsOfFile, cancellationToken, host) {
|
|
141652
141697
|
var _a;
|
|
141653
|
-
if (!tryAddToSet(seenFileAndExportsOfFile,
|
|
141654
|
-
if (handleDtsMayChangeOfGlobalScope(state,
|
|
141655
|
-
handleDtsMayChangeOf(state,
|
|
141656
|
-
(_a = state.referencedMap.getKeys(
|
|
141698
|
+
if (!tryAddToSet(seenFileAndExportsOfFile, filePath2)) return void 0;
|
|
141699
|
+
if (handleDtsMayChangeOfGlobalScope(state, filePath2, invalidateJsFiles, cancellationToken, host)) return true;
|
|
141700
|
+
handleDtsMayChangeOf(state, filePath2, invalidateJsFiles, cancellationToken, host);
|
|
141701
|
+
(_a = state.referencedMap.getKeys(filePath2)) == null ? void 0 : _a.forEach(
|
|
141657
141702
|
(referencingFilePath) => handleDtsMayChangeOfFileAndExportsOfFile(
|
|
141658
141703
|
state,
|
|
141659
141704
|
referencingFilePath,
|
|
@@ -142297,10 +142342,10 @@ ${lanes.join("\n")}
|
|
|
142297
142342
|
}
|
|
142298
142343
|
}
|
|
142299
142344
|
if (state.compilerOptions.composite) {
|
|
142300
|
-
const
|
|
142301
|
-
emitSignature = handleNewSignature((_c = state.emitSignatures) == null ? void 0 : _c.get(
|
|
142345
|
+
const filePath2 = sourceFiles[0].resolvedPath;
|
|
142346
|
+
emitSignature = handleNewSignature((_c = state.emitSignatures) == null ? void 0 : _c.get(filePath2), emitSignature);
|
|
142302
142347
|
if (!emitSignature) return data.skippedDtsWrite = true;
|
|
142303
|
-
(state.emitSignatures ?? (state.emitSignatures = /* @__PURE__ */ new Map())).set(
|
|
142348
|
+
(state.emitSignatures ?? (state.emitSignatures = /* @__PURE__ */ new Map())).set(filePath2, emitSignature);
|
|
142304
142349
|
}
|
|
142305
142350
|
} else if (state.compilerOptions.composite) {
|
|
142306
142351
|
const newSignature = handleNewSignature(
|
|
@@ -142783,8 +142828,8 @@ ${lanes.join("\n")}
|
|
|
142783
142828
|
function canWatchAffectedPackageJsonOrNodeModulesOfAtTypes(fileOrDirPath) {
|
|
142784
142829
|
return canWatchDirectoryOrFilePath(fileOrDirPath);
|
|
142785
142830
|
}
|
|
142786
|
-
function canWatchAffectingLocation(
|
|
142787
|
-
return canWatchAffectedPackageJsonOrNodeModulesOfAtTypes(
|
|
142831
|
+
function canWatchAffectingLocation(filePath2) {
|
|
142832
|
+
return canWatchAffectedPackageJsonOrNodeModulesOfAtTypes(filePath2);
|
|
142788
142833
|
}
|
|
142789
142834
|
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath, rootDir, rootPath, rootPathComponents, isRootWatchable, getCurrentDirectory, preferNonRecursiveWatch) {
|
|
142790
142835
|
const failedLookupPathComponents = getPathComponents(failedLookupLocationPath);
|
|
@@ -143366,8 +143411,8 @@ ${lanes.join("\n")}
|
|
|
143366
143411
|
function isNodeModulesAtTypesDirectory(dirPath) {
|
|
143367
143412
|
return endsWith(dirPath, "/node_modules/@types");
|
|
143368
143413
|
}
|
|
143369
|
-
function watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution,
|
|
143370
|
-
(resolution.files ?? (resolution.files = /* @__PURE__ */ new Set())).add(
|
|
143414
|
+
function watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, filePath2, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution) {
|
|
143415
|
+
(resolution.files ?? (resolution.files = /* @__PURE__ */ new Set())).add(filePath2);
|
|
143371
143416
|
if (resolution.files.size !== 1) return;
|
|
143372
143417
|
if (!deferWatchingNonRelativeResolution || isExternalModuleNameRelative(name)) {
|
|
143373
143418
|
watchFailedLookupLocationOfResolution(resolution);
|
|
@@ -143609,8 +143654,8 @@ ${lanes.join("\n")}
|
|
|
143609
143654
|
}
|
|
143610
143655
|
return removeAtRoot;
|
|
143611
143656
|
}
|
|
143612
|
-
function stopWatchFailedLookupLocationOfResolution(resolution,
|
|
143613
|
-
Debug.checkDefined(resolution.files).delete(
|
|
143657
|
+
function stopWatchFailedLookupLocationOfResolution(resolution, filePath2, getResolutionWithResolvedFileName) {
|
|
143658
|
+
Debug.checkDefined(resolution.files).delete(filePath2);
|
|
143614
143659
|
if (resolution.files.size) return;
|
|
143615
143660
|
resolution.files = void 0;
|
|
143616
143661
|
const resolved = getResolutionWithResolvedFileName(resolution);
|
|
@@ -143657,34 +143702,34 @@ ${lanes.join("\n")}
|
|
|
143657
143702
|
/* Recursive */
|
|
143658
143703
|
);
|
|
143659
143704
|
}
|
|
143660
|
-
function removeResolutionsOfFileFromCache(cache,
|
|
143661
|
-
const resolutions = cache.get(
|
|
143705
|
+
function removeResolutionsOfFileFromCache(cache, filePath2, getResolutionWithResolvedFileName) {
|
|
143706
|
+
const resolutions = cache.get(filePath2);
|
|
143662
143707
|
if (resolutions) {
|
|
143663
143708
|
resolutions.forEach(
|
|
143664
143709
|
(resolution) => stopWatchFailedLookupLocationOfResolution(
|
|
143665
143710
|
resolution,
|
|
143666
|
-
|
|
143711
|
+
filePath2,
|
|
143667
143712
|
getResolutionWithResolvedFileName
|
|
143668
143713
|
)
|
|
143669
143714
|
);
|
|
143670
|
-
cache.delete(
|
|
143715
|
+
cache.delete(filePath2);
|
|
143671
143716
|
}
|
|
143672
143717
|
}
|
|
143673
|
-
function removeResolutionsFromProjectReferenceRedirects(
|
|
143718
|
+
function removeResolutionsFromProjectReferenceRedirects(filePath2) {
|
|
143674
143719
|
if (!fileExtensionIs(
|
|
143675
|
-
|
|
143720
|
+
filePath2,
|
|
143676
143721
|
".json"
|
|
143677
143722
|
/* Json */
|
|
143678
143723
|
)) return;
|
|
143679
143724
|
const program = resolutionHost.getCurrentProgram();
|
|
143680
143725
|
if (!program) return;
|
|
143681
|
-
const resolvedProjectReference = program.getResolvedProjectReferenceByPath(
|
|
143726
|
+
const resolvedProjectReference = program.getResolvedProjectReferenceByPath(filePath2);
|
|
143682
143727
|
if (!resolvedProjectReference) return;
|
|
143683
143728
|
resolvedProjectReference.commandLine.fileNames.forEach((f) => removeResolutionsOfFile(resolutionHost.toPath(f)));
|
|
143684
143729
|
}
|
|
143685
|
-
function removeResolutionsOfFile(
|
|
143686
|
-
removeResolutionsOfFileFromCache(resolvedModuleNames,
|
|
143687
|
-
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives,
|
|
143730
|
+
function removeResolutionsOfFile(filePath2) {
|
|
143731
|
+
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath2, getResolvedModuleFromResolution);
|
|
143732
|
+
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath2, getResolvedTypeReferenceDirectiveFromResolution);
|
|
143688
143733
|
}
|
|
143689
143734
|
function invalidateResolutions(resolutions, canInvalidate) {
|
|
143690
143735
|
if (!resolutions) return false;
|
|
@@ -143699,10 +143744,10 @@ ${lanes.join("\n")}
|
|
|
143699
143744
|
});
|
|
143700
143745
|
return invalidated;
|
|
143701
143746
|
}
|
|
143702
|
-
function invalidateResolutionOfFile(
|
|
143703
|
-
removeResolutionsOfFile(
|
|
143747
|
+
function invalidateResolutionOfFile(filePath2) {
|
|
143748
|
+
removeResolutionsOfFile(filePath2);
|
|
143704
143749
|
const prevHasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
|
|
143705
|
-
if (invalidateResolutions(resolvedFileToResolution.get(
|
|
143750
|
+
if (invalidateResolutions(resolvedFileToResolution.get(filePath2), returnTrue) && hasChangedAutomaticTypeDirectiveNames && !prevHasChangedAutomaticTypeDirectiveNames) {
|
|
143706
143751
|
resolutionHost.onChangedAutomaticTypeDirectiveNames();
|
|
143707
143752
|
}
|
|
143708
143753
|
}
|
|
@@ -144096,9 +144141,9 @@ ${lanes.join("\n")}
|
|
|
144096
144141
|
var _a;
|
|
144097
144142
|
const configFile = program.getCompilerOptions().configFile;
|
|
144098
144143
|
if (!((_a = configFile == null ? void 0 : configFile.configFileSpecs) == null ? void 0 : _a.validatedFilesSpec)) return void 0;
|
|
144099
|
-
const
|
|
144144
|
+
const filePath2 = program.getCanonicalFileName(fileName);
|
|
144100
144145
|
const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()));
|
|
144101
|
-
const index = findIndex(configFile.configFileSpecs.validatedFilesSpec, (fileSpec) => program.getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) ===
|
|
144146
|
+
const index = findIndex(configFile.configFileSpecs.validatedFilesSpec, (fileSpec) => program.getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath2);
|
|
144102
144147
|
return index !== -1 ? configFile.configFileSpecs.validatedFilesSpecBeforeSubstitution[index] : void 0;
|
|
144103
144148
|
}
|
|
144104
144149
|
function getMatchedIncludeSpec(program, fileName) {
|
|
@@ -183289,13 +183334,13 @@ ${newComment.split("\n").map((c2) => ` * ${c2}`).join("\n")}
|
|
|
183289
183334
|
["./*"]
|
|
183290
183335
|
);
|
|
183291
183336
|
if (files) {
|
|
183292
|
-
for (let
|
|
183293
|
-
|
|
183294
|
-
if (exclude && comparePaths(
|
|
183337
|
+
for (let filePath2 of files) {
|
|
183338
|
+
filePath2 = normalizePath2(filePath2);
|
|
183339
|
+
if (exclude && comparePaths(filePath2, exclude, scriptDirectory, ignoreCase) === 0) {
|
|
183295
183340
|
continue;
|
|
183296
183341
|
}
|
|
183297
183342
|
const { name, extension } = getFilenameWithExtensionOption(
|
|
183298
|
-
getBaseFileName(
|
|
183343
|
+
getBaseFileName(filePath2),
|
|
183299
183344
|
program,
|
|
183300
183345
|
extensionOptions,
|
|
183301
183346
|
/*isExportsOrImportsWildcard*/
|
|
@@ -189595,8 +189640,8 @@ ${content}
|
|
|
189595
189640
|
}
|
|
189596
189641
|
return void 0;
|
|
189597
189642
|
}
|
|
189598
|
-
function getPackagePathComponents(
|
|
189599
|
-
const components = getPathComponents(
|
|
189643
|
+
function getPackagePathComponents(filePath2) {
|
|
189644
|
+
const components = getPathComponents(filePath2);
|
|
189600
189645
|
const nodeModulesIdx = components.lastIndexOf("node_modules");
|
|
189601
189646
|
if (nodeModulesIdx === -1) {
|
|
189602
189647
|
return void 0;
|
|
@@ -201069,8 +201114,8 @@ ${options.prefix}` : "\n" : options.prefix
|
|
|
201069
201114
|
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
|
|
201070
201115
|
}
|
|
201071
201116
|
/** @internal */
|
|
201072
|
-
fileIsOpen(
|
|
201073
|
-
return this.projectService.openFiles.has(
|
|
201117
|
+
fileIsOpen(filePath2) {
|
|
201118
|
+
return this.projectService.openFiles.has(filePath2);
|
|
201074
201119
|
}
|
|
201075
201120
|
/** @internal */
|
|
201076
201121
|
writeLog(s) {
|
|
@@ -215423,15 +215468,15 @@ function generateDashboard(result, outputPath) {
|
|
|
215423
215468
|
writeFileSync10(outputPath, html, "utf8");
|
|
215424
215469
|
return outputPath;
|
|
215425
215470
|
}
|
|
215426
|
-
function openDashboard(
|
|
215471
|
+
function openDashboard(filePath2) {
|
|
215427
215472
|
const platform = process.platform;
|
|
215428
215473
|
let cmd;
|
|
215429
215474
|
if (platform === "darwin") {
|
|
215430
|
-
cmd = `open "${
|
|
215475
|
+
cmd = `open "${filePath2}"`;
|
|
215431
215476
|
} else if (platform === "linux") {
|
|
215432
|
-
cmd = `xdg-open "${
|
|
215477
|
+
cmd = `xdg-open "${filePath2}"`;
|
|
215433
215478
|
} else if (platform === "win32") {
|
|
215434
|
-
cmd = `start "" "${
|
|
215479
|
+
cmd = `start "" "${filePath2}"`;
|
|
215435
215480
|
} else {
|
|
215436
215481
|
return;
|
|
215437
215482
|
}
|
|
@@ -215723,11 +215768,11 @@ function safeJsonParse(json, stepName, validator, logger) {
|
|
|
215723
215768
|
parsed = JSON.parse(json);
|
|
215724
215769
|
} catch (err) {
|
|
215725
215770
|
const msg = err instanceof Error ? err.message : String(err);
|
|
215726
|
-
if (logger) logger.warn(
|
|
215771
|
+
if (logger) logger.warn(stepName, `JSON parse: ${msg}`);
|
|
215727
215772
|
}
|
|
215728
215773
|
const result = validator(parsed);
|
|
215729
215774
|
if (!result.ok) {
|
|
215730
|
-
if (logger) logger.warn(
|
|
215775
|
+
if (logger) logger.warn(stepName, `validation: ${result.errors.join("; ")}`);
|
|
215731
215776
|
if (result.partial !== void 0) return result.partial;
|
|
215732
215777
|
return null;
|
|
215733
215778
|
}
|
|
@@ -216742,13 +216787,13 @@ async function attributeWithLLM(data, steps, stats, meta, graphStore, attributio
|
|
|
216742
216787
|
statsSummary,
|
|
216743
216788
|
recoveryArcs
|
|
216744
216789
|
);
|
|
216745
|
-
if (logger) logger.info("
|
|
216790
|
+
if (logger) logger.info("RuleAttribution", `Prompt size: ${prompt.length} chars, graph ${graphSnapshot ? `${graphSnapshot.dataFlows.length} dataFlows, ${graphSnapshot.subtasks.length} subtasks` : "none"}`);
|
|
216746
216791
|
let rawOutput;
|
|
216747
216792
|
let rulesOutput = [];
|
|
216748
216793
|
try {
|
|
216749
216794
|
rawOutput = await callLLM(RULE_ATTRIBUTION_SYSTEM, prompt, harness, 16384);
|
|
216750
216795
|
} catch (err) {
|
|
216751
|
-
if (logger) logger.warn("
|
|
216796
|
+
if (logger) logger.warn("RuleAttribution", `LLM call failed: ${err.message}`);
|
|
216752
216797
|
return [];
|
|
216753
216798
|
}
|
|
216754
216799
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
@@ -216760,11 +216805,11 @@ async function attributeWithLLM(data, steps, stats, meta, graphStore, attributio
|
|
|
216760
216805
|
rawOutput = await callLLM(RULE_ATTRIBUTION_SYSTEM, retryPrompt, harness, 16384);
|
|
216761
216806
|
continue;
|
|
216762
216807
|
} catch {
|
|
216763
|
-
if (logger) logger.warn("
|
|
216808
|
+
if (logger) logger.warn("RuleAttribution", "Retry LLM call failed");
|
|
216764
216809
|
return [];
|
|
216765
216810
|
}
|
|
216766
216811
|
}
|
|
216767
|
-
if (logger) logger.warn("
|
|
216812
|
+
if (logger) logger.warn("RuleAttribution", "No JSON found in LLM response after retry");
|
|
216768
216813
|
return [];
|
|
216769
216814
|
}
|
|
216770
216815
|
let parsed;
|
|
@@ -216802,7 +216847,7 @@ Output the FULL corrected JSON array.`;
|
|
|
216802
216847
|
rawOutput = await callLLM(RULE_ATTRIBUTION_SYSTEM, retryPrompt, harness, 16384);
|
|
216803
216848
|
continue;
|
|
216804
216849
|
} catch {
|
|
216805
|
-
if (logger) logger.warn("
|
|
216850
|
+
if (logger) logger.warn("RuleAttribution", "Validation retry failed");
|
|
216806
216851
|
break;
|
|
216807
216852
|
}
|
|
216808
216853
|
}
|
|
@@ -216816,11 +216861,11 @@ Output the FULL corrected JSON array.`;
|
|
|
216816
216861
|
rawOutput = await callLLM(RULE_ATTRIBUTION_SYSTEM, retryPrompt, harness, 16384);
|
|
216817
216862
|
continue;
|
|
216818
216863
|
} catch {
|
|
216819
|
-
if (logger) logger.warn("
|
|
216864
|
+
if (logger) logger.warn("RuleAttribution", "Retry LLM call failed");
|
|
216820
216865
|
return [];
|
|
216821
216866
|
}
|
|
216822
216867
|
}
|
|
216823
|
-
if (logger) logger.warn("
|
|
216868
|
+
if (logger) logger.warn("RuleAttribution", "No JSON found in LLM response after retry");
|
|
216824
216869
|
return [];
|
|
216825
216870
|
}
|
|
216826
216871
|
const parsed = safeJsonParse(json, "rule-attribution", validateHarnessRuleOutputs);
|
|
@@ -216836,14 +216881,14 @@ Output the FULL corrected JSON array.`;
|
|
|
216836
216881
|
rawOutput = await callLLM(RULE_ATTRIBUTION_SYSTEM, retryPrompt, harness, 16384);
|
|
216837
216882
|
continue;
|
|
216838
216883
|
} catch {
|
|
216839
|
-
if (logger) logger.warn("
|
|
216884
|
+
if (logger) logger.warn("RuleAttribution", "Validation retry failed");
|
|
216840
216885
|
return [];
|
|
216841
216886
|
}
|
|
216842
216887
|
}
|
|
216843
216888
|
}
|
|
216844
|
-
if (logger) logger.info("
|
|
216889
|
+
if (logger) logger.info("RuleAttribution", `Generated ${rulesOutput.length} rules`);
|
|
216845
216890
|
if (rulesOutput.length === 0) {
|
|
216846
|
-
if (logger) logger.info("
|
|
216891
|
+
if (logger) logger.info("RuleAttribution", `Raw LLM response (first 500): ${rawOutput.slice(0, 500)}`);
|
|
216847
216892
|
}
|
|
216848
216893
|
return rulesOutput.map((r) => ({
|
|
216849
216894
|
id: r.id,
|
|
@@ -218393,9 +218438,9 @@ function writeLibraryMetadata(skeleton, workspacePath) {
|
|
|
218393
218438
|
`| Screenshots Taken | ${stats.screenshotsTaken} |`,
|
|
218394
218439
|
""
|
|
218395
218440
|
].join("\n");
|
|
218396
|
-
const
|
|
218397
|
-
writeFileSync12(
|
|
218398
|
-
return
|
|
218441
|
+
const filePath2 = join24(workspacePath, "library", "meta.md");
|
|
218442
|
+
writeFileSync12(filePath2, content, "utf-8");
|
|
218443
|
+
return filePath2;
|
|
218399
218444
|
}
|
|
218400
218445
|
function writeLibrarySkeleton(skeleton, workspacePath) {
|
|
218401
218446
|
const lines = [];
|
|
@@ -218458,9 +218503,9 @@ function writeLibrarySkeleton(skeleton, workspacePath) {
|
|
|
218458
218503
|
}
|
|
218459
218504
|
lines.push(hints.join("\n"));
|
|
218460
218505
|
lines.push("");
|
|
218461
|
-
const
|
|
218462
|
-
writeFileSync12(
|
|
218463
|
-
return
|
|
218506
|
+
const filePath2 = join24(workspacePath, "library", "skeleton.md");
|
|
218507
|
+
writeFileSync12(filePath2, lines.join("\n"), "utf-8");
|
|
218508
|
+
return filePath2;
|
|
218464
218509
|
}
|
|
218465
218510
|
function writeLibrarySignals(skeleton, workspacePath) {
|
|
218466
218511
|
const typeOrder = [
|
|
@@ -218504,9 +218549,9 @@ function writeLibrarySignals(skeleton, workspacePath) {
|
|
|
218504
218549
|
lines.push("_No signal anchors detected._");
|
|
218505
218550
|
lines.push("");
|
|
218506
218551
|
}
|
|
218507
|
-
const
|
|
218508
|
-
writeFileSync12(
|
|
218509
|
-
return
|
|
218552
|
+
const filePath2 = join24(workspacePath, "library", "signals.md");
|
|
218553
|
+
writeFileSync12(filePath2, lines.join("\n"), "utf-8");
|
|
218554
|
+
return filePath2;
|
|
218510
218555
|
}
|
|
218511
218556
|
function writeLibraryDataItems(skeleton, workspacePath) {
|
|
218512
218557
|
const sorted = [...skeleton.dataItems].sort((a, b) => b.operationCount - a.operationCount);
|
|
@@ -218527,9 +218572,9 @@ function writeLibraryDataItems(skeleton, workspacePath) {
|
|
|
218527
218572
|
lines.push("");
|
|
218528
218573
|
}
|
|
218529
218574
|
}
|
|
218530
|
-
const
|
|
218531
|
-
writeFileSync12(
|
|
218532
|
-
return
|
|
218575
|
+
const filePath2 = join24(workspacePath, "library", "data-items.md");
|
|
218576
|
+
writeFileSync12(filePath2, lines.join("\n"), "utf-8");
|
|
218577
|
+
return filePath2;
|
|
218533
218578
|
}
|
|
218534
218579
|
function writeLibrarySteps(steps, phases, workspacePath) {
|
|
218535
218580
|
const MAX_STEPS_PER_FILE = 150;
|
|
@@ -218570,9 +218615,9 @@ function writeLibrarySteps(steps, phases, workspacePath) {
|
|
|
218570
218615
|
}
|
|
218571
218616
|
lines.push("");
|
|
218572
218617
|
}
|
|
218573
|
-
const
|
|
218574
|
-
writeFileSync12(
|
|
218575
|
-
written.push(
|
|
218618
|
+
const filePath2 = join24(workspacePath, "library", "steps", fileName);
|
|
218619
|
+
writeFileSync12(filePath2, lines.join("\n"), "utf-8");
|
|
218620
|
+
written.push(filePath2);
|
|
218576
218621
|
}
|
|
218577
218622
|
}
|
|
218578
218623
|
return written;
|
|
@@ -218654,9 +218699,9 @@ function writeLibraryReadme(phase, workspacePath) {
|
|
|
218654
218699
|
"- `glob(pattern)` \u2014 list files matching a pattern in library/ or notebook/",
|
|
218655
218700
|
""
|
|
218656
218701
|
].join("\n");
|
|
218657
|
-
const
|
|
218658
|
-
writeFileSync12(
|
|
218659
|
-
return
|
|
218702
|
+
const filePath2 = join24(workspacePath, "library", "README.md");
|
|
218703
|
+
writeFileSync12(filePath2, content, "utf-8");
|
|
218704
|
+
return filePath2;
|
|
218660
218705
|
}
|
|
218661
218706
|
function writeLibrary(skeleton, steps, ruleResult, phase, workspacePath) {
|
|
218662
218707
|
let fileCount = 0;
|
|
@@ -218750,7 +218795,7 @@ var init_progress = __esm({
|
|
|
218750
218795
|
this.logProgressBar();
|
|
218751
218796
|
}
|
|
218752
218797
|
if (this.logger) {
|
|
218753
|
-
this.logger.info("
|
|
218798
|
+
this.logger.info("Progress", label);
|
|
218754
218799
|
}
|
|
218755
218800
|
}
|
|
218756
218801
|
onPhaseProgress(phaseIndex, event, subZoneId) {
|
|
@@ -218789,7 +218834,7 @@ var init_progress = __esm({
|
|
|
218789
218834
|
this.emitWebEvent("phaseDone", { phaseIndex, summary, durationMs });
|
|
218790
218835
|
if (summary) {
|
|
218791
218836
|
if (this.onLog) this.onLog(`\u2713 ${summary}`);
|
|
218792
|
-
if (this.logger) this.logger.info("
|
|
218837
|
+
if (this.logger) this.logger.info("Progress", `Phase ${phaseIndex} done: ${summary}`);
|
|
218793
218838
|
}
|
|
218794
218839
|
this.logProgressBar();
|
|
218795
218840
|
}
|
|
@@ -218814,7 +218859,7 @@ var init_progress = __esm({
|
|
|
218814
218859
|
this.logProgressBar();
|
|
218815
218860
|
}
|
|
218816
218861
|
if (this.logger) {
|
|
218817
|
-
this.logger.info("
|
|
218862
|
+
this.logger.info("Progress", msg);
|
|
218818
218863
|
}
|
|
218819
218864
|
}
|
|
218820
218865
|
dispose() {
|
|
@@ -218916,7 +218961,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218916
218961
|
}
|
|
218917
218962
|
const pipelineStart = Date.now();
|
|
218918
218963
|
let totalLLMCalls = 0;
|
|
218919
|
-
if (logger) logger.info("
|
|
218964
|
+
if (logger) logger.info("FocusPipeline", `Start: ${steps.length} steps, session ${sessionId.slice(0, 8)}`);
|
|
218920
218965
|
const progress = new ProgressDisplay({ onLog, logger });
|
|
218921
218966
|
progress.onPhaseStart(0);
|
|
218922
218967
|
await yieldTui();
|
|
@@ -218936,7 +218981,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218936
218981
|
const workspacePath = createWorkspace(sessionId);
|
|
218937
218982
|
const { fileCount } = writeLibrary(skeleton, steps, ruleResult, "SCAN", workspacePath);
|
|
218938
218983
|
cleanOldWorkspaces(10);
|
|
218939
|
-
if (logger) logger.info("
|
|
218984
|
+
if (logger) logger.info("Phase0", `Library: ${fileCount} files \u2192 ${workspacePath}`);
|
|
218940
218985
|
progress.onPhaseDone(0, `\u5199\u5165 ${fileCount} \u4E2A\u6587\u4EF6`, Date.now() - pipelineStart);
|
|
218941
218986
|
await yieldTui();
|
|
218942
218987
|
progress.onPhaseStart(1);
|
|
@@ -218944,7 +218989,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218944
218989
|
const scanResult = await scanSession(skeleton, harness, workspacePath, sessionId, progress);
|
|
218945
218990
|
totalLLMCalls++;
|
|
218946
218991
|
const scanSummary = scanResult.noIssuesDetected ? "\u672A\u68C0\u6D4B\u5230\u95EE\u9898" : `\u8BC6\u522B\u5230 ${scanResult.zones.length} \u4E2A attention zones: ${scanResult.zones.map((z) => z.id).join(", ")}`;
|
|
218947
|
-
if (logger) logger.info("
|
|
218992
|
+
if (logger) logger.info("SCAN", scanSummary);
|
|
218948
218993
|
progress.onPhaseDone(1, scanSummary, Date.now() - pipelineStart);
|
|
218949
218994
|
await yieldTui();
|
|
218950
218995
|
if (scanResult.noIssuesDetected || scanResult.zones.length === 0) {
|
|
@@ -218961,7 +219006,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218961
219006
|
Date.now(),
|
|
218962
219007
|
logger
|
|
218963
219008
|
);
|
|
218964
|
-
if (logger) logger.info("
|
|
219009
|
+
if (logger) logger.info("FocusPipeline", "Early exit: no issues detected");
|
|
218965
219010
|
return { ...sessionStats, phases: [], deviations: [], rootCauses: [], rules: rules2, timeline: [], causalGraph: null, attribution: null, rulesApplied: [] };
|
|
218966
219011
|
}
|
|
218967
219012
|
progress.onPhaseStart(2);
|
|
@@ -218980,7 +219025,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218980
219025
|
zoneAnalyses.push({ zoneId: zone.id, subtasks: [], subtaskEdges: [], agentNodes: [], agentEdges: [], stepDataFlows: [], candidates: [], topCandidate: null, zoneGraphComplete: false });
|
|
218981
219026
|
}
|
|
218982
219027
|
}
|
|
218983
|
-
if (logger) logger.info("
|
|
219028
|
+
if (logger) logger.info("ZOOM", `${zoneAnalyses.length} zones, ${zoneAnalyses.filter((z) => z.zoneGraphComplete).length} complete`);
|
|
218984
219029
|
progress.onPhaseDone(2, `${zoneAnalyses.length} zones \u5206\u6790\u5B8C\u6210`, Date.now() - pipelineStart);
|
|
218985
219030
|
await yieldTui();
|
|
218986
219031
|
progress.onPhaseStart(3);
|
|
@@ -218996,7 +219041,7 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
218996
219041
|
);
|
|
218997
219042
|
totalLLMCalls++;
|
|
218998
219043
|
const synthSummary = attribution.mistakeStep > 0 ? `\u6839\u56E0: ${attribution.mistakeAgent}@Step ${attribution.mistakeStep}` : "\u5F52\u56E0\u5B8C\u6210";
|
|
218999
|
-
if (logger) logger.info("
|
|
219044
|
+
if (logger) logger.info("SYNTH", synthSummary);
|
|
219000
219045
|
progress.onPhaseDone(3, synthSummary, Date.now() - pipelineStart);
|
|
219001
219046
|
await yieldTui();
|
|
219002
219047
|
progress.onPhaseStart(4);
|
|
@@ -219017,11 +219062,11 @@ async function runFocusPipeline(data, harness, sessionStats, onLog, logger) {
|
|
|
219017
219062
|
sessionStats.metadata.sessionId,
|
|
219018
219063
|
Date.now()
|
|
219019
219064
|
);
|
|
219020
|
-
if (logger) logger.info("
|
|
219065
|
+
if (logger) logger.info("Phase4", `${rules.length} rules extracted`);
|
|
219021
219066
|
progress.onPhaseDone(4, `${rules.length} \u6761\u89C4\u5219`, Date.now() - pipelineStart);
|
|
219022
219067
|
const totalDuration = Date.now() - pipelineStart;
|
|
219023
219068
|
const keyFindings = attribution.mistakeStep > 0 ? `\u6839\u56E0: ${attribution.mistakeAgent}@Step ${attribution.mistakeStep}` : "\u672A\u68C0\u6D4B\u5230\u660E\u786E\u6839\u56E0";
|
|
219024
|
-
if (logger) logger.info("
|
|
219069
|
+
if (logger) logger.info("FocusPipeline", `Done: ${(totalDuration / 1e3).toFixed(1)}s, ${totalLLMCalls} LLM calls, ${keyFindings}`);
|
|
219025
219070
|
progress.showCompletion({ totalDurationMs: totalDuration, totalLLMCalls, keyFindings });
|
|
219026
219071
|
progress.dispose();
|
|
219027
219072
|
const report = { skeleton, scan: scanResult, zoneAnalyses, attribution, totalLLMCalls };
|
|
@@ -219134,11 +219179,11 @@ async function executeStep1(steps, question, harness, logger) {
|
|
|
219134
219179
|
const prev = result[i];
|
|
219135
219180
|
const next = result[i + 1];
|
|
219136
219181
|
if (prev.stepEnd >= next.stepStart) {
|
|
219137
|
-
if (logger) logger.warn("
|
|
219182
|
+
if (logger) logger.warn("Step1", `Fixing overlap: ${prev.id} (${prev.stepStart}-${prev.stepEnd}) overlaps ${next.id} (${next.stepStart}-${next.stepEnd}), truncating ${prev.id}.stepEnd to ${next.stepStart - 1}`);
|
|
219138
219183
|
prev.stepEnd = next.stepStart - 1;
|
|
219139
219184
|
}
|
|
219140
219185
|
if (prev.stepEnd + 1 < next.stepStart) {
|
|
219141
|
-
if (logger) logger.warn("
|
|
219186
|
+
if (logger) logger.warn("Step1", `Filling gap: gap ${prev.stepEnd + 1}-${next.stepStart - 1} between ${prev.id} and ${next.id}, extending ${prev.id}.stepEnd to ${next.stepStart - 1}`);
|
|
219142
219187
|
prev.stepEnd = next.stepStart - 1;
|
|
219143
219188
|
}
|
|
219144
219189
|
}
|
|
@@ -219191,16 +219236,16 @@ async function executeStep3(subtasks, steps, harness, logger) {
|
|
|
219191
219236
|
const prompt = buildStep3SingleSubtaskPrompt(subtask, steps, subtasks);
|
|
219192
219237
|
const flows = await callAndValidate(harness, prompt, validateStepDataFlows, 4096, `Step 3 / ${subtask.id}`);
|
|
219193
219238
|
allFlows.push(...flows);
|
|
219194
|
-
if (logger) logger.info("
|
|
219239
|
+
if (logger) logger.info("Step3", `Subtask ${subtask.id}: ${flows.length} data flows extracted`);
|
|
219195
219240
|
} catch (err) {
|
|
219196
|
-
if (logger) logger.warn("
|
|
219241
|
+
if (logger) logger.warn("Step3", `Subtask ${subtask.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
219197
219242
|
failedSubtasks++;
|
|
219198
219243
|
}
|
|
219199
219244
|
}
|
|
219200
219245
|
if (failedSubtasks > 0) {
|
|
219201
|
-
if (logger) logger.warn("
|
|
219246
|
+
if (logger) logger.warn("Step3", `${failedSubtasks}/${subtasks.length} subtasks failed to produce data flows`);
|
|
219202
219247
|
}
|
|
219203
|
-
if (logger) logger.info("
|
|
219248
|
+
if (logger) logger.info("Step3", `Subtask summary: ${allFlows.length} total data flows from ${subtasks.length - failedSubtasks}/${subtasks.length} subtasks`);
|
|
219204
219249
|
return { agents, dataFlows: allFlows };
|
|
219205
219250
|
}
|
|
219206
219251
|
async function executeStep4(subtasks, agentNodes, harness) {
|
|
@@ -219407,7 +219452,7 @@ function loadRuleStore(projectPath, logger) {
|
|
|
219407
219452
|
updatedAt: parsed.updatedAt ?? Date.now()
|
|
219408
219453
|
};
|
|
219409
219454
|
} catch (err) {
|
|
219410
|
-
if (logger) logger.warn("
|
|
219455
|
+
if (logger) logger.warn("RuleStore", `Failed to load rules.json, starting fresh: ${err.message}`);
|
|
219411
219456
|
return createEmptyStore(projectPath);
|
|
219412
219457
|
}
|
|
219413
219458
|
}
|
|
@@ -219418,7 +219463,7 @@ function saveRuleStore(store, logger) {
|
|
|
219418
219463
|
store.updatedAt = Date.now();
|
|
219419
219464
|
writeFileSync13(path, JSON.stringify(store, null, 2), "utf8");
|
|
219420
219465
|
} catch (err) {
|
|
219421
|
-
if (logger) logger.error("
|
|
219466
|
+
if (logger) logger.error("RuleStore", `Failed to save rules.json: ${err.message}`);
|
|
219422
219467
|
}
|
|
219423
219468
|
}
|
|
219424
219469
|
function createEmptyStore(projectPath) {
|
|
@@ -219476,7 +219521,7 @@ async function semanticMerge(newRules, existingStore, harness, logger) {
|
|
|
219476
219521
|
rawOutput = await callMergeLLM(RULE_MERGE_SYSTEM, prompt + "\n\n\u26A0 Output PURE JSON array only.", harness);
|
|
219477
219522
|
continue;
|
|
219478
219523
|
}
|
|
219479
|
-
if (logger) logger.warn("
|
|
219524
|
+
if (logger) logger.warn("RuleStore", "No JSON in merge LLM response, adding all as new");
|
|
219480
219525
|
break;
|
|
219481
219526
|
}
|
|
219482
219527
|
const parsed = validateMergeDecisions(JSON.parse(json));
|
|
@@ -219494,10 +219539,10 @@ async function semanticMerge(newRules, existingStore, harness, logger) {
|
|
|
219494
219539
|
);
|
|
219495
219540
|
continue;
|
|
219496
219541
|
}
|
|
219497
|
-
if (logger) logger.warn("
|
|
219542
|
+
if (logger) logger.warn("RuleStore", `Merge validation failed: ${parsed.errors.join("; ")}`);
|
|
219498
219543
|
}
|
|
219499
219544
|
} catch (err) {
|
|
219500
|
-
if (logger) logger.warn("
|
|
219545
|
+
if (logger) logger.warn("RuleStore", `Semantic merge LLM call failed, adding all as new: ${err.message}`);
|
|
219501
219546
|
}
|
|
219502
219547
|
const merged = { ...existingStore.rules };
|
|
219503
219548
|
const decisionMap = new Map(decisions.map((d) => [d.newRuleId, d]));
|
|
@@ -219578,7 +219623,7 @@ async function runEval(sessionId, ctx) {
|
|
|
219578
219623
|
}
|
|
219579
219624
|
}
|
|
219580
219625
|
}
|
|
219581
|
-
evalLogger.clear(
|
|
219626
|
+
evalLogger.clear();
|
|
219582
219627
|
ui.addInfo(`\u6B63\u5728\u5206\u6790 session ${resolvedId.slice(0, 8)}...`);
|
|
219583
219628
|
const onLog = (msg) => {
|
|
219584
219629
|
ui.addInfo(msg);
|
|
@@ -219604,9 +219649,9 @@ async function runEval(sessionId, ctx) {
|
|
|
219604
219649
|
[${analysisLabel}] Messages: ${result.metadata.totalMessages} | Tool calls: ${result.stats.toolCalls} | Error rate: ${result.stats.errorRate}${attributionInfo} | Rules: ${rulesTriggered}`
|
|
219605
219650
|
);
|
|
219606
219651
|
} catch (err) {
|
|
219607
|
-
evalLogger.error("
|
|
219652
|
+
evalLogger.error("Pipeline", `crash: ${err instanceof Error ? err.message : String(err)}`);
|
|
219608
219653
|
if (err instanceof Error && err.stack) {
|
|
219609
|
-
evalLogger.error("
|
|
219654
|
+
evalLogger.error("Pipeline", `stack:
|
|
219610
219655
|
${err.stack}`);
|
|
219611
219656
|
}
|
|
219612
219657
|
ui.addError(`eval: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -220624,18 +220669,18 @@ function safeResolveWithin(projectPath, relPath) {
|
|
|
220624
220669
|
}
|
|
220625
220670
|
return resolved;
|
|
220626
220671
|
}
|
|
220627
|
-
function isTextPath(
|
|
220628
|
-
const ext =
|
|
220672
|
+
function isTextPath(filePath2) {
|
|
220673
|
+
const ext = filePath2.slice(filePath2.lastIndexOf(".")).toLowerCase();
|
|
220629
220674
|
if (BINARY_EXTENSIONS.has(ext)) return false;
|
|
220630
220675
|
if (TEXT_EXTENSIONS.has(ext)) return true;
|
|
220631
220676
|
return false;
|
|
220632
220677
|
}
|
|
220633
|
-
function isImagePath(
|
|
220634
|
-
const ext =
|
|
220678
|
+
function isImagePath(filePath2) {
|
|
220679
|
+
const ext = filePath2.slice(filePath2.lastIndexOf(".")).toLowerCase();
|
|
220635
220680
|
return IMAGE_EXTENSIONS.has(ext);
|
|
220636
220681
|
}
|
|
220637
|
-
function imageMimeType(
|
|
220638
|
-
const ext =
|
|
220682
|
+
function imageMimeType(filePath2) {
|
|
220683
|
+
const ext = filePath2.slice(filePath2.lastIndexOf(".")).toLowerCase();
|
|
220639
220684
|
return IMAGE_MIME_MAP[ext] ?? "image/png";
|
|
220640
220685
|
}
|
|
220641
220686
|
function isBinaryContent(buf) {
|
|
@@ -220645,8 +220690,8 @@ function isBinaryContent(buf) {
|
|
|
220645
220690
|
}
|
|
220646
220691
|
return false;
|
|
220647
220692
|
}
|
|
220648
|
-
function inferLanguage(
|
|
220649
|
-
const ext =
|
|
220693
|
+
function inferLanguage(filePath2) {
|
|
220694
|
+
const ext = filePath2.slice(filePath2.lastIndexOf(".")).toLowerCase();
|
|
220650
220695
|
return LANG_MAP[ext] ?? "";
|
|
220651
220696
|
}
|
|
220652
220697
|
function isLikelyFilePath(text) {
|
|
@@ -221570,8 +221615,8 @@ __export(web_backend_exports, {
|
|
|
221570
221615
|
WebUiBackend: () => WebUiBackend
|
|
221571
221616
|
});
|
|
221572
221617
|
import { createServer, request as httpRequest2 } from "node:http";
|
|
221573
|
-
import { readFileSync as
|
|
221574
|
-
import { join as
|
|
221618
|
+
import { readFileSync as readFileSync22, existsSync as existsSync25, mkdirSync as mkdirSync13, writeFileSync as writeFileSync15, rmSync as rmSync3, readdirSync as readdirSync9, statSync as statSync5 } from "node:fs";
|
|
221619
|
+
import { join as join30, extname as extname2, resolve as resolve10 } from "node:path";
|
|
221575
221620
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
221576
221621
|
function extractImagesFromToolResult(result) {
|
|
221577
221622
|
if (!result || typeof result !== "object") return void 0;
|
|
@@ -221631,8 +221676,8 @@ var init_web_backend = __esm({
|
|
|
221631
221676
|
lastArtifactHtml = "";
|
|
221632
221677
|
isAssistantTurn = false;
|
|
221633
221678
|
cleanupUploadDir(sessionId) {
|
|
221634
|
-
const uploadDir =
|
|
221635
|
-
if (
|
|
221679
|
+
const uploadDir = join30(this.config.projectPath, ".dscode", "uploads", sessionId);
|
|
221680
|
+
if (existsSync25(uploadDir)) {
|
|
221636
221681
|
try {
|
|
221637
221682
|
rmSync3(uploadDir, { recursive: true, force: true });
|
|
221638
221683
|
} catch {
|
|
@@ -222021,13 +222066,13 @@ var init_web_backend = __esm({
|
|
|
222021
222066
|
const sm = this.harness.sessionManager;
|
|
222022
222067
|
const sessionId = sm.getCurrentSessionId?.() ?? "default";
|
|
222023
222068
|
const ts = Date.now();
|
|
222024
|
-
const uploadDir =
|
|
222069
|
+
const uploadDir = join30(this.config.projectPath, ".dscode", "uploads", sessionId);
|
|
222025
222070
|
mkdirSync13(uploadDir, { recursive: true });
|
|
222026
222071
|
const tempPaths = [];
|
|
222027
222072
|
for (const uf of cmd.uploadedFiles) {
|
|
222028
222073
|
const tempName = `${ts}-${uf.name}`;
|
|
222029
|
-
const tempPath =
|
|
222030
|
-
|
|
222074
|
+
const tempPath = join30(uploadDir, tempName);
|
|
222075
|
+
writeFileSync15(tempPath, Buffer.from(uf.content, "base64"));
|
|
222031
222076
|
tempPaths.push(tempPath);
|
|
222032
222077
|
}
|
|
222033
222078
|
if (tempPaths.length > 0) {
|
|
@@ -222113,7 +222158,7 @@ ${refsResolved.text}` : refsResolved.text;
|
|
|
222113
222158
|
mimeType: img.mimeType
|
|
222114
222159
|
}));
|
|
222115
222160
|
this.pendingImages = [];
|
|
222116
|
-
this.harness.logger.info("
|
|
222161
|
+
this.harness.logger.info("WebBackend", `promptWithImages: textLen=${text.length}, images=${imageContents.length}, img[0].dataLen=${imageContents[0]?.data?.length ?? 0}, mime=${imageContents[0]?.mimeType ?? "?"}`);
|
|
222117
222162
|
await this.harness.promptWithImages(text, imageContents);
|
|
222118
222163
|
} else {
|
|
222119
222164
|
this.pendingImages = [];
|
|
@@ -222142,7 +222187,7 @@ ${refsResolved.text}` : refsResolved.text;
|
|
|
222142
222187
|
fuzzyPattern: fuzzy,
|
|
222143
222188
|
permissionArgs: this.currentPermissionArgs
|
|
222144
222189
|
};
|
|
222145
|
-
this.harness.logger.info("
|
|
222190
|
+
this.harness.logger.info("WebBackend", "saving pendingPermission to metadata, then denying");
|
|
222146
222191
|
sm.saveSession(this.harness.agent, meta.pendingPermission);
|
|
222147
222192
|
}
|
|
222148
222193
|
this.permissionResolve({ decision: "deny" });
|
|
@@ -222272,9 +222317,9 @@ ${refsResolved.text}` : refsResolved.text;
|
|
|
222272
222317
|
}
|
|
222273
222318
|
}
|
|
222274
222319
|
handleCache(client, cmd) {
|
|
222275
|
-
const uploadsDir =
|
|
222320
|
+
const uploadsDir = join30(this.config.projectPath, ".dscode", "uploads");
|
|
222276
222321
|
if (cmd.action === "clear") {
|
|
222277
|
-
if (
|
|
222322
|
+
if (existsSync25(uploadsDir)) {
|
|
222278
222323
|
try {
|
|
222279
222324
|
rmSync3(uploadsDir, { recursive: true, force: true });
|
|
222280
222325
|
} catch {
|
|
@@ -222286,16 +222331,16 @@ ${refsResolved.text}` : refsResolved.text;
|
|
|
222286
222331
|
let totalBytes = 0;
|
|
222287
222332
|
let fileCount = 0;
|
|
222288
222333
|
let sessionCount = 0;
|
|
222289
|
-
if (
|
|
222334
|
+
if (existsSync25(uploadsDir)) {
|
|
222290
222335
|
const sessionDirs = readdirSync9(uploadsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
222291
222336
|
sessionCount = sessionDirs.length;
|
|
222292
222337
|
for (const dir of sessionDirs) {
|
|
222293
|
-
const sessionPath =
|
|
222338
|
+
const sessionPath = join30(uploadsDir, dir.name);
|
|
222294
222339
|
const files = readdirSync9(sessionPath, { withFileTypes: true });
|
|
222295
222340
|
for (const f of files) {
|
|
222296
222341
|
if (f.isFile()) {
|
|
222297
222342
|
try {
|
|
222298
|
-
const st = statSync5(
|
|
222343
|
+
const st = statSync5(join30(sessionPath, f.name));
|
|
222299
222344
|
totalBytes += st.size;
|
|
222300
222345
|
fileCount++;
|
|
222301
222346
|
} catch {
|
|
@@ -222630,15 +222675,15 @@ ${matchList}` });
|
|
|
222630
222675
|
const meta = sessionManager.getCurrentMetadata();
|
|
222631
222676
|
if (meta?.pendingPermission) {
|
|
222632
222677
|
pendingPermission = meta.pendingPermission;
|
|
222633
|
-
this.harness.logger.info("
|
|
222678
|
+
this.harness.logger.info("WebBackend", "using pendingPermission from metadata");
|
|
222634
222679
|
}
|
|
222635
222680
|
}
|
|
222636
222681
|
this.harness.abort();
|
|
222637
222682
|
if (pendingPermission) {
|
|
222638
|
-
this.harness.logger.info("
|
|
222683
|
+
this.harness.logger.info("WebBackend", `saving with pendingPermission: ${JSON.stringify(pendingPermission)}`);
|
|
222639
222684
|
sessionManager.saveSession(agent, pendingPermission);
|
|
222640
222685
|
} else {
|
|
222641
|
-
this.harness.logger.info("
|
|
222686
|
+
this.harness.logger.info("WebBackend", "saving without pendingPermission");
|
|
222642
222687
|
this.harness.saveSessionNow();
|
|
222643
222688
|
}
|
|
222644
222689
|
const result = await sessionManager.loadSession(match.id, agent);
|
|
@@ -222881,15 +222926,15 @@ ${matchList}` });
|
|
|
222881
222926
|
req.pipe(proxyReq);
|
|
222882
222927
|
}
|
|
222883
222928
|
serveSpa(req, res) {
|
|
222884
|
-
const projectDist =
|
|
222885
|
-
const moduleDist =
|
|
222886
|
-
const webDist =
|
|
222887
|
-
let
|
|
222888
|
-
const qIdx =
|
|
222889
|
-
if (qIdx >= 0)
|
|
222890
|
-
const hIdx =
|
|
222891
|
-
if (hIdx >= 0)
|
|
222892
|
-
const ext = extname2(
|
|
222929
|
+
const projectDist = join30(resolve10(this.projectRoot), "dist", "web");
|
|
222930
|
+
const moduleDist = join30(fileURLToPath3(new URL(".", import.meta.url)), "web");
|
|
222931
|
+
const webDist = existsSync25(projectDist) ? projectDist : moduleDist;
|
|
222932
|
+
let filePath2 = join30(webDist, req.url === "/" ? "index.html" : req.url);
|
|
222933
|
+
const qIdx = filePath2.indexOf("?");
|
|
222934
|
+
if (qIdx >= 0) filePath2 = filePath2.slice(0, qIdx);
|
|
222935
|
+
const hIdx = filePath2.indexOf("#");
|
|
222936
|
+
if (hIdx >= 0) filePath2 = filePath2.slice(0, hIdx);
|
|
222937
|
+
const ext = extname2(filePath2);
|
|
222893
222938
|
const mimeTypes = {
|
|
222894
222939
|
".html": "text/html",
|
|
222895
222940
|
".js": "application/javascript",
|
|
@@ -222902,12 +222947,12 @@ ${matchList}` });
|
|
|
222902
222947
|
".woff": "font/woff"
|
|
222903
222948
|
};
|
|
222904
222949
|
try {
|
|
222905
|
-
if (
|
|
222906
|
-
const content =
|
|
222950
|
+
if (existsSync25(filePath2) && ext) {
|
|
222951
|
+
const content = readFileSync22(filePath2);
|
|
222907
222952
|
res.writeHead(200, { "Content-Type": mimeTypes[ext] ?? "application/octet-stream" });
|
|
222908
222953
|
res.end(content);
|
|
222909
222954
|
} else {
|
|
222910
|
-
const html =
|
|
222955
|
+
const html = readFileSync22(join30(webDist, "index.html"));
|
|
222911
222956
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
222912
222957
|
res.end(html);
|
|
222913
222958
|
}
|
|
@@ -222920,9 +222965,9 @@ ${matchList}` });
|
|
|
222920
222965
|
try {
|
|
222921
222966
|
let styleConstraints = "";
|
|
222922
222967
|
try {
|
|
222923
|
-
const skillPath =
|
|
222924
|
-
if (
|
|
222925
|
-
styleConstraints =
|
|
222968
|
+
const skillPath = join30(this.config.projectPath, ".dscode", "html_output_skill");
|
|
222969
|
+
if (existsSync25(skillPath)) {
|
|
222970
|
+
styleConstraints = readFileSync22(skillPath, "utf-8");
|
|
222926
222971
|
}
|
|
222927
222972
|
} catch {
|
|
222928
222973
|
}
|
|
@@ -223007,6 +223052,10 @@ Modify the HTML to fulfill the user's request. Output the complete modified HTML
|
|
|
223007
223052
|
}
|
|
223008
223053
|
}
|
|
223009
223054
|
fullHtml = this.stripArtifactFences(fullHtml);
|
|
223055
|
+
try {
|
|
223056
|
+
writeFileSync15(join30(this.config.projectPath, "_artifact_debug.html"), fullHtml, "utf-8");
|
|
223057
|
+
} catch {
|
|
223058
|
+
}
|
|
223010
223059
|
this.lastArtifactHtml = fullHtml;
|
|
223011
223060
|
client.send({ type: "artifact_end" });
|
|
223012
223061
|
} catch (err) {
|
|
@@ -223140,8 +223189,8 @@ Modify the HTML to fulfill the user's request. Output the complete modified HTML
|
|
|
223140
223189
|
|
|
223141
223190
|
// src/core/main.ts
|
|
223142
223191
|
init_config();
|
|
223143
|
-
import { existsSync as
|
|
223144
|
-
import { dirname as dirname7, join as
|
|
223192
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23 } from "node:fs";
|
|
223193
|
+
import { dirname as dirname7, join as join31, resolve as resolve11 } from "node:path";
|
|
223145
223194
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
223146
223195
|
import { randomBytes } from "node:crypto";
|
|
223147
223196
|
|
|
@@ -224143,13 +224192,13 @@ var CheckpointManager = class {
|
|
|
224143
224192
|
return this.baseCommit;
|
|
224144
224193
|
}
|
|
224145
224194
|
/** Save a checkpoint of the file before modification. */
|
|
224146
|
-
save(
|
|
224147
|
-
const fileExists4 = existsSync7(
|
|
224148
|
-
const content = fileExists4 ? readFileSync6(
|
|
224149
|
-
this.store.delete(
|
|
224195
|
+
save(filePath2, writerType) {
|
|
224196
|
+
const fileExists4 = existsSync7(filePath2);
|
|
224197
|
+
const content = fileExists4 ? readFileSync6(filePath2) : null;
|
|
224198
|
+
this.store.delete(filePath2);
|
|
224150
224199
|
this.store.save(
|
|
224151
224200
|
{
|
|
224152
|
-
filePath,
|
|
224201
|
+
filePath: filePath2,
|
|
224153
224202
|
baseCommit: this.baseCommit,
|
|
224154
224203
|
writerType,
|
|
224155
224204
|
timestamp: Date.now(),
|
|
@@ -224160,31 +224209,31 @@ var CheckpointManager = class {
|
|
|
224160
224209
|
);
|
|
224161
224210
|
}
|
|
224162
224211
|
/** Restore file from its checkpoint and remove the checkpoint. */
|
|
224163
|
-
rollback(
|
|
224164
|
-
const entry = this.store.load(
|
|
224212
|
+
rollback(filePath2) {
|
|
224213
|
+
const entry = this.store.load(filePath2);
|
|
224165
224214
|
if (!entry) {
|
|
224166
|
-
throw new Error(`No checkpoint found for ${
|
|
224215
|
+
throw new Error(`No checkpoint found for ${filePath2}`);
|
|
224167
224216
|
}
|
|
224168
224217
|
if (entry.content !== null) {
|
|
224169
|
-
const parentDir = dirname(
|
|
224218
|
+
const parentDir = dirname(filePath2);
|
|
224170
224219
|
if (!existsSync7(parentDir)) {
|
|
224171
224220
|
mkdirSync6(parentDir, { recursive: true });
|
|
224172
224221
|
}
|
|
224173
|
-
writeFileSync6(
|
|
224222
|
+
writeFileSync6(filePath2, entry.content);
|
|
224174
224223
|
} else {
|
|
224175
|
-
if (existsSync7(
|
|
224176
|
-
unlinkSync2(
|
|
224224
|
+
if (existsSync7(filePath2)) {
|
|
224225
|
+
unlinkSync2(filePath2);
|
|
224177
224226
|
}
|
|
224178
224227
|
}
|
|
224179
|
-
this.store.delete(
|
|
224228
|
+
this.store.delete(filePath2);
|
|
224180
224229
|
}
|
|
224181
224230
|
/** Commit (remove) the checkpoint after a successful write. */
|
|
224182
|
-
commit(
|
|
224183
|
-
this.store.delete(
|
|
224231
|
+
commit(filePath2) {
|
|
224232
|
+
this.store.delete(filePath2);
|
|
224184
224233
|
}
|
|
224185
224234
|
/** Check if a file has an uncommitted checkpoint. */
|
|
224186
|
-
isDirty(
|
|
224187
|
-
return this.store.load(
|
|
224235
|
+
isDirty(filePath2) {
|
|
224236
|
+
return this.store.load(filePath2) !== null;
|
|
224188
224237
|
}
|
|
224189
224238
|
/** List all file paths with uncommitted checkpoints. */
|
|
224190
224239
|
listDirty() {
|
|
@@ -224199,20 +224248,20 @@ var CheckpointManager = class {
|
|
|
224199
224248
|
// src/checkpoint/write-tracker.ts
|
|
224200
224249
|
var FileWriteTracker = class {
|
|
224201
224250
|
writers = /* @__PURE__ */ new Map();
|
|
224202
|
-
recordWrite(
|
|
224203
|
-
this.writers.set(
|
|
224251
|
+
recordWrite(filePath2, writerType) {
|
|
224252
|
+
this.writers.set(filePath2, writerType);
|
|
224204
224253
|
}
|
|
224205
|
-
getWriter(
|
|
224206
|
-
return this.writers.get(
|
|
224254
|
+
getWriter(filePath2) {
|
|
224255
|
+
return this.writers.get(filePath2) ?? null;
|
|
224207
224256
|
}
|
|
224208
|
-
getContinuity(
|
|
224209
|
-
const prev = this.writers.get(
|
|
224257
|
+
getContinuity(filePath2, currentWriter) {
|
|
224258
|
+
const prev = this.writers.get(filePath2);
|
|
224210
224259
|
if (prev === void 0 || prev === currentWriter) return "clean";
|
|
224211
224260
|
return "mixed";
|
|
224212
224261
|
}
|
|
224213
224262
|
/** Mark a file as having been written by bash (external/black-box writer). */
|
|
224214
|
-
markExternalWrite(
|
|
224215
|
-
this.writers.set(
|
|
224263
|
+
markExternalWrite(filePath2) {
|
|
224264
|
+
this.writers.set(filePath2, "bash");
|
|
224216
224265
|
return { anchorInvalidated: true };
|
|
224217
224266
|
}
|
|
224218
224267
|
};
|
|
@@ -224226,11 +224275,11 @@ var FileSystemCheckpointStore = class {
|
|
|
224226
224275
|
this.baseDir = baseDir;
|
|
224227
224276
|
mkdirSync7(this.baseDir, { recursive: true });
|
|
224228
224277
|
}
|
|
224229
|
-
safeName(
|
|
224230
|
-
return
|
|
224278
|
+
safeName(filePath2) {
|
|
224279
|
+
return filePath2.replace(/[\/\\:]/g, "_").replace(/^_+/, "");
|
|
224231
224280
|
}
|
|
224232
|
-
findCheckpointDir(
|
|
224233
|
-
const prefix = this.safeName(
|
|
224281
|
+
findCheckpointDir(filePath2) {
|
|
224282
|
+
const prefix = this.safeName(filePath2) + "-";
|
|
224234
224283
|
if (!existsSync8(this.baseDir)) return null;
|
|
224235
224284
|
let entries;
|
|
224236
224285
|
try {
|
|
@@ -224258,8 +224307,8 @@ var FileSystemCheckpointStore = class {
|
|
|
224258
224307
|
writeFileSync7(join7(dir, "original"), content);
|
|
224259
224308
|
}
|
|
224260
224309
|
}
|
|
224261
|
-
load(
|
|
224262
|
-
const dir = this.findCheckpointDir(
|
|
224310
|
+
load(filePath2) {
|
|
224311
|
+
const dir = this.findCheckpointDir(filePath2);
|
|
224263
224312
|
if (!dir) return null;
|
|
224264
224313
|
const metaPath = join7(dir, "meta.json");
|
|
224265
224314
|
const originalPath = join7(dir, "original");
|
|
@@ -224267,8 +224316,8 @@ var FileSystemCheckpointStore = class {
|
|
|
224267
224316
|
const content = existsSync8(originalPath) ? readFileSync7(originalPath) : null;
|
|
224268
224317
|
return { meta, content };
|
|
224269
224318
|
}
|
|
224270
|
-
delete(
|
|
224271
|
-
const dir = this.findCheckpointDir(
|
|
224319
|
+
delete(filePath2) {
|
|
224320
|
+
const dir = this.findCheckpointDir(filePath2);
|
|
224272
224321
|
if (dir) {
|
|
224273
224322
|
rmSync(dir, { recursive: true, force: true });
|
|
224274
224323
|
}
|
|
@@ -224321,27 +224370,27 @@ var SnapshotStore = class {
|
|
|
224321
224370
|
* Record a snapshot of a file. Called after read_file returns hashed content
|
|
224322
224371
|
* (so the model receives the file_version and can use it for later edits).
|
|
224323
224372
|
*/
|
|
224324
|
-
record(
|
|
224325
|
-
const key = this.makeKey(
|
|
224373
|
+
record(filePath2, fileVersion, content) {
|
|
224374
|
+
const key = this.makeKey(filePath2, fileVersion);
|
|
224326
224375
|
const existing = this.lruKeys.indexOf(key);
|
|
224327
224376
|
if (existing >= 0) {
|
|
224328
224377
|
this.lruKeys.splice(existing, 1);
|
|
224329
224378
|
this.lruKeys.push(key);
|
|
224330
|
-
const entries2 = this.byFile.get(
|
|
224379
|
+
const entries2 = this.byFile.get(filePath2);
|
|
224331
224380
|
const entry2 = entries2.find((e) => e.fileVersion === fileVersion);
|
|
224332
224381
|
if (entry2) entry2.timestamp = Date.now();
|
|
224333
224382
|
return;
|
|
224334
224383
|
}
|
|
224335
224384
|
const entry = {
|
|
224336
|
-
filePath,
|
|
224385
|
+
filePath: filePath2,
|
|
224337
224386
|
fileVersion,
|
|
224338
224387
|
content,
|
|
224339
224388
|
timestamp: Date.now()
|
|
224340
224389
|
};
|
|
224341
|
-
let entries = this.byFile.get(
|
|
224390
|
+
let entries = this.byFile.get(filePath2);
|
|
224342
224391
|
if (!entries) {
|
|
224343
224392
|
entries = [];
|
|
224344
|
-
this.byFile.set(
|
|
224393
|
+
this.byFile.set(filePath2, entries);
|
|
224345
224394
|
}
|
|
224346
224395
|
entries.unshift(entry);
|
|
224347
224396
|
while (entries.length > this.maxSnapshotsPerFile) {
|
|
@@ -224364,12 +224413,12 @@ var SnapshotStore = class {
|
|
|
224364
224413
|
* Look up a snapshot by file path and version.
|
|
224365
224414
|
* Returns the full file content or null if not found.
|
|
224366
224415
|
*/
|
|
224367
|
-
lookup(
|
|
224368
|
-
const entries = this.byFile.get(
|
|
224416
|
+
lookup(filePath2, fileVersion) {
|
|
224417
|
+
const entries = this.byFile.get(filePath2);
|
|
224369
224418
|
if (!entries) return null;
|
|
224370
224419
|
const entry = entries.find((e) => e.fileVersion === fileVersion);
|
|
224371
224420
|
if (!entry) return null;
|
|
224372
|
-
const key = this.makeKey(
|
|
224421
|
+
const key = this.makeKey(filePath2, fileVersion);
|
|
224373
224422
|
const idx = this.lruKeys.indexOf(key);
|
|
224374
224423
|
if (idx >= 0) {
|
|
224375
224424
|
this.lruKeys.splice(idx, 1);
|
|
@@ -224381,13 +224430,13 @@ var SnapshotStore = class {
|
|
|
224381
224430
|
/**
|
|
224382
224431
|
* Remove all snapshots for a file (called after successful write_file / overwrite_file).
|
|
224383
224432
|
*/
|
|
224384
|
-
invalidate(
|
|
224385
|
-
const entries = this.byFile.get(
|
|
224433
|
+
invalidate(filePath2) {
|
|
224434
|
+
const entries = this.byFile.get(filePath2);
|
|
224386
224435
|
if (!entries) return;
|
|
224387
224436
|
for (const e of entries) {
|
|
224388
224437
|
this.removeFromLru(this.makeKey(e.filePath, e.fileVersion));
|
|
224389
224438
|
}
|
|
224390
|
-
this.byFile.delete(
|
|
224439
|
+
this.byFile.delete(filePath2);
|
|
224391
224440
|
}
|
|
224392
224441
|
/** Remove all snapshots. */
|
|
224393
224442
|
clear() {
|
|
@@ -224399,8 +224448,8 @@ var SnapshotStore = class {
|
|
|
224399
224448
|
return this.lruKeys.length;
|
|
224400
224449
|
}
|
|
224401
224450
|
// --- Private helpers ---
|
|
224402
|
-
makeKey(
|
|
224403
|
-
return `${
|
|
224451
|
+
makeKey(filePath2, fileVersion) {
|
|
224452
|
+
return `${filePath2}::${fileVersion}`;
|
|
224404
224453
|
}
|
|
224405
224454
|
parseKey(key) {
|
|
224406
224455
|
const idx = key.lastIndexOf("::");
|
|
@@ -225506,17 +225555,17 @@ function buildDiffPreview(snapshotLines, expectedLines, currentLines, patch) {
|
|
|
225506
225555
|
|
|
225507
225556
|
// src/drivers/edit/undo-store.ts
|
|
225508
225557
|
var undoSnapshots = /* @__PURE__ */ new Map();
|
|
225509
|
-
function captureUndoSnapshot(
|
|
225510
|
-
undoSnapshots.set(
|
|
225558
|
+
function captureUndoSnapshot(filePath2, content) {
|
|
225559
|
+
undoSnapshots.set(filePath2, content);
|
|
225511
225560
|
}
|
|
225512
|
-
function getUndoSnapshot(
|
|
225513
|
-
return undoSnapshots.get(
|
|
225561
|
+
function getUndoSnapshot(filePath2) {
|
|
225562
|
+
return undoSnapshots.get(filePath2);
|
|
225514
225563
|
}
|
|
225515
|
-
function clearUndoSnapshot(
|
|
225516
|
-
undoSnapshots.delete(
|
|
225564
|
+
function clearUndoSnapshot(filePath2) {
|
|
225565
|
+
undoSnapshots.delete(filePath2);
|
|
225517
225566
|
}
|
|
225518
|
-
function hasUndoSnapshot(
|
|
225519
|
-
return undoSnapshots.has(
|
|
225567
|
+
function hasUndoSnapshot(filePath2) {
|
|
225568
|
+
return undoSnapshots.has(filePath2);
|
|
225520
225569
|
}
|
|
225521
225570
|
|
|
225522
225571
|
// src/drivers/edit/syntax-validate.ts
|
|
@@ -225530,11 +225579,11 @@ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
225530
225579
|
".html",
|
|
225531
225580
|
".json"
|
|
225532
225581
|
]);
|
|
225533
|
-
function isSyntaxCheckSupported(
|
|
225534
|
-
return SUPPORTED_EXTENSIONS.has(extname(
|
|
225582
|
+
function isSyntaxCheckSupported(filePath2) {
|
|
225583
|
+
return SUPPORTED_EXTENSIONS.has(extname(filePath2).toLowerCase());
|
|
225535
225584
|
}
|
|
225536
|
-
function getSyntaxTarget(
|
|
225537
|
-
const ext = extname(
|
|
225585
|
+
function getSyntaxTarget(filePath2) {
|
|
225586
|
+
const ext = extname(filePath2).toLowerCase();
|
|
225538
225587
|
switch (ext) {
|
|
225539
225588
|
case ".js":
|
|
225540
225589
|
return { kind: "js" };
|
|
@@ -225565,8 +225614,8 @@ async function getTypeScript() {
|
|
|
225565
225614
|
}
|
|
225566
225615
|
return _tsModule;
|
|
225567
225616
|
}
|
|
225568
|
-
async function validateSyntax(
|
|
225569
|
-
const target = getSyntaxTarget(
|
|
225617
|
+
async function validateSyntax(filePath2, content) {
|
|
225618
|
+
const target = getSyntaxTarget(filePath2);
|
|
225570
225619
|
if (!target) {
|
|
225571
225620
|
return { valid: true };
|
|
225572
225621
|
}
|
|
@@ -225910,7 +225959,7 @@ var editTool = {
|
|
|
225910
225959
|
};
|
|
225911
225960
|
}
|
|
225912
225961
|
if (file_path && !path) {
|
|
225913
|
-
_editLogger.warn("
|
|
225962
|
+
_editLogger.warn("Edit", "file_path is deprecated, use path instead");
|
|
225914
225963
|
}
|
|
225915
225964
|
const resolved = resolve4(effectivePath);
|
|
225916
225965
|
if (!await fileExists3(resolved)) {
|
|
@@ -226838,10 +226887,10 @@ function stripBomAndDecode(buf) {
|
|
|
226838
226887
|
}
|
|
226839
226888
|
return buf.toString("utf8");
|
|
226840
226889
|
}
|
|
226841
|
-
function parseSkillManifest(
|
|
226890
|
+
function parseSkillManifest(filePath2, source) {
|
|
226842
226891
|
let raw;
|
|
226843
226892
|
try {
|
|
226844
|
-
const buf = readFileSync9(
|
|
226893
|
+
const buf = readFileSync9(filePath2);
|
|
226845
226894
|
raw = stripBomAndDecode(buf);
|
|
226846
226895
|
} catch {
|
|
226847
226896
|
return null;
|
|
@@ -226858,7 +226907,7 @@ function parseSkillManifest(filePath, source) {
|
|
|
226858
226907
|
tools: parsed.tools,
|
|
226859
226908
|
instructions: body || void 0,
|
|
226860
226909
|
source,
|
|
226861
|
-
path:
|
|
226910
|
+
path: filePath2
|
|
226862
226911
|
};
|
|
226863
226912
|
}
|
|
226864
226913
|
function parseFrontmatter(text) {
|
|
@@ -227153,10 +227202,10 @@ function stripBomAndDecode2(buf) {
|
|
|
227153
227202
|
function normalizeName(name) {
|
|
227154
227203
|
return name.toLowerCase().replace(/\s+/g, "");
|
|
227155
227204
|
}
|
|
227156
|
-
function parseCommandFile(
|
|
227205
|
+
function parseCommandFile(filePath2, source, derivedName) {
|
|
227157
227206
|
let raw;
|
|
227158
227207
|
try {
|
|
227159
|
-
const buf = readFileSync10(
|
|
227208
|
+
const buf = readFileSync10(filePath2);
|
|
227160
227209
|
raw = stripBomAndDecode2(buf);
|
|
227161
227210
|
} catch {
|
|
227162
227211
|
return null;
|
|
@@ -227170,7 +227219,7 @@ function parseCommandFile(filePath, source, derivedName) {
|
|
|
227170
227219
|
if (!parsed.description) return null;
|
|
227171
227220
|
if (parsed.name !== void 0 && normalizeName(parsed.name) !== normalizeName(derivedName)) {
|
|
227172
227221
|
console.warn(
|
|
227173
|
-
`[commands] Skipping ${
|
|
227222
|
+
`[commands] Skipping ${filePath2}: frontmatter name "${parsed.name}" does not match path-derived name "${derivedName}"`
|
|
227174
227223
|
);
|
|
227175
227224
|
return null;
|
|
227176
227225
|
}
|
|
@@ -227179,7 +227228,7 @@ function parseCommandFile(filePath, source, derivedName) {
|
|
|
227179
227228
|
description: parsed.description,
|
|
227180
227229
|
body,
|
|
227181
227230
|
source,
|
|
227182
|
-
path:
|
|
227231
|
+
path: filePath2
|
|
227183
227232
|
};
|
|
227184
227233
|
}
|
|
227185
227234
|
function parseFrontmatter2(text) {
|
|
@@ -227373,10 +227422,10 @@ var PermissionManager = class {
|
|
|
227373
227422
|
const toolName = context.toolCall.name;
|
|
227374
227423
|
const argsStr = JSON.stringify(context.args);
|
|
227375
227424
|
if ((toolName === "read_file" || toolName === "write_file") && this.denyRegexes.length > 0) {
|
|
227376
|
-
const
|
|
227377
|
-
if (
|
|
227425
|
+
const filePath2 = context.args?.path;
|
|
227426
|
+
if (filePath2) {
|
|
227378
227427
|
for (const { pattern, regex } of this.denyRegexes) {
|
|
227379
|
-
if (regex.test(
|
|
227428
|
+
if (regex.test(filePath2)) {
|
|
227380
227429
|
return { block: true, reason: `Denied by file pattern: ${pattern}` };
|
|
227381
227430
|
}
|
|
227382
227431
|
}
|
|
@@ -227788,6 +227837,7 @@ var MCPClient = class {
|
|
|
227788
227837
|
if (this.closing) return;
|
|
227789
227838
|
if (!this.closed) {
|
|
227790
227839
|
this.closed = true;
|
|
227840
|
+
this.emit({ type: "disconnected", serverName: this.config.name, reason: `MCP server "${this.config.name}" exited with code ${code}` });
|
|
227791
227841
|
setImmediate(() => {
|
|
227792
227842
|
const stderr = stderrBuf.trim().slice(0, 500);
|
|
227793
227843
|
const detail = stderr ? `: ${stderr}` : "";
|
|
@@ -227795,6 +227845,14 @@ var MCPClient = class {
|
|
|
227795
227845
|
});
|
|
227796
227846
|
}
|
|
227797
227847
|
});
|
|
227848
|
+
this.process.on("error", (err) => {
|
|
227849
|
+
if (this.closing) return;
|
|
227850
|
+
if (!this.closed) {
|
|
227851
|
+
this.closed = true;
|
|
227852
|
+
this.emit({ type: "disconnected", serverName: this.config.name, reason: `MCP server "${this.config.name}" error: ${err.message}` });
|
|
227853
|
+
this.rejectAllPending(new Error(`MCP server "${this.config.name}" error: ${err.message}`));
|
|
227854
|
+
}
|
|
227855
|
+
});
|
|
227798
227856
|
this.process.on("error", (err) => {
|
|
227799
227857
|
if (this.closing) return;
|
|
227800
227858
|
if (!this.closed) {
|
|
@@ -227867,11 +227925,18 @@ var MCPClient = class {
|
|
|
227867
227925
|
res.on("end", () => {
|
|
227868
227926
|
if (!this.closed) {
|
|
227869
227927
|
this.closed = true;
|
|
227928
|
+
this.emit({ type: "disconnected", serverName: this.config.name, reason: `MCP server "${this.config.name}" SSE connection closed` });
|
|
227870
227929
|
this.rejectAllPending(new Error(`MCP server "${this.config.name}" SSE connection closed`));
|
|
227871
227930
|
}
|
|
227872
227931
|
});
|
|
227873
227932
|
res.on("error", (err) => {
|
|
227874
|
-
|
|
227933
|
+
if (!this.closed) {
|
|
227934
|
+
this.closed = true;
|
|
227935
|
+
this.emit({ type: "disconnected", serverName: this.config.name, reason: `MCP server "${this.config.name}" SSE error: ${err.message}` });
|
|
227936
|
+
this.rejectAllPending(new Error(`MCP server "${this.config.name}" SSE error: ${err.message}`));
|
|
227937
|
+
} else {
|
|
227938
|
+
reject(new Error(`MCP server "${this.config.name}" SSE error: ${err.message}`));
|
|
227939
|
+
}
|
|
227875
227940
|
});
|
|
227876
227941
|
}
|
|
227877
227942
|
);
|
|
@@ -228099,7 +228164,7 @@ var MCPClient = class {
|
|
|
228099
228164
|
return;
|
|
228100
228165
|
}
|
|
228101
228166
|
if (this.resolvedTransport === "streamable-http") {
|
|
228102
|
-
this.
|
|
228167
|
+
this.sendHttpWithSessionRecovery(this.config.url, { jsonrpc: "2.0", id, method, params: finalParams }, id).then((response) => {
|
|
228103
228168
|
const entry2 = this.pending.get(id);
|
|
228104
228169
|
if (!entry2) return;
|
|
228105
228170
|
if (response.statusCode >= 400) {
|
|
@@ -228285,6 +228350,30 @@ var MCPClient = class {
|
|
|
228285
228350
|
}
|
|
228286
228351
|
return headers;
|
|
228287
228352
|
}
|
|
228353
|
+
async sendHttpWithSessionRecovery(url, payload, id) {
|
|
228354
|
+
const response = await this.sendHttpMessage(url, payload, true, true);
|
|
228355
|
+
const newSessionId = this.getHeader(response.headers, "mcp-session-id");
|
|
228356
|
+
if (newSessionId && newSessionId !== this.sessionId) {
|
|
228357
|
+
this.sessionId = newSessionId;
|
|
228358
|
+
}
|
|
228359
|
+
const isSessionExpired = (response.statusCode === 404 || response.statusCode === 410) && !this.getHeader(response.headers, "mcp-session-id");
|
|
228360
|
+
if (isSessionExpired && !this.closed) {
|
|
228361
|
+
try {
|
|
228362
|
+
await this.connectStreamableHttp();
|
|
228363
|
+
const retryResponse = await this.sendHttpMessage(url, payload, true, true);
|
|
228364
|
+
const retrySessionId = this.getHeader(retryResponse.headers, "mcp-session-id");
|
|
228365
|
+
if (retrySessionId) {
|
|
228366
|
+
this.sessionId = retrySessionId;
|
|
228367
|
+
}
|
|
228368
|
+
return retryResponse;
|
|
228369
|
+
} catch (reinitErr) {
|
|
228370
|
+
this.closed = true;
|
|
228371
|
+
this.emit({ type: "disconnected", serverName: this.config.name, reason: `MCP session recovery failed: ${reinitErr.message}` });
|
|
228372
|
+
throw reinitErr;
|
|
228373
|
+
}
|
|
228374
|
+
}
|
|
228375
|
+
return response;
|
|
228376
|
+
}
|
|
228288
228377
|
async sendHttpMessage(url, payload, isRequest, includeContentType) {
|
|
228289
228378
|
const parsed = new URL(url);
|
|
228290
228379
|
const requester = parsed.protocol === "https:" ? httpsRequest : httpRequest;
|
|
@@ -228462,6 +228551,20 @@ function normalizeHtmlMimeType(mimeType) {
|
|
|
228462
228551
|
if (!mimeType) return "";
|
|
228463
228552
|
return mimeType.split(";").map((part) => part.trim()).sort().join(";");
|
|
228464
228553
|
}
|
|
228554
|
+
function classifyError(err, transport, statusCode) {
|
|
228555
|
+
const msg = err.message ?? "";
|
|
228556
|
+
if (/ECONNREFUSED|ETIMEDOUT/i.test(msg)) return "transient";
|
|
228557
|
+
if (statusCode !== void 0) {
|
|
228558
|
+
if (statusCode === 502 || statusCode === 503 || statusCode === 504) return "transient";
|
|
228559
|
+
if (statusCode === 401 || statusCode === 403) return "permanent";
|
|
228560
|
+
if (statusCode === 404 || statusCode === 410) return "session_expired";
|
|
228561
|
+
}
|
|
228562
|
+
if (/ENOTFOUND/i.test(msg)) return "permanent";
|
|
228563
|
+
if (transport === "stdio" && /exited/i.test(msg)) return "transient";
|
|
228564
|
+
if (transport === "sse" && /connection closed/i.test(msg)) return "transient";
|
|
228565
|
+
if (/invalid|no command|no url/i.test(msg)) return "permanent";
|
|
228566
|
+
return "transient";
|
|
228567
|
+
}
|
|
228465
228568
|
var MCPManager = class {
|
|
228466
228569
|
constructor(configs) {
|
|
228467
228570
|
this.configs = configs;
|
|
@@ -228587,37 +228690,66 @@ var MCPManager = class {
|
|
|
228587
228690
|
if (this.driverRegistry) {
|
|
228588
228691
|
this.driverRegistry.unregister(mcpDriverName(name));
|
|
228589
228692
|
}
|
|
228590
|
-
state.status = "
|
|
228591
|
-
|
|
228592
|
-
|
|
228593
|
-
|
|
228594
|
-
|
|
228595
|
-
|
|
228596
|
-
|
|
228597
|
-
|
|
228598
|
-
|
|
228599
|
-
|
|
228600
|
-
|
|
228601
|
-
|
|
228602
|
-
|
|
228603
|
-
|
|
228604
|
-
|
|
228605
|
-
|
|
228606
|
-
|
|
228607
|
-
|
|
228608
|
-
|
|
228609
|
-
|
|
228610
|
-
|
|
228693
|
+
state.status = "reconnecting";
|
|
228694
|
+
const client = new MCPClient(cfg);
|
|
228695
|
+
client.onEvent((event) => this.handleClientEvent(event));
|
|
228696
|
+
await client.connect();
|
|
228697
|
+
this.clients.set(name, client);
|
|
228698
|
+
const tools = await client.listTools();
|
|
228699
|
+
this.registerDriver(name, tools);
|
|
228700
|
+
state.status = "connected";
|
|
228701
|
+
state.error = void 0;
|
|
228702
|
+
state.toolCount = tools.length;
|
|
228703
|
+
state.negotiatedProtocolVersion = client.getNegotiatedProtocolVersion() ?? void 0;
|
|
228704
|
+
state.resolvedTransport = client.getResolvedTransport();
|
|
228705
|
+
state.compatibilityMode = client.getCompatibilityMode();
|
|
228706
|
+
state.refreshState = "idle";
|
|
228707
|
+
state.refreshError = void 0;
|
|
228708
|
+
state.lastRefreshAt = Date.now();
|
|
228709
|
+
return true;
|
|
228710
|
+
}
|
|
228711
|
+
reconnectTimers = /* @__PURE__ */ new Map();
|
|
228712
|
+
scheduleReconnect(name, attempt) {
|
|
228713
|
+
const state = this.states.get(name);
|
|
228714
|
+
if (!state) return;
|
|
228715
|
+
if (state.status === "disconnected") return;
|
|
228716
|
+
if (attempt >= 10) {
|
|
228717
|
+
state.status = "error";
|
|
228718
|
+
state.error = "Reconnect attempts exhausted";
|
|
228719
|
+
state.refreshState = "error";
|
|
228720
|
+
state.refreshError = "Reconnect attempts exhausted";
|
|
228721
|
+
this.emit({ type: "tools_refresh_failed", serverName: name, error: "Reconnect attempts exhausted" });
|
|
228722
|
+
return;
|
|
228723
|
+
}
|
|
228724
|
+
state.status = "reconnecting";
|
|
228725
|
+
const delay = Math.min(3e4, 1e3 * Math.pow(2, attempt)) + Math.random() * 500;
|
|
228726
|
+
const timer = setTimeout(async () => {
|
|
228727
|
+
this.reconnectTimers.delete(name);
|
|
228728
|
+
try {
|
|
228611
228729
|
await this.reconnectServer(name);
|
|
228612
|
-
|
|
228613
|
-
|
|
228614
|
-
|
|
228615
|
-
|
|
228616
|
-
|
|
228730
|
+
state.refreshState = "idle";
|
|
228731
|
+
state.refreshError = void 0;
|
|
228732
|
+
this.emit({ type: "tools_refreshed", serverName: name, toolCount: state.toolCount });
|
|
228733
|
+
} catch (err) {
|
|
228734
|
+
const cfg = this.configs.find((c2) => c2.name === name);
|
|
228735
|
+
const errorClass = classifyError(err, cfg?.transport ?? "stdio");
|
|
228736
|
+
if (errorClass === "permanent" || errorClass === "session_expired") {
|
|
228737
|
+
if (errorClass === "session_expired") {
|
|
228738
|
+
this.scheduleReconnect(name, 0);
|
|
228739
|
+
return;
|
|
228740
|
+
}
|
|
228741
|
+
state.status = "error";
|
|
228742
|
+
state.error = err.message ?? "Unknown error";
|
|
228743
|
+
state.refreshState = "error";
|
|
228744
|
+
state.refreshError = err.message ?? "Unknown error";
|
|
228745
|
+
state.toolCount = 0;
|
|
228746
|
+
this.emit({ type: "tools_refresh_failed", serverName: name, error: err.message ?? "Unknown error" });
|
|
228747
|
+
return;
|
|
228748
|
+
}
|
|
228749
|
+
this.scheduleReconnect(name, attempt + 1);
|
|
228617
228750
|
}
|
|
228618
|
-
|
|
228619
|
-
|
|
228620
|
-
}
|
|
228751
|
+
}, delay);
|
|
228752
|
+
this.reconnectTimers.set(name, timer);
|
|
228621
228753
|
}
|
|
228622
228754
|
async registerDrivers(registry) {
|
|
228623
228755
|
this.driverRegistry = registry;
|
|
@@ -228633,7 +228765,7 @@ var MCPManager = class {
|
|
|
228633
228765
|
} catch (err) {
|
|
228634
228766
|
const state = this.states.get(name);
|
|
228635
228767
|
if (state.status === "connected" || state.status === "error") {
|
|
228636
|
-
|
|
228768
|
+
this.scheduleReconnect(name, 0);
|
|
228637
228769
|
} else {
|
|
228638
228770
|
state.status = "error";
|
|
228639
228771
|
state.error = err.message ?? "Unknown error";
|
|
@@ -228659,6 +228791,10 @@ var MCPManager = class {
|
|
|
228659
228791
|
})
|
|
228660
228792
|
);
|
|
228661
228793
|
this.clients.clear();
|
|
228794
|
+
for (const timer of this.reconnectTimers.values()) {
|
|
228795
|
+
clearTimeout(timer);
|
|
228796
|
+
}
|
|
228797
|
+
this.reconnectTimers.clear();
|
|
228662
228798
|
}
|
|
228663
228799
|
async connectServer(name) {
|
|
228664
228800
|
const existing = this.clients.get(name);
|
|
@@ -228826,6 +228962,10 @@ var MCPManager = class {
|
|
|
228826
228962
|
if (event.type === "resources_list_changed") {
|
|
228827
228963
|
state.lastRefreshAt = Date.now();
|
|
228828
228964
|
}
|
|
228965
|
+
if (event.type === "disconnected") {
|
|
228966
|
+
state.status = "reconnecting";
|
|
228967
|
+
this.scheduleReconnect(event.serverName, 0);
|
|
228968
|
+
}
|
|
228829
228969
|
}
|
|
228830
228970
|
for (const listener of this.eventListeners) {
|
|
228831
228971
|
listener(event);
|
|
@@ -229592,9 +229732,9 @@ var ConversationView = class {
|
|
|
229592
229732
|
mkdirSync8(cacheDir, { recursive: true });
|
|
229593
229733
|
const ext = displayMimeType.split("/")[1] || "png";
|
|
229594
229734
|
const filename = `${Date.now()}.${ext}`;
|
|
229595
|
-
const
|
|
229596
|
-
writeFileSync9(
|
|
229597
|
-
this.pushText(c.dim(`[image: ${
|
|
229735
|
+
const filePath2 = join16(cacheDir, filename);
|
|
229736
|
+
writeFileSync9(filePath2, Buffer.from(displayData, "base64"));
|
|
229737
|
+
this.pushText(c.dim(`[image: ${filePath2}]`));
|
|
229598
229738
|
if (format !== "webp") {
|
|
229599
229739
|
try {
|
|
229600
229740
|
const img = new Image(displayData, displayMimeType, this.imageTheme, {
|
|
@@ -230013,6 +230153,13 @@ var FileTracker = class {
|
|
|
230013
230153
|
getDisplayPaths() {
|
|
230014
230154
|
return [...this.entries.values()];
|
|
230015
230155
|
}
|
|
230156
|
+
/** Reverse lookup: return the absolute path for a given display path, or undefined. */
|
|
230157
|
+
getAbsPath(displayPath) {
|
|
230158
|
+
for (const [absPath, dp] of this.entries) {
|
|
230159
|
+
if (dp === displayPath) return absPath;
|
|
230160
|
+
}
|
|
230161
|
+
return void 0;
|
|
230162
|
+
}
|
|
230016
230163
|
/** Clear all tracked files. */
|
|
230017
230164
|
clear() {
|
|
230018
230165
|
this.entries.clear();
|
|
@@ -230108,6 +230255,19 @@ function formatCost(total) {
|
|
|
230108
230255
|
if (total >= 0.01) return `$${total.toFixed(4)}`;
|
|
230109
230256
|
return `\xA2${(total * 100).toFixed(2)}`;
|
|
230110
230257
|
}
|
|
230258
|
+
function findFileMarkerAt(text, cursorLine, cursorCol) {
|
|
230259
|
+
const lines = text.split("\n");
|
|
230260
|
+
if (cursorLine < 0 || cursorLine >= lines.length) return void 0;
|
|
230261
|
+
const line = lines[cursorLine];
|
|
230262
|
+
const re = /\[file:([^\]]+)\]/g;
|
|
230263
|
+
let m;
|
|
230264
|
+
while ((m = re.exec(line)) !== null) {
|
|
230265
|
+
if (cursorCol >= m.index && cursorCol <= m.index + m[0].length) {
|
|
230266
|
+
return m[1];
|
|
230267
|
+
}
|
|
230268
|
+
}
|
|
230269
|
+
return void 0;
|
|
230270
|
+
}
|
|
230111
230271
|
var TuiApp = class {
|
|
230112
230272
|
deps;
|
|
230113
230273
|
terminal;
|
|
@@ -230152,6 +230312,8 @@ var TuiApp = class {
|
|
|
230152
230312
|
drainedSubmitImages = null;
|
|
230153
230313
|
// Pre-drained files: captured in input listener before Editor's onChange("") clears them
|
|
230154
230314
|
drainedSubmitFiles = null;
|
|
230315
|
+
// Absolute path shown when cursor is on a [file:xxx] placeholder
|
|
230316
|
+
hoveredFilePath = null;
|
|
230155
230317
|
lastPasteTime = 0;
|
|
230156
230318
|
// ── Kitty protocol multi-chunk buffer ──
|
|
230157
230319
|
// Kitty transmits large images in chunks. Accumulate base64 payloads here
|
|
@@ -230220,6 +230382,14 @@ var TuiApp = class {
|
|
|
230220
230382
|
}
|
|
230221
230383
|
}
|
|
230222
230384
|
}
|
|
230385
|
+
const cursor = this.editor.getCursor();
|
|
230386
|
+
const editorText = this.editor.getText();
|
|
230387
|
+
const hoveredDisplayPath = findFileMarkerAt(editorText, cursor.line, cursor.col);
|
|
230388
|
+
if (hoveredDisplayPath) {
|
|
230389
|
+
this.hoveredFilePath = this.fileTracker.getAbsPath(hoveredDisplayPath) ?? null;
|
|
230390
|
+
} else {
|
|
230391
|
+
this.hoveredFilePath = null;
|
|
230392
|
+
}
|
|
230223
230393
|
this.updateAttachmentBar();
|
|
230224
230394
|
};
|
|
230225
230395
|
this.tui.addInputListener((data) => {
|
|
@@ -230565,7 +230735,9 @@ var TuiApp = class {
|
|
|
230565
230735
|
const chipsLine = parts.join(" ");
|
|
230566
230736
|
const scrollHint = this.attachmentScrollOffset > 0 ? ` +${this.attachmentScrollOffset} more` : "";
|
|
230567
230737
|
const hintLine = c.dim(`Ctrl+Shift+\u2190 \u2192 scroll${scrollHint} \xB7 Esc clear all`);
|
|
230568
|
-
this.
|
|
230738
|
+
const hoverLine = this.hoveredFilePath ? c.dim(`
|
|
230739
|
+
Path: ${this.hoveredFilePath}`) : "";
|
|
230740
|
+
this.imageStatus.setText(`${chipsLine}${hoverLine}
|
|
230569
230741
|
${hintLine}`);
|
|
230570
230742
|
this.tui.requestRender(true);
|
|
230571
230743
|
}
|
|
@@ -231132,17 +231304,11 @@ ${hintLine}`);
|
|
|
231132
231304
|
if (hasFiles) {
|
|
231133
231305
|
const imageRefs = fileRefs.filter((f) => isImagePath(f));
|
|
231134
231306
|
const nonImageRefs = fileRefs.filter((f) => !isImagePath(f));
|
|
231135
|
-
|
|
231136
|
-
const pathLines = nonImageRefs.map((f) => `- \`${f}\``).join("\n");
|
|
231137
|
-
text = text ? `${text}
|
|
231138
|
-
|
|
231139
|
-
\u{1F4C1} Attached files:
|
|
231140
|
-
${pathLines}` : `\u{1F4C1} Attached files:
|
|
231141
|
-
${pathLines}`;
|
|
231142
|
-
}
|
|
231307
|
+
const promptFilePaths = nonImageRefs.length > 0 ? [...nonImageRefs] : [];
|
|
231143
231308
|
if (imageRefs.length > 0) {
|
|
231144
231309
|
const dedupedImageRefs = imageRefs.filter((f) => !atPathAbsPaths.has(f));
|
|
231145
231310
|
if (dedupedImageRefs.length > 0) {
|
|
231311
|
+
promptFilePaths.push(...dedupedImageRefs);
|
|
231146
231312
|
const refsResolved = resolveFileRefs(this.deps.config.projectPath, dedupedImageRefs, this.deps.config.atFile ?? {});
|
|
231147
231313
|
if (refsResolved.warnings.length > 0) {
|
|
231148
231314
|
for (const warn of refsResolved.warnings) {
|
|
@@ -231159,11 +231325,18 @@ ${pathLines}`;
|
|
|
231159
231325
|
}
|
|
231160
231326
|
}
|
|
231161
231327
|
}
|
|
231328
|
+
if (promptFilePaths.length > 0) {
|
|
231329
|
+
const pathLines = promptFilePaths.map((f) => `- \`${f}\``).join("\n");
|
|
231330
|
+
text = text ? `${text}
|
|
231331
|
+
|
|
231332
|
+
\u{1F4C1} Attached files:
|
|
231333
|
+
${pathLines}` : `\u{1F4C1} Attached files:
|
|
231334
|
+
${pathLines}`;
|
|
231335
|
+
}
|
|
231162
231336
|
}
|
|
231163
|
-
|
|
231164
|
-
this.
|
|
231165
|
-
|
|
231166
|
-
);
|
|
231337
|
+
this.conversation.addInfo(
|
|
231338
|
+
c.dim(`${resolveModel(this.deps.config.provider, this.deps.config.modelId).name} does not support image input natively \u2014 using vision model or OCR.`)
|
|
231339
|
+
);
|
|
231167
231340
|
const imageIndicator = images ? c.dim(`[${images.length} image(s) attached]`) : "";
|
|
231168
231341
|
const userMessage = hasText ? imageIndicator ? `${text}
|
|
231169
231342
|
${imageIndicator}` : text : imageIndicator;
|
|
@@ -231380,9 +231553,9 @@ async function ocrImages(images, signal) {
|
|
|
231380
231553
|
}
|
|
231381
231554
|
|
|
231382
231555
|
// src/drivers/vision/client.ts
|
|
231556
|
+
init_logger();
|
|
231383
231557
|
init_models();
|
|
231384
231558
|
init_models();
|
|
231385
|
-
init_logger();
|
|
231386
231559
|
var _clog = new Logger({ type: "harness", id: process.env.DSCODE_RUNTIME_ID ?? "vision-client" });
|
|
231387
231560
|
function resolveVisionModel(visionConfig, fallbackApiKey, onWarning) {
|
|
231388
231561
|
if (!visionConfig?.provider || !visionConfig?.model) return null;
|
|
@@ -231432,14 +231605,12 @@ async function describeImagesViaVisionModel(images, visionModel, apiKey, signal)
|
|
|
231432
231605
|
throw err;
|
|
231433
231606
|
}
|
|
231434
231607
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
231435
|
-
_clog.warn("
|
|
231608
|
+
_clog.warn("vision-client", `describeImages FAILED: ${errMsg}. images=${images.length}, totalBase64=${images.reduce((s, i) => s + (i.data?.length ?? 0), 0)}, img[0].mime=${images[0]?.mimeType ?? "?"}`);
|
|
231436
231609
|
throw err;
|
|
231437
231610
|
}
|
|
231438
231611
|
}
|
|
231439
231612
|
|
|
231440
231613
|
// src/drivers/vision/pipeline.ts
|
|
231441
|
-
init_logger();
|
|
231442
|
-
var _plog = new Logger({ type: "harness", id: process.env.DSCODE_RUNTIME_ID ?? "pipeline" });
|
|
231443
231614
|
var ImagePipeline = class {
|
|
231444
231615
|
visionConfig;
|
|
231445
231616
|
fallbackApiKey;
|
|
@@ -231472,7 +231643,6 @@ var ImagePipeline = class {
|
|
|
231472
231643
|
const compressedImages = compressedRaw.every((img) => img !== null) ? compressedRaw : normalizedImages;
|
|
231473
231644
|
if (signal?.aborted) throw new DOMException("The operation was aborted", "AbortError");
|
|
231474
231645
|
const vision = resolveVisionModel(this.visionConfig, this.fallbackApiKey, this.onWarning);
|
|
231475
|
-
_plog.info("tool", "image-pipeline", `vision resolved: ${vision ? `${vision.model.provider}/${vision.model.id}` : "null \u2014 falling to OCR"}, images=${normalizedImages.length}, img[0].dataLen=${normalizedImages[0]?.data?.length ?? 0}, mime=${normalizedImages[0]?.mimeType ?? "?"}`);
|
|
231476
231646
|
if (vision) {
|
|
231477
231647
|
try {
|
|
231478
231648
|
onProgress?.({ phase: "describing", cachedRefs });
|
|
@@ -231494,11 +231664,9 @@ ${description}
|
|
|
231494
231664
|
throw err;
|
|
231495
231665
|
}
|
|
231496
231666
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
231497
|
-
_plog.warn("tool", "image-pipeline", `vision FAILED: ${errMsg}. img[0].dataLen=${normalizedImages[0]?.data?.length ?? 0}, mime=${normalizedImages[0]?.mimeType ?? "?"}, preview=${normalizedImages[0]?.data?.slice(0, 80) ?? "?"}`);
|
|
231498
231667
|
this.onWarning(`Vision model failed: ${errMsg}. Falling back to OCR.`);
|
|
231499
231668
|
}
|
|
231500
231669
|
}
|
|
231501
|
-
_plog.info("tool", "image-pipeline", `entering OCR fallback, images=${normalizedImages.length}`);
|
|
231502
231670
|
if (signal?.aborted) throw new DOMException("The operation was aborted", "AbortError");
|
|
231503
231671
|
try {
|
|
231504
231672
|
onProgress?.({ phase: "ocr", cachedRefs });
|
|
@@ -231601,12 +231769,12 @@ var ConfigWatch = class {
|
|
|
231601
231769
|
|
|
231602
231770
|
// src/context/anchor-invalidation.ts
|
|
231603
231771
|
var pendingEvents = [];
|
|
231604
|
-
function recordInvalidation(
|
|
231605
|
-
const existing = pendingEvents.findIndex((e) => e.filePath ===
|
|
231772
|
+
function recordInvalidation(filePath2, lineCount, fileVersion) {
|
|
231773
|
+
const existing = pendingEvents.findIndex((e) => e.filePath === filePath2);
|
|
231606
231774
|
if (existing >= 0) {
|
|
231607
|
-
pendingEvents[existing] = { filePath, lineCount, fileVersion };
|
|
231775
|
+
pendingEvents[existing] = { filePath: filePath2, lineCount, fileVersion };
|
|
231608
231776
|
} else {
|
|
231609
|
-
pendingEvents.push({ filePath, lineCount, fileVersion });
|
|
231777
|
+
pendingEvents.push({ filePath: filePath2, lineCount, fileVersion });
|
|
231610
231778
|
}
|
|
231611
231779
|
}
|
|
231612
231780
|
function consumePendingNotices() {
|
|
@@ -231652,7 +231820,7 @@ var HarnessEventBus = class {
|
|
|
231652
231820
|
try {
|
|
231653
231821
|
handler(event);
|
|
231654
231822
|
} catch (err) {
|
|
231655
|
-
this.logger.error("
|
|
231823
|
+
this.logger.error("EventBus", `handler error for "${event.type}": ${String(err)}`);
|
|
231656
231824
|
}
|
|
231657
231825
|
}
|
|
231658
231826
|
}
|
|
@@ -231689,6 +231857,8 @@ var Harness = class {
|
|
|
231689
231857
|
shuttingDown = false;
|
|
231690
231858
|
turnIndex = 0;
|
|
231691
231859
|
visionAbortController = null;
|
|
231860
|
+
autoSaveTimer;
|
|
231861
|
+
lastSavedMessageCount = 0;
|
|
231692
231862
|
constructor(config, logger, debug) {
|
|
231693
231863
|
this.logger = logger;
|
|
231694
231864
|
this.configStore = new ConfigWatch(config);
|
|
@@ -231777,7 +231947,7 @@ var Harness = class {
|
|
|
231777
231947
|
await self.dumpDebugPrompt();
|
|
231778
231948
|
return self.contextManager.transform(msgs, signal);
|
|
231779
231949
|
} catch (err) {
|
|
231780
|
-
this.logger.error("
|
|
231950
|
+
this.logger.error("TransformContext", String(err));
|
|
231781
231951
|
return msgs;
|
|
231782
231952
|
}
|
|
231783
231953
|
},
|
|
@@ -231800,7 +231970,7 @@ var Harness = class {
|
|
|
231800
231970
|
}
|
|
231801
231971
|
}
|
|
231802
231972
|
} catch (err) {
|
|
231803
|
-
this.logger.error("
|
|
231973
|
+
this.logger.error("AfterToolCall", String(err));
|
|
231804
231974
|
}
|
|
231805
231975
|
if (_signal?.aborted) {
|
|
231806
231976
|
return { terminate: true };
|
|
@@ -231843,6 +232013,7 @@ var Harness = class {
|
|
|
231843
232013
|
const lastAssistantMsg = this.findLastAssistantMessage(msgs);
|
|
231844
232014
|
if (!lastAssistantMsg || lastAssistantMsg.stopReason !== "error") {
|
|
231845
232015
|
this.sessionManager.trySaveSession(this.agent);
|
|
232016
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
231846
232017
|
return;
|
|
231847
232018
|
}
|
|
231848
232019
|
const errorMsg = lastAssistantMsg.errorMessage ?? "Unknown model error";
|
|
@@ -231858,6 +232029,7 @@ var Harness = class {
|
|
|
231858
232029
|
this.events.emit({ type: "ui:error", text: `Model error: ${errorMsg}` });
|
|
231859
232030
|
this.events.emit({ type: "turn:error", error: errorMsg, attempt: attempt + 1, maxRetries });
|
|
231860
232031
|
this.sessionManager.trySaveSession(this.agent);
|
|
232032
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
231861
232033
|
return;
|
|
231862
232034
|
}
|
|
231863
232035
|
if (attempt >= maxRetries) {
|
|
@@ -231873,6 +232045,7 @@ var Harness = class {
|
|
|
231873
232045
|
this.events.emit({ type: "turn:error", error: errorMsg, attempt: attempt + 1, maxRetries });
|
|
231874
232046
|
this.events.emit({ type: "ui:error", text: "\u2717 All retries exhausted" });
|
|
231875
232047
|
this.sessionManager.trySaveSession(this.agent);
|
|
232048
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
231876
232049
|
return;
|
|
231877
232050
|
}
|
|
231878
232051
|
this.events.emit({
|
|
@@ -231891,6 +232064,24 @@ var Harness = class {
|
|
|
231891
232064
|
*/
|
|
231892
232065
|
saveSessionNow() {
|
|
231893
232066
|
this.sessionManager.trySaveSession(this.agent);
|
|
232067
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232068
|
+
}
|
|
232069
|
+
/**
|
|
232070
|
+
* Start periodic auto-save (every 15s) during agent execution.
|
|
232071
|
+
* Only saves when new messages have been added since last save.
|
|
232072
|
+
*/
|
|
232073
|
+
startAutoSave() {
|
|
232074
|
+
this.autoSaveTimer = setInterval(() => {
|
|
232075
|
+
if (this.agent?.state?.messages) {
|
|
232076
|
+
const currentCount = this.agent.state.messages.length;
|
|
232077
|
+
if (currentCount !== this.lastSavedMessageCount) {
|
|
232078
|
+
this.logger.info("AutoSave", `Periodic auto-save (${currentCount} messages, was ${this.lastSavedMessageCount})`);
|
|
232079
|
+
this.sessionManager.trySaveSession(this.agent);
|
|
232080
|
+
this.lastSavedMessageCount = currentCount;
|
|
232081
|
+
}
|
|
232082
|
+
}
|
|
232083
|
+
}, 15e3);
|
|
232084
|
+
this.autoSaveTimer.unref();
|
|
231894
232085
|
}
|
|
231895
232086
|
findLastUserMessageIndex(messages) {
|
|
231896
232087
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -232039,6 +232230,7 @@ var Harness = class {
|
|
|
232039
232230
|
}));
|
|
232040
232231
|
}
|
|
232041
232232
|
this.sessionManager.trySaveSession(this.agent);
|
|
232233
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232042
232234
|
const restoredImgs = [];
|
|
232043
232235
|
for (const ref of cachedRefs) {
|
|
232044
232236
|
const cached2 = ImageCache.getSync(ref);
|
|
@@ -232099,6 +232291,7 @@ var Harness = class {
|
|
|
232099
232291
|
this.toolRegistry.initialize(this.makeSkillTool());
|
|
232100
232292
|
this.agent.state.tools = this.toolRegistry.buildToolsForRequest();
|
|
232101
232293
|
}
|
|
232294
|
+
this.startAutoSave();
|
|
232102
232295
|
if (!this.config.apiKey) {
|
|
232103
232296
|
this.events.emit({ type: "ui:info", text: [
|
|
232104
232297
|
"Welcome to DSCode! To get started, configure your API key:",
|
|
@@ -232160,6 +232353,7 @@ var Harness = class {
|
|
|
232160
232353
|
return { success: false, error: `Path does not exist: ${resolvedPath}` };
|
|
232161
232354
|
}
|
|
232162
232355
|
this.sessionManager.trySaveSession(this.agent);
|
|
232356
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232163
232357
|
process.chdir(resolvedPath);
|
|
232164
232358
|
this.configStore.setProjectPath(resolvedPath);
|
|
232165
232359
|
this.sessionManager.updateProjectPath(this.config.dataDir, resolvedPath);
|
|
@@ -232193,7 +232387,7 @@ var Harness = class {
|
|
|
232193
232387
|
this.ui.setMcpManager?.(this.mcpManager);
|
|
232194
232388
|
this.ui.pushMcpState?.();
|
|
232195
232389
|
} catch (err) {
|
|
232196
|
-
this.logger.error("
|
|
232390
|
+
this.logger.error("McpReload", String(err));
|
|
232197
232391
|
}
|
|
232198
232392
|
this.agent.state.tools = this.toolRegistry.buildToolsForRequest();
|
|
232199
232393
|
const memories = this.memoryManager.getRelevantMemories();
|
|
@@ -232203,7 +232397,12 @@ var Harness = class {
|
|
|
232203
232397
|
return { success: true };
|
|
232204
232398
|
}
|
|
232205
232399
|
async shutdown() {
|
|
232400
|
+
if (this.autoSaveTimer) {
|
|
232401
|
+
clearInterval(this.autoSaveTimer);
|
|
232402
|
+
this.autoSaveTimer = void 0;
|
|
232403
|
+
}
|
|
232206
232404
|
this.sessionManager.trySaveSession(this.agent);
|
|
232405
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232207
232406
|
if (this.shuttingDown) return;
|
|
232208
232407
|
this.shuttingDown = true;
|
|
232209
232408
|
this.mcpEventUnsubscribe?.();
|
|
@@ -232216,14 +232415,14 @@ var Harness = class {
|
|
|
232216
232415
|
try {
|
|
232217
232416
|
await this.appHostManager.shutdown();
|
|
232218
232417
|
} catch (err) {
|
|
232219
|
-
this.logger.error("
|
|
232418
|
+
this.logger.error("AppHostShutdown", String(err));
|
|
232220
232419
|
}
|
|
232221
232420
|
}
|
|
232222
232421
|
if (this.mcpManager) {
|
|
232223
232422
|
try {
|
|
232224
232423
|
await this.mcpManager.shutdown();
|
|
232225
232424
|
} catch (err) {
|
|
232226
|
-
this.logger.error("
|
|
232425
|
+
this.logger.error("McpShutdown", String(err));
|
|
232227
232426
|
}
|
|
232228
232427
|
}
|
|
232229
232428
|
}
|
|
@@ -232315,13 +232514,13 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
232315
232514
|
const hash = String(prompt.length);
|
|
232316
232515
|
if (hash === this.debugPromptLastHash) return;
|
|
232317
232516
|
this.debugPromptLastHash = hash;
|
|
232318
|
-
const { mkdirSync: mkdirSync14, writeFileSync:
|
|
232319
|
-
const { join:
|
|
232320
|
-
const dumpDir =
|
|
232517
|
+
const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
232518
|
+
const { join: join32 } = await import("node:path");
|
|
232519
|
+
const dumpDir = join32(this.config.projectPath, "dump");
|
|
232321
232520
|
mkdirSync14(dumpDir, { recursive: true });
|
|
232322
|
-
const
|
|
232323
|
-
|
|
232324
|
-
process.stderr.write("\n[dscode] --debug: system prompt dumped to " +
|
|
232521
|
+
const filePath2 = join32(dumpDir, "system-prompt.md");
|
|
232522
|
+
writeFileSync16(filePath2, prompt, "utf8");
|
|
232523
|
+
process.stderr.write("\n[dscode] --debug: system prompt dumped to " + filePath2 + " (" + prompt.length + " chars)\n\n");
|
|
232325
232524
|
}
|
|
232326
232525
|
makeSkillTool() {
|
|
232327
232526
|
const skillManager = this.skillManager;
|
|
@@ -232457,6 +232656,14 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
232457
232656
|
bindEvents() {
|
|
232458
232657
|
this.agent.subscribe((event) => {
|
|
232459
232658
|
switch (event.type) {
|
|
232659
|
+
case "message_end": {
|
|
232660
|
+
if (event.message?.role === "user") {
|
|
232661
|
+
this.logger.info("PreTurnSave", `Saving session pre-turn (${this.agent.state.messages.length} messages)`);
|
|
232662
|
+
this.sessionManager.trySaveSession(this.agent);
|
|
232663
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232664
|
+
}
|
|
232665
|
+
break;
|
|
232666
|
+
}
|
|
232460
232667
|
case "message_update": {
|
|
232461
232668
|
const ev = event.assistantMessageEvent;
|
|
232462
232669
|
if (!ev) break;
|
|
@@ -232498,12 +232705,14 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
232498
232705
|
if (event.type === "agent_end") {
|
|
232499
232706
|
this.events.emit({ type: "processing:stop" });
|
|
232500
232707
|
this.sessionManager.trySaveSession(this.agent);
|
|
232708
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232501
232709
|
}
|
|
232502
232710
|
if (event.type === "agent_start") {
|
|
232503
232711
|
this.events.emit({ type: "turn:streaming:start" });
|
|
232504
232712
|
}
|
|
232505
232713
|
if (event.type === "turn_end") {
|
|
232506
232714
|
this.sessionManager.trySaveSession(this.agent);
|
|
232715
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232507
232716
|
const turnEndMsg = event.message;
|
|
232508
232717
|
const rawUsage = turnEndMsg?.usage;
|
|
232509
232718
|
this.events.emit({ type: "turn:end", stopReason: turnEndMsg?.stopReason, usage: rawUsage ? { input: rawUsage.input, output: rawUsage.output, cacheRead: rawUsage.cacheRead, cacheWrite: rawUsage.cacheWrite, total: rawUsage.totalTokens, cost: { total: rawUsage.cost.total } } : void 0 });
|
|
@@ -232515,8 +232724,9 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
232515
232724
|
}
|
|
232516
232725
|
}
|
|
232517
232726
|
} catch (err) {
|
|
232518
|
-
this.logger.error("
|
|
232727
|
+
this.logger.error("AgentEvent", String(err));
|
|
232519
232728
|
this.sessionManager.trySaveSession(this.agent);
|
|
232729
|
+
this.lastSavedMessageCount = this.agent.state.messages.length;
|
|
232520
232730
|
}
|
|
232521
232731
|
});
|
|
232522
232732
|
}
|
|
@@ -232611,6 +232821,132 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
232611
232821
|
|
|
232612
232822
|
// src/core/main.ts
|
|
232613
232823
|
init_logger();
|
|
232824
|
+
|
|
232825
|
+
// src/core/od-daemon.ts
|
|
232826
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
232827
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "node:fs";
|
|
232828
|
+
import { homedir as homedir10 } from "node:os";
|
|
232829
|
+
import { join as join29 } from "node:path";
|
|
232830
|
+
function findProjectOd(odDir) {
|
|
232831
|
+
const expandedDir = expandTilde2(odDir);
|
|
232832
|
+
const odPath = join29(expandedDir, "node_modules", ".bin", "od");
|
|
232833
|
+
if (existsSync24(odPath)) return odPath;
|
|
232834
|
+
return null;
|
|
232835
|
+
}
|
|
232836
|
+
function resolveOdCommand(odDir, port) {
|
|
232837
|
+
const expandedDir = expandTilde2(odDir);
|
|
232838
|
+
const odPath = findProjectOd(odDir);
|
|
232839
|
+
if (odPath) {
|
|
232840
|
+
return { cmd: odPath, args: ["--port", String(port), "--no-open"], cwd: expandedDir };
|
|
232841
|
+
}
|
|
232842
|
+
return { cmd: "pnpm", args: ["tools-dev", "run", "web", "--", "--port", String(port), "--no-open"], cwd: expandedDir };
|
|
232843
|
+
}
|
|
232844
|
+
function startOdDaemon(odDir, odPort) {
|
|
232845
|
+
const { cmd, args, cwd } = resolveOdCommand(odDir, odPort);
|
|
232846
|
+
const child = spawn2(cmd, args, {
|
|
232847
|
+
cwd,
|
|
232848
|
+
stdio: "ignore",
|
|
232849
|
+
env: { ...process.env, OD_PORT: String(odPort) }
|
|
232850
|
+
});
|
|
232851
|
+
child.unref();
|
|
232852
|
+
return child;
|
|
232853
|
+
}
|
|
232854
|
+
async function waitForOdDaemon(port, timeoutMs = 3e4) {
|
|
232855
|
+
const start = Date.now();
|
|
232856
|
+
while (Date.now() - start < timeoutMs) {
|
|
232857
|
+
try {
|
|
232858
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/projects`);
|
|
232859
|
+
if (res.status === 200) {
|
|
232860
|
+
console.log(`Open Design daemon ready on port ${port}`);
|
|
232861
|
+
return true;
|
|
232862
|
+
}
|
|
232863
|
+
} catch {
|
|
232864
|
+
}
|
|
232865
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
232866
|
+
}
|
|
232867
|
+
console.warn(`Open Design daemon did not become healthy within ${timeoutMs / 1e3}s`);
|
|
232868
|
+
return false;
|
|
232869
|
+
}
|
|
232870
|
+
var cleanupHandlers = [];
|
|
232871
|
+
function runOdCleanup() {
|
|
232872
|
+
for (const handler of cleanupHandlers) {
|
|
232873
|
+
handler();
|
|
232874
|
+
}
|
|
232875
|
+
cleanupHandlers = [];
|
|
232876
|
+
}
|
|
232877
|
+
var cleanupHooksInstalled = false;
|
|
232878
|
+
function installCleanupHooks() {
|
|
232879
|
+
if (cleanupHooksInstalled) return;
|
|
232880
|
+
cleanupHooksInstalled = true;
|
|
232881
|
+
process.on("exit", runOdCleanup);
|
|
232882
|
+
process.on("SIGINT", runOdCleanup);
|
|
232883
|
+
process.on("SIGTERM", runOdCleanup);
|
|
232884
|
+
}
|
|
232885
|
+
function registerOdCleanup(odChild) {
|
|
232886
|
+
installCleanupHooks();
|
|
232887
|
+
const handler = () => {
|
|
232888
|
+
if (odChild.exitCode !== null || odChild.signalCode !== null) return;
|
|
232889
|
+
odChild.kill("SIGTERM");
|
|
232890
|
+
const forceKill = setTimeout(() => {
|
|
232891
|
+
if (odChild.exitCode === null && odChild.signalCode === null) {
|
|
232892
|
+
odChild.kill("SIGKILL");
|
|
232893
|
+
}
|
|
232894
|
+
}, 3e3);
|
|
232895
|
+
forceKill.unref();
|
|
232896
|
+
};
|
|
232897
|
+
cleanupHandlers.push(handler);
|
|
232898
|
+
}
|
|
232899
|
+
function expandTilde2(filePath2) {
|
|
232900
|
+
if (filePath2.startsWith("~")) {
|
|
232901
|
+
return join29(homedir10(), filePath2.slice(1));
|
|
232902
|
+
}
|
|
232903
|
+
return filePath2;
|
|
232904
|
+
}
|
|
232905
|
+
var MCP_PATH = join29(homedir10(), ".mcp.json");
|
|
232906
|
+
function ensureOdMcpEntry(odDir, odPort) {
|
|
232907
|
+
const expandedDir = expandTilde2(odDir);
|
|
232908
|
+
const daemonCliPath = join29(expandedDir, "apps", "daemon", "src", "cli.ts");
|
|
232909
|
+
const daemonUrl = `http://127.0.0.1:${odPort}`;
|
|
232910
|
+
let mcpConfig;
|
|
232911
|
+
try {
|
|
232912
|
+
if (existsSync24(MCP_PATH)) {
|
|
232913
|
+
const raw = readFileSync21(MCP_PATH, "utf8");
|
|
232914
|
+
mcpConfig = JSON.parse(raw);
|
|
232915
|
+
} else {
|
|
232916
|
+
mcpConfig = {};
|
|
232917
|
+
}
|
|
232918
|
+
} catch (e) {
|
|
232919
|
+
if (existsSync24(MCP_PATH)) {
|
|
232920
|
+
console.warn(
|
|
232921
|
+
`Cannot read ~/.mcp.json: ${e instanceof Error ? e.message : String(e)}`
|
|
232922
|
+
);
|
|
232923
|
+
return false;
|
|
232924
|
+
}
|
|
232925
|
+
mcpConfig = {};
|
|
232926
|
+
}
|
|
232927
|
+
const servers = mcpConfig.mcpServers ?? {};
|
|
232928
|
+
const existing = servers["open-design"];
|
|
232929
|
+
if (existing?.args?.[1] === daemonCliPath && existing?.args?.[4] === daemonUrl) {
|
|
232930
|
+
return true;
|
|
232931
|
+
}
|
|
232932
|
+
servers["open-design"] = {
|
|
232933
|
+
command: "npx",
|
|
232934
|
+
args: ["tsx", daemonCliPath, "mcp", "--daemon-url", daemonUrl]
|
|
232935
|
+
};
|
|
232936
|
+
mcpConfig.mcpServers = servers;
|
|
232937
|
+
try {
|
|
232938
|
+
writeFileSync14(MCP_PATH, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
232939
|
+
console.log(`~/.mcp.json updated with open-design MCP entry`);
|
|
232940
|
+
return true;
|
|
232941
|
+
} catch (e) {
|
|
232942
|
+
console.warn(
|
|
232943
|
+
`Cannot write ~/.mcp.json: ${e instanceof Error ? e.message : String(e)}`
|
|
232944
|
+
);
|
|
232945
|
+
return false;
|
|
232946
|
+
}
|
|
232947
|
+
}
|
|
232948
|
+
|
|
232949
|
+
// src/core/main.ts
|
|
232614
232950
|
function generateRuntimeId() {
|
|
232615
232951
|
return "rt_" + randomBytes(4).toString("hex");
|
|
232616
232952
|
}
|
|
@@ -232627,12 +232963,12 @@ function emergencySaveSession() {
|
|
|
232627
232963
|
}
|
|
232628
232964
|
}
|
|
232629
232965
|
process.on("unhandledRejection", (reason) => {
|
|
232630
|
-
harnessLogger.error("
|
|
232966
|
+
harnessLogger.error("UnhandledRejection", String(reason));
|
|
232631
232967
|
emergencySaveSession();
|
|
232632
232968
|
});
|
|
232633
232969
|
process.on("uncaughtException", (err) => {
|
|
232634
232970
|
const msg = err instanceof Error ? err.message : String(err);
|
|
232635
|
-
harnessLogger.error("
|
|
232971
|
+
harnessLogger.error("UncaughtException", msg);
|
|
232636
232972
|
emergencySaveSession();
|
|
232637
232973
|
setTimeout(() => {
|
|
232638
232974
|
process.exit(1);
|
|
@@ -232642,28 +232978,28 @@ var sigintCount = 0;
|
|
|
232642
232978
|
process.on("SIGINT", () => {
|
|
232643
232979
|
sigintCount++;
|
|
232644
232980
|
if (sigintCount === 1) {
|
|
232645
|
-
harnessLogger.info("
|
|
232981
|
+
harnessLogger.info("SIGINT", "Shutting down... (press Ctrl+C again to force quit)");
|
|
232646
232982
|
emergencySaveSession();
|
|
232647
232983
|
} else {
|
|
232648
|
-
harnessLogger.info("
|
|
232984
|
+
harnessLogger.info("SIGINT", "Force quitting...");
|
|
232649
232985
|
emergencySaveSession();
|
|
232650
232986
|
process.exit(0);
|
|
232651
232987
|
}
|
|
232652
232988
|
});
|
|
232653
232989
|
process.on("SIGTERM", () => {
|
|
232654
|
-
harnessLogger.info("
|
|
232990
|
+
harnessLogger.info("SIGTERM", "Received SIGTERM, shutting down...");
|
|
232655
232991
|
emergencySaveSession();
|
|
232656
232992
|
process.exit(0);
|
|
232657
232993
|
});
|
|
232658
232994
|
function readCliVersion() {
|
|
232659
232995
|
const currentDir = dirname7(fileURLToPath4(import.meta.url));
|
|
232660
232996
|
const candidates = [
|
|
232661
|
-
|
|
232662
|
-
|
|
232997
|
+
join31(currentDir, "..", "package.json"),
|
|
232998
|
+
join31(currentDir, "..", "..", "package.json")
|
|
232663
232999
|
];
|
|
232664
233000
|
for (const candidate of candidates) {
|
|
232665
|
-
if (!
|
|
232666
|
-
const pkg = JSON.parse(
|
|
233001
|
+
if (!existsSync26(candidate)) continue;
|
|
233002
|
+
const pkg = JSON.parse(readFileSync23(candidate, "utf8"));
|
|
232667
233003
|
if (typeof pkg.version === "string" && pkg.version.trim() !== "") {
|
|
232668
233004
|
return pkg.version;
|
|
232669
233005
|
}
|
|
@@ -232676,11 +233012,14 @@ function parseArgs() {
|
|
|
232676
233012
|
let webPort = 3e3;
|
|
232677
233013
|
let debug = false;
|
|
232678
233014
|
let cwd;
|
|
233015
|
+
let withOd = false;
|
|
232679
233016
|
for (let i = 0; i < args.length; i++) {
|
|
232680
233017
|
if (args[i] === "--web") {
|
|
232681
233018
|
web = true;
|
|
232682
233019
|
} else if (args[i] === "--debug") {
|
|
232683
233020
|
debug = true;
|
|
233021
|
+
} else if (args[i] === "--with-od") {
|
|
233022
|
+
withOd = true;
|
|
232684
233023
|
} else if (args[i] === "--web-port" && i + 1 < args.length) {
|
|
232685
233024
|
webPort = parseInt(args[++i], 10);
|
|
232686
233025
|
if (isNaN(webPort) || webPort < 1 || webPort > 65535) {
|
|
@@ -232690,15 +233029,91 @@ function parseArgs() {
|
|
|
232690
233029
|
cwd = resolve11(args[++i]);
|
|
232691
233030
|
}
|
|
232692
233031
|
}
|
|
232693
|
-
return { web, webPort, debug, cwd };
|
|
233032
|
+
return { web, webPort, debug, cwd, withOd };
|
|
232694
233033
|
}
|
|
232695
233034
|
async function main() {
|
|
232696
233035
|
if (process.argv.slice(2).some((arg) => arg === "--version" || arg === "-v")) {
|
|
232697
233036
|
console.log(readCliVersion());
|
|
232698
233037
|
return;
|
|
232699
233038
|
}
|
|
232700
|
-
const { web, webPort, debug, cwd } = parseArgs();
|
|
233039
|
+
const { web, webPort, debug, cwd, withOd } = parseArgs();
|
|
232701
233040
|
const projectRoot = process.cwd();
|
|
233041
|
+
if (withOd) {
|
|
233042
|
+
const odDir = process.env.OPEN_DESIGN_DIR;
|
|
233043
|
+
const odPort = parseInt(process.env.OD_PORT ?? "7456", 10);
|
|
233044
|
+
if (!odDir) {
|
|
233045
|
+
console.warn("OPEN_DESIGN_DIR is not set. Create a .env file from .env.example");
|
|
233046
|
+
} else {
|
|
233047
|
+
ensureOdMcpEntry(odDir, odPort);
|
|
233048
|
+
const alreadyAlive = await waitForOdDaemon(odPort, 2e3);
|
|
233049
|
+
if (!alreadyAlive) {
|
|
233050
|
+
try {
|
|
233051
|
+
const odChild = startOdDaemon(odDir, odPort);
|
|
233052
|
+
registerOdCleanup(odChild);
|
|
233053
|
+
let odRestartCount = 0;
|
|
233054
|
+
let lastRestartTime = 0;
|
|
233055
|
+
const attachExitHandler = (child) => {
|
|
233056
|
+
child.on("exit", (code, signal) => {
|
|
233057
|
+
if (signal) {
|
|
233058
|
+
harnessLogger.info("ODDaemon", `Open Design daemon killed by signal ${signal}`);
|
|
233059
|
+
} else if (code !== 0 && code !== null) {
|
|
233060
|
+
harnessLogger.info("ODDaemon", `Open Design daemon exited with code ${code}`);
|
|
233061
|
+
}
|
|
233062
|
+
if (code !== 0 && code !== null && withOd) {
|
|
233063
|
+
const now = Date.now();
|
|
233064
|
+
if (now - lastRestartTime < 5e3) {
|
|
233065
|
+
odRestartCount++;
|
|
233066
|
+
} else {
|
|
233067
|
+
odRestartCount = 1;
|
|
233068
|
+
}
|
|
233069
|
+
lastRestartTime = now;
|
|
233070
|
+
if (odRestartCount > 3) {
|
|
233071
|
+
harnessLogger.warn("ODDaemon", "Open Design daemon restart loop detected (3 rapid restarts), giving up");
|
|
233072
|
+
return;
|
|
233073
|
+
}
|
|
233074
|
+
harnessLogger.info("ODDaemon", `Restarting Open Design daemon (attempt ${odRestartCount})...`);
|
|
233075
|
+
try {
|
|
233076
|
+
const newChild = startOdDaemon(odDir, odPort);
|
|
233077
|
+
registerOdCleanup(newChild);
|
|
233078
|
+
attachExitHandler(newChild);
|
|
233079
|
+
void waitForOdDaemon(odPort).then((healthy) => {
|
|
233080
|
+
if (healthy) {
|
|
233081
|
+
harnessLogger.info("ODDaemon", "Open Design daemon restarted successfully");
|
|
233082
|
+
}
|
|
233083
|
+
});
|
|
233084
|
+
} catch (e) {
|
|
233085
|
+
harnessLogger.warn("ODDaemon", `Failed to restart Open Design daemon: ${e instanceof Error ? e.message : String(e)}`);
|
|
233086
|
+
}
|
|
233087
|
+
}
|
|
233088
|
+
});
|
|
233089
|
+
child.on("error", (err) => {
|
|
233090
|
+
if (err.code === "ENOENT") {
|
|
233091
|
+
const expandedDir = expandTilde2(odDir);
|
|
233092
|
+
if (!existsSync26(expandedDir)) {
|
|
233093
|
+
console.warn(
|
|
233094
|
+
`Open Design directory not found: ${expandedDir}. Check OPEN_DESIGN_DIR in .env`
|
|
233095
|
+
);
|
|
233096
|
+
} else {
|
|
233097
|
+
console.warn(
|
|
233098
|
+
`Cannot start Open Design daemon: command not found. Install pnpm (https://pnpm.io/installation) or run \`cd ${expandedDir} && pnpm link --global\` for the global od command.`
|
|
233099
|
+
);
|
|
233100
|
+
}
|
|
233101
|
+
} else {
|
|
233102
|
+
harnessLogger.warn("ODDaemon", `Open Design daemon error: ${err.message}`);
|
|
233103
|
+
}
|
|
233104
|
+
});
|
|
233105
|
+
};
|
|
233106
|
+
attachExitHandler(odChild);
|
|
233107
|
+
await waitForOdDaemon(odPort);
|
|
233108
|
+
} catch (e) {
|
|
233109
|
+
harnessLogger.warn(
|
|
233110
|
+
"ODDaemon",
|
|
233111
|
+
`Failed to start Open Design daemon: ${e instanceof Error ? e.message : String(e)}`
|
|
233112
|
+
);
|
|
233113
|
+
}
|
|
233114
|
+
}
|
|
233115
|
+
}
|
|
233116
|
+
}
|
|
232702
233117
|
const config = loadConfig(cwd);
|
|
232703
233118
|
if (config.apiKey) {
|
|
232704
233119
|
const envVar = PROVIDER_ENV_VARS[config.provider] ?? "DEEPSEEK_API_KEY";
|
|
@@ -232728,7 +233143,7 @@ async function main() {
|
|
|
232728
233143
|
}
|
|
232729
233144
|
}
|
|
232730
233145
|
main().catch((err) => {
|
|
232731
|
-
harnessLogger.error("
|
|
233146
|
+
harnessLogger.error("FatalStartup", err instanceof Error ? err.message : String(err));
|
|
232732
233147
|
emergencySaveSession();
|
|
232733
233148
|
process.exit(1);
|
|
232734
233149
|
});
|