@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/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 "high";
159
- return "off";
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, channel, agentType, agentId, tag, message) {
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()}] [${channel}] [${agentType}/${agentId}] [${tag}] ${message}`;
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 channelPath(channel) {
560
- return join2(LOG_DIR, `${channel}.log`);
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(channel, tag, message) {
583
- this.write("debug", channel, tag, message);
627
+ debug(tag, message) {
628
+ this.write("debug", tag, message);
584
629
  }
585
- info(channel, tag, message) {
586
- this.write("info", channel, tag, message);
630
+ info(tag, message) {
631
+ this.write("info", tag, message);
587
632
  }
588
- warn(channel, tag, message) {
589
- this.write("warn", channel, tag, message);
633
+ warn(tag, message) {
634
+ this.write("warn", tag, message);
590
635
  }
591
- error(channel, tag, message) {
592
- this.write("error", channel, tag, message);
636
+ error(tag, message) {
637
+ this.write("error", tag, message);
593
638
  }
594
- clear(channel) {
639
+ clear() {
595
640
  try {
596
641
  ensureDir();
597
- writeFileSync2(channelPath(channel), "", "utf-8");
642
+ writeFileSync2(filePath(), "", "utf-8");
598
643
  } catch {
599
644
  }
600
645
  }
601
646
  // ── Internal ──
602
- write(level, channel, tag, message) {
647
+ write(level, tag, message) {
603
648
  if (LEVEL_RANK[level] < this.minLevel) return;
604
- const line = formatLine(level, channel, this.type, this.id, tag, message);
649
+ const line = formatLine(level, this.type, this.id, tag, message);
605
650
  try {
606
651
  ensureDir();
607
- appendFileSync(channelPath(channel), line + "\n", "utf8");
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("tool", "ImageCache", "sharp not available, images will be stored uncompressed");
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("tool", "ImageCache", `sharp processing failed, storing original: ${String(err)}`);
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 filePath;
878
+ let filePath2;
834
879
  if (existsSync4(projPath)) {
835
- filePath = projPath;
880
+ filePath2 = projPath;
836
881
  } else if (existsSync4(globalPath)) {
837
- filePath = globalPath;
882
+ filePath2 = globalPath;
838
883
  } else {
839
884
  throw new SessionValidateError(`Session not found: ${id}`);
840
885
  }
841
- const stat4 = existsSync4(filePath);
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(filePath, "utf8"));
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 filePath;
901
+ let filePath2;
857
902
  if (existsSync4(projPath)) {
858
- filePath = projPath;
903
+ filePath2 = projPath;
859
904
  } else if (existsSync4(globalPath)) {
860
- filePath = globalPath;
905
+ filePath2 = globalPath;
861
906
  } else {
862
907
  return null;
863
908
  }
864
909
  try {
865
- const raw = JSON.parse(readFileSync3(filePath, "utf8"));
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("session", "Save", `trySaveSession failed: ${String(err)}`);
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 filePath = toCanonicalName(fileName);
9128
- if (fileWatcherCallbacks.add(filePath, callback).length === 1 && fileTimestamps) {
9129
- fileTimestamps.set(filePath, getModifiedTime3(fileName) || missingFileModifiedTime);
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(filePath) || ".";
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(filePath, callback);
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 filePath = toCanonicalName(fileName);
9154
- const callbacks = fileName && fileWatcherCallbacks.get(filePath);
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(filePath);
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(filePath, currentModifiedTime);
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 filePath = combinePaths(containingDirectoryPath, language2);
16693
+ let filePath2 = combinePaths(containingDirectoryPath, language2);
16649
16694
  if (territory2) {
16650
- filePath = filePath + "-" + territory2;
16695
+ filePath2 = filePath2 + "-" + territory2;
16651
16696
  }
16652
- filePath = sys2.resolvePath(combinePaths(filePath, "diagnosticMessages.generated.json"));
16653
- if (!sys2.fileExists(filePath)) {
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(filePath);
16703
+ fileContents = sys2.readFile(filePath2);
16659
16704
  } catch {
16660
16705
  if (errors2) {
16661
- errors2.push(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0, filePath));
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, filePath));
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 filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
22166
+ const filePath2 = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
22122
22167
  const relativePath = getRelativePathToDirectoryOrUrl(
22123
22168
  dir,
22124
- filePath,
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(filePath, ignoreCase, outputDir, getCommonSourceDirectory2) {
22244
+ function getPossibleOriginalInputPathWithoutChangingExt(filePath2, ignoreCase, outputDir, getCommonSourceDirectory2) {
22200
22245
  return outputDir ? resolvePath2(
22201
22246
  getCommonSourceDirectory2(),
22202
- getRelativePathFromDirectory(outputDir, filePath, ignoreCase)
22203
- ) : filePath;
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, filePath, sourceFile) {
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(filePath));
131304
+ return getDirectoryPath(normalizePath2(filePath2));
131260
131305
  }
131261
- function getSourceMappingURL(mapOptions, sourceMapGenerator, filePath, sourceMapFilePath, sourceFile) {
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(filePath)),
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, filePath, eventKind) {
136301
+ function addOrDeleteFile(fileName, filePath2, eventKind) {
136257
136302
  if (eventKind === 1) {
136258
136303
  return;
136259
136304
  }
136260
- const parentResult = getCachedFileSystemEntriesForBaseDir(filePath);
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(filePath);
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, filePath) => resolutions.forEach((resolution, name, mode) => callback(resolution, name, mode, filePath)));
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 filePath = toPath3(file);
140143
- if (getSourceFileByPath(filePath)) {
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(filePath, out) || isSameFile(
140149
- filePath,
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, filePath, currentDirectory, !host.useCaseSensitiveFileNames())) {
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, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
140203
+ return containsPath(options.outDir, filePath2, currentDirectory, !host.useCaseSensitiveFileNames());
140159
140204
  }
140160
- if (fileExtensionIsOneOf(filePath, supportedJSExtensionsFlat) || isDeclarationFileName(filePath)) {
140161
- const filePathWithoutExtension = removeFileExtension(filePath);
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, filePath, invalidateJsFiles, cancellationToken, host) {
141618
+ function handleDtsMayChangeOfGlobalScope(state, filePath2, invalidateJsFiles, cancellationToken, host) {
141574
141619
  var _a;
141575
- if (!((_a = state.fileInfos.get(filePath)) == null ? void 0 : _a.affectsGlobalScope)) return false;
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, (filePath) => handleDtsMayChangeOfFileAndExportsOfFile(
141686
+ return references && forEachKey(references, (filePath2) => handleDtsMayChangeOfFileAndExportsOfFile(
141642
141687
  state,
141643
- filePath,
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, filePath, invalidateJsFiles, seenFileAndExportsOfFile, cancellationToken, host) {
141696
+ function handleDtsMayChangeOfFileAndExportsOfFile(state, filePath2, invalidateJsFiles, seenFileAndExportsOfFile, cancellationToken, host) {
141652
141697
  var _a;
141653
- if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return void 0;
141654
- if (handleDtsMayChangeOfGlobalScope(state, filePath, invalidateJsFiles, cancellationToken, host)) return true;
141655
- handleDtsMayChangeOf(state, filePath, invalidateJsFiles, cancellationToken, host);
141656
- (_a = state.referencedMap.getKeys(filePath)) == null ? void 0 : _a.forEach(
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 filePath = sourceFiles[0].resolvedPath;
142301
- emitSignature = handleNewSignature((_c = state.emitSignatures) == null ? void 0 : _c.get(filePath), emitSignature);
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(filePath, emitSignature);
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(filePath) {
142787
- return canWatchAffectedPackageJsonOrNodeModulesOfAtTypes(filePath);
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, filePath, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution) {
143370
- (resolution.files ?? (resolution.files = /* @__PURE__ */ new Set())).add(filePath);
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, filePath, getResolutionWithResolvedFileName) {
143613
- Debug.checkDefined(resolution.files).delete(filePath);
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, filePath, getResolutionWithResolvedFileName) {
143661
- const resolutions = cache.get(filePath);
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
- filePath,
143711
+ filePath2,
143667
143712
  getResolutionWithResolvedFileName
143668
143713
  )
143669
143714
  );
143670
- cache.delete(filePath);
143715
+ cache.delete(filePath2);
143671
143716
  }
143672
143717
  }
143673
- function removeResolutionsFromProjectReferenceRedirects(filePath) {
143718
+ function removeResolutionsFromProjectReferenceRedirects(filePath2) {
143674
143719
  if (!fileExtensionIs(
143675
- filePath,
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(filePath);
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(filePath) {
143686
- removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution);
143687
- removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution);
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(filePath) {
143703
- removeResolutionsOfFile(filePath);
143747
+ function invalidateResolutionOfFile(filePath2) {
143748
+ removeResolutionsOfFile(filePath2);
143704
143749
  const prevHasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
143705
- if (invalidateResolutions(resolvedFileToResolution.get(filePath), returnTrue) && hasChangedAutomaticTypeDirectiveNames && !prevHasChangedAutomaticTypeDirectiveNames) {
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 filePath = program.getCanonicalFileName(fileName);
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)) === filePath);
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 filePath of files) {
183293
- filePath = normalizePath2(filePath);
183294
- if (exclude && comparePaths(filePath, exclude, scriptDirectory, ignoreCase) === 0) {
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(filePath),
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(filePath) {
189599
- const components = getPathComponents(filePath);
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(filePath) {
201073
- return this.projectService.openFiles.has(filePath);
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(filePath) {
215471
+ function openDashboard(filePath2) {
215427
215472
  const platform = process.platform;
215428
215473
  let cmd;
215429
215474
  if (platform === "darwin") {
215430
- cmd = `open "${filePath}"`;
215475
+ cmd = `open "${filePath2}"`;
215431
215476
  } else if (platform === "linux") {
215432
- cmd = `xdg-open "${filePath}"`;
215477
+ cmd = `xdg-open "${filePath2}"`;
215433
215478
  } else if (platform === "win32") {
215434
- cmd = `start "" "${filePath}"`;
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("analysis", stepName, `JSON parse: ${msg}`);
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("analysis", stepName, `validation: ${result.errors.join("; ")}`);
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("analysis", "RuleAttribution", `Prompt size: ${prompt.length} chars, graph ${graphSnapshot ? `${graphSnapshot.dataFlows.length} dataFlows, ${graphSnapshot.subtasks.length} subtasks` : "none"}`);
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("analysis", "RuleAttribution", `LLM call failed: ${err.message}`);
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("analysis", "RuleAttribution", "Retry LLM call failed");
216808
+ if (logger) logger.warn("RuleAttribution", "Retry LLM call failed");
216764
216809
  return [];
216765
216810
  }
216766
216811
  }
216767
- if (logger) logger.warn("analysis", "RuleAttribution", "No JSON found in LLM response after retry");
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("analysis", "RuleAttribution", "Validation retry failed");
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("analysis", "RuleAttribution", "Retry LLM call failed");
216864
+ if (logger) logger.warn("RuleAttribution", "Retry LLM call failed");
216820
216865
  return [];
216821
216866
  }
216822
216867
  }
216823
- if (logger) logger.warn("analysis", "RuleAttribution", "No JSON found in LLM response after retry");
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("analysis", "RuleAttribution", "Validation retry failed");
216884
+ if (logger) logger.warn("RuleAttribution", "Validation retry failed");
216840
216885
  return [];
216841
216886
  }
216842
216887
  }
216843
216888
  }
216844
- if (logger) logger.info("analysis", "RuleAttribution", `Generated ${rulesOutput.length} rules`);
216889
+ if (logger) logger.info("RuleAttribution", `Generated ${rulesOutput.length} rules`);
216845
216890
  if (rulesOutput.length === 0) {
216846
- if (logger) logger.info("analysis", "RuleAttribution", `Raw LLM response (first 500): ${rawOutput.slice(0, 500)}`);
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 filePath = join24(workspacePath, "library", "meta.md");
218397
- writeFileSync12(filePath, content, "utf-8");
218398
- return filePath;
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 filePath = join24(workspacePath, "library", "skeleton.md");
218462
- writeFileSync12(filePath, lines.join("\n"), "utf-8");
218463
- return filePath;
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 filePath = join24(workspacePath, "library", "signals.md");
218508
- writeFileSync12(filePath, lines.join("\n"), "utf-8");
218509
- return filePath;
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 filePath = join24(workspacePath, "library", "data-items.md");
218531
- writeFileSync12(filePath, lines.join("\n"), "utf-8");
218532
- return filePath;
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 filePath = join24(workspacePath, "library", "steps", fileName);
218574
- writeFileSync12(filePath, lines.join("\n"), "utf-8");
218575
- written.push(filePath);
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 filePath = join24(workspacePath, "library", "README.md");
218658
- writeFileSync12(filePath, content, "utf-8");
218659
- return filePath;
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("analysis", "Progress", label);
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("analysis", "Progress", `Phase ${phaseIndex} done: ${summary}`);
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("analysis", "Progress", msg);
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("analysis", "FocusPipeline", `Start: ${steps.length} steps, session ${sessionId.slice(0, 8)}`);
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("analysis", "Phase0", `Library: ${fileCount} files \u2192 ${workspacePath}`);
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("analysis", "SCAN", scanSummary);
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("analysis", "FocusPipeline", "Early exit: no issues detected");
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("analysis", "ZOOM", `${zoneAnalyses.length} zones, ${zoneAnalyses.filter((z) => z.zoneGraphComplete).length} complete`);
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("analysis", "SYNTH", synthSummary);
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("analysis", "Phase4", `${rules.length} rules extracted`);
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("analysis", "FocusPipeline", `Done: ${(totalDuration / 1e3).toFixed(1)}s, ${totalLLMCalls} LLM calls, ${keyFindings}`);
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("analysis", "Step1", `Fixing overlap: ${prev.id} (${prev.stepStart}-${prev.stepEnd}) overlaps ${next.id} (${next.stepStart}-${next.stepEnd}), truncating ${prev.id}.stepEnd to ${next.stepStart - 1}`);
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("analysis", "Step1", `Filling gap: gap ${prev.stepEnd + 1}-${next.stepStart - 1} between ${prev.id} and ${next.id}, extending ${prev.id}.stepEnd to ${next.stepStart - 1}`);
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("analysis", "Step3", `Subtask ${subtask.id}: ${flows.length} data flows extracted`);
219239
+ if (logger) logger.info("Step3", `Subtask ${subtask.id}: ${flows.length} data flows extracted`);
219195
219240
  } catch (err) {
219196
- if (logger) logger.warn("analysis", "Step3", `Subtask ${subtask.id}: ${err instanceof Error ? err.message : String(err)}`);
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("analysis", "Step3", `${failedSubtasks}/${subtasks.length} subtasks failed to produce data flows`);
219246
+ if (logger) logger.warn("Step3", `${failedSubtasks}/${subtasks.length} subtasks failed to produce data flows`);
219202
219247
  }
219203
- if (logger) logger.info("analysis", "Step3", `Subtask summary: ${allFlows.length} total data flows from ${subtasks.length - failedSubtasks}/${subtasks.length} subtasks`);
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("analysis", "RuleStore", `Failed to load rules.json, starting fresh: ${err.message}`);
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("analysis", "RuleStore", `Failed to save rules.json: ${err.message}`);
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("analysis", "RuleStore", "No JSON in merge LLM response, adding all as new");
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("analysis", "RuleStore", `Merge validation failed: ${parsed.errors.join("; ")}`);
219542
+ if (logger) logger.warn("RuleStore", `Merge validation failed: ${parsed.errors.join("; ")}`);
219498
219543
  }
219499
219544
  } catch (err) {
219500
- if (logger) logger.warn("analysis", "RuleStore", `Semantic merge LLM call failed, adding all as new: ${err.message}`);
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("analysis");
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("analysis", "Pipeline", `crash: ${err instanceof Error ? err.message : String(err)}`);
219652
+ evalLogger.error("Pipeline", `crash: ${err instanceof Error ? err.message : String(err)}`);
219608
219653
  if (err instanceof Error && err.stack) {
219609
- evalLogger.error("analysis", "Pipeline", `stack:
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(filePath) {
220628
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
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(filePath) {
220634
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
220678
+ function isImagePath(filePath2) {
220679
+ const ext = filePath2.slice(filePath2.lastIndexOf(".")).toLowerCase();
220635
220680
  return IMAGE_EXTENSIONS.has(ext);
220636
220681
  }
220637
- function imageMimeType(filePath) {
220638
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
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(filePath) {
220649
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
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 readFileSync21, existsSync as existsSync24, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, rmSync as rmSync3, readdirSync as readdirSync9, statSync as statSync5 } from "node:fs";
221574
- import { join as join29, extname as extname2, resolve as resolve10 } from "node:path";
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 = join29(this.config.projectPath, ".dscode", "uploads", sessionId);
221635
- if (existsSync24(uploadDir)) {
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 = join29(this.config.projectPath, ".dscode", "uploads", sessionId);
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 = join29(uploadDir, tempName);
222030
- writeFileSync14(tempPath, Buffer.from(uf.content, "base64"));
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("tool", "web-backend", `promptWithImages: textLen=${text.length}, images=${imageContents.length}, img[0].dataLen=${imageContents[0]?.data?.length ?? 0}, mime=${imageContents[0]?.mimeType ?? "?"}`);
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("session", "WebBackend", "saving pendingPermission to metadata, then denying");
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 = join29(this.config.projectPath, ".dscode", "uploads");
222320
+ const uploadsDir = join30(this.config.projectPath, ".dscode", "uploads");
222276
222321
  if (cmd.action === "clear") {
222277
- if (existsSync24(uploadsDir)) {
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 (existsSync24(uploadsDir)) {
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 = join29(uploadsDir, dir.name);
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(join29(sessionPath, f.name));
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("session", "WebBackend", "using pendingPermission from metadata");
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("session", "WebBackend", `saving with pendingPermission: ${JSON.stringify(pendingPermission)}`);
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("session", "WebBackend", "saving without pendingPermission");
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 = join29(resolve10(this.projectRoot), "dist", "web");
222885
- const moduleDist = join29(fileURLToPath3(new URL(".", import.meta.url)), "web");
222886
- const webDist = existsSync24(projectDist) ? projectDist : moduleDist;
222887
- let filePath = join29(webDist, req.url === "/" ? "index.html" : req.url);
222888
- const qIdx = filePath.indexOf("?");
222889
- if (qIdx >= 0) filePath = filePath.slice(0, qIdx);
222890
- const hIdx = filePath.indexOf("#");
222891
- if (hIdx >= 0) filePath = filePath.slice(0, hIdx);
222892
- const ext = extname2(filePath);
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 (existsSync24(filePath) && ext) {
222906
- const content = readFileSync21(filePath);
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 = readFileSync21(join29(webDist, "index.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 = join29(this.config.projectPath, ".dscode", "html_output_skill");
222924
- if (existsSync24(skillPath)) {
222925
- styleConstraints = readFileSync21(skillPath, "utf-8");
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 existsSync25, readFileSync as readFileSync22 } from "node:fs";
223144
- import { dirname as dirname7, join as join30, resolve as resolve11 } from "node:path";
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(filePath, writerType) {
224147
- const fileExists4 = existsSync7(filePath);
224148
- const content = fileExists4 ? readFileSync6(filePath) : null;
224149
- this.store.delete(filePath);
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(filePath) {
224164
- const entry = this.store.load(filePath);
224212
+ rollback(filePath2) {
224213
+ const entry = this.store.load(filePath2);
224165
224214
  if (!entry) {
224166
- throw new Error(`No checkpoint found for ${filePath}`);
224215
+ throw new Error(`No checkpoint found for ${filePath2}`);
224167
224216
  }
224168
224217
  if (entry.content !== null) {
224169
- const parentDir = dirname(filePath);
224218
+ const parentDir = dirname(filePath2);
224170
224219
  if (!existsSync7(parentDir)) {
224171
224220
  mkdirSync6(parentDir, { recursive: true });
224172
224221
  }
224173
- writeFileSync6(filePath, entry.content);
224222
+ writeFileSync6(filePath2, entry.content);
224174
224223
  } else {
224175
- if (existsSync7(filePath)) {
224176
- unlinkSync2(filePath);
224224
+ if (existsSync7(filePath2)) {
224225
+ unlinkSync2(filePath2);
224177
224226
  }
224178
224227
  }
224179
- this.store.delete(filePath);
224228
+ this.store.delete(filePath2);
224180
224229
  }
224181
224230
  /** Commit (remove) the checkpoint after a successful write. */
224182
- commit(filePath) {
224183
- this.store.delete(filePath);
224231
+ commit(filePath2) {
224232
+ this.store.delete(filePath2);
224184
224233
  }
224185
224234
  /** Check if a file has an uncommitted checkpoint. */
224186
- isDirty(filePath) {
224187
- return this.store.load(filePath) !== null;
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(filePath, writerType) {
224203
- this.writers.set(filePath, writerType);
224251
+ recordWrite(filePath2, writerType) {
224252
+ this.writers.set(filePath2, writerType);
224204
224253
  }
224205
- getWriter(filePath) {
224206
- return this.writers.get(filePath) ?? null;
224254
+ getWriter(filePath2) {
224255
+ return this.writers.get(filePath2) ?? null;
224207
224256
  }
224208
- getContinuity(filePath, currentWriter) {
224209
- const prev = this.writers.get(filePath);
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(filePath) {
224215
- this.writers.set(filePath, "bash");
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(filePath) {
224230
- return filePath.replace(/[\/\\:]/g, "_").replace(/^_+/, "");
224278
+ safeName(filePath2) {
224279
+ return filePath2.replace(/[\/\\:]/g, "_").replace(/^_+/, "");
224231
224280
  }
224232
- findCheckpointDir(filePath) {
224233
- const prefix = this.safeName(filePath) + "-";
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(filePath) {
224262
- const dir = this.findCheckpointDir(filePath);
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(filePath) {
224271
- const dir = this.findCheckpointDir(filePath);
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(filePath, fileVersion, content) {
224325
- const key = this.makeKey(filePath, fileVersion);
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(filePath);
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(filePath);
224390
+ let entries = this.byFile.get(filePath2);
224342
224391
  if (!entries) {
224343
224392
  entries = [];
224344
- this.byFile.set(filePath, entries);
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(filePath, fileVersion) {
224368
- const entries = this.byFile.get(filePath);
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(filePath, fileVersion);
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(filePath) {
224385
- const entries = this.byFile.get(filePath);
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(filePath);
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(filePath, fileVersion) {
224403
- return `${filePath}::${fileVersion}`;
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(filePath, content) {
225510
- undoSnapshots.set(filePath, content);
225558
+ function captureUndoSnapshot(filePath2, content) {
225559
+ undoSnapshots.set(filePath2, content);
225511
225560
  }
225512
- function getUndoSnapshot(filePath) {
225513
- return undoSnapshots.get(filePath);
225561
+ function getUndoSnapshot(filePath2) {
225562
+ return undoSnapshots.get(filePath2);
225514
225563
  }
225515
- function clearUndoSnapshot(filePath) {
225516
- undoSnapshots.delete(filePath);
225564
+ function clearUndoSnapshot(filePath2) {
225565
+ undoSnapshots.delete(filePath2);
225517
225566
  }
225518
- function hasUndoSnapshot(filePath) {
225519
- return undoSnapshots.has(filePath);
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(filePath) {
225534
- return SUPPORTED_EXTENSIONS.has(extname(filePath).toLowerCase());
225582
+ function isSyntaxCheckSupported(filePath2) {
225583
+ return SUPPORTED_EXTENSIONS.has(extname(filePath2).toLowerCase());
225535
225584
  }
225536
- function getSyntaxTarget(filePath) {
225537
- const ext = extname(filePath).toLowerCase();
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(filePath, content) {
225569
- const target = getSyntaxTarget(filePath);
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("tool", "Edit", "file_path is deprecated, use path instead");
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(filePath, source) {
226890
+ function parseSkillManifest(filePath2, source) {
226842
226891
  let raw;
226843
226892
  try {
226844
- const buf = readFileSync9(filePath);
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: filePath
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(filePath, source, derivedName) {
227205
+ function parseCommandFile(filePath2, source, derivedName) {
227157
227206
  let raw;
227158
227207
  try {
227159
- const buf = readFileSync10(filePath);
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 ${filePath}: frontmatter name "${parsed.name}" does not match path-derived name "${derivedName}"`
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: filePath
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 filePath = context.args?.path;
227377
- if (filePath) {
227425
+ const filePath2 = context.args?.path;
227426
+ if (filePath2) {
227378
227427
  for (const { pattern, regex } of this.denyRegexes) {
227379
- if (regex.test(filePath)) {
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
- reject(new Error(`MCP server "${this.config.name}" SSE error: ${err.message}`));
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.sendHttpMessage(this.config.url, { jsonrpc: "2.0", id, method, params: finalParams }, true, true).then((response) => {
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 = "connecting";
228591
- try {
228592
- const client = new MCPClient(cfg);
228593
- client.onEvent((event) => this.handleClientEvent(event));
228594
- await client.connect();
228595
- this.clients.set(name, client);
228596
- const tools = await client.listTools();
228597
- this.registerDriver(name, tools);
228598
- state.status = "connected";
228599
- state.error = void 0;
228600
- state.toolCount = tools.length;
228601
- state.negotiatedProtocolVersion = client.getNegotiatedProtocolVersion() ?? void 0;
228602
- state.resolvedTransport = client.getResolvedTransport();
228603
- state.compatibilityMode = client.getCompatibilityMode();
228604
- state.refreshState = "idle";
228605
- state.refreshError = void 0;
228606
- state.lastRefreshAt = Date.now();
228607
- return true;
228608
- } catch (err) {
228609
- const state2 = this.states.get(name);
228610
- if (state2.status === "connected" || state2.status === "error") {
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
- } else {
228613
- state2.status = "error";
228614
- state2.error = err.message ?? "Unknown error";
228615
- state2.refreshState = "error";
228616
- state2.refreshError = err.message ?? "Unknown error";
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
- state2.toolCount = 0;
228619
- return false;
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
- await this.reconnectServer(name);
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 filePath = join16(cacheDir, filename);
229596
- writeFileSync9(filePath, Buffer.from(displayData, "base64"));
229597
- this.pushText(c.dim(`[image: ${filePath}]`));
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.imageStatus.setText(`${chipsLine}
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
- if (nonImageRefs.length > 0) {
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
- if (images && images.length > 0 && !resolveModel(this.deps.config.provider, this.deps.config.modelId).input.includes("image"))
231164
- this.conversation.addInfo(
231165
- c.dim(`${resolveModel(this.deps.config.provider, this.deps.config.modelId).name} does not support image input natively \u2014 using vision model or OCR.`)
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("tool", "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 ?? "?"}`);
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(filePath, lineCount, fileVersion) {
231605
- const existing = pendingEvents.findIndex((e) => e.filePath === 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("tool", "EventBus", `handler error for "${event.type}": ${String(err)}`);
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("tool", "TransformContext", String(err));
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("tool", "AfterToolCall", String(err));
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("tool", "McpReload", String(err));
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("tool", "AppHostShutdown", String(err));
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("tool", "McpShutdown", String(err));
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: writeFileSync15 } = await import("node:fs");
232319
- const { join: join31 } = await import("node:path");
232320
- const dumpDir = join31(this.config.projectPath, "dump");
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 filePath = join31(dumpDir, "system-prompt.md");
232323
- writeFileSync15(filePath, prompt, "utf8");
232324
- process.stderr.write("\n[dscode] --debug: system prompt dumped to " + filePath + " (" + prompt.length + " chars)\n\n");
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("tool", "AgentEvent", String(err));
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("lifecycle", "UnhandledRejection", String(reason));
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("lifecycle", "UncaughtException", msg);
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("lifecycle", "SIGINT", "Shutting down... (press Ctrl+C again to force quit)");
232981
+ harnessLogger.info("SIGINT", "Shutting down... (press Ctrl+C again to force quit)");
232646
232982
  emergencySaveSession();
232647
232983
  } else {
232648
- harnessLogger.info("lifecycle", "SIGINT", "Force quitting...");
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("lifecycle", "SIGTERM", "Received SIGTERM, shutting down...");
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
- join30(currentDir, "..", "package.json"),
232662
- join30(currentDir, "..", "..", "package.json")
232997
+ join31(currentDir, "..", "package.json"),
232998
+ join31(currentDir, "..", "..", "package.json")
232663
232999
  ];
232664
233000
  for (const candidate of candidates) {
232665
- if (!existsSync25(candidate)) continue;
232666
- const pkg = JSON.parse(readFileSync22(candidate, "utf8"));
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("lifecycle", "FatalStartup", err instanceof Error ? err.message : String(err));
233146
+ harnessLogger.error("FatalStartup", err instanceof Error ? err.message : String(err));
232732
233147
  emergencySaveSession();
232733
233148
  process.exit(1);
232734
233149
  });