@dreb/coding-agent 2.4.2 → 2.4.4
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/CHANGELOG.md +10 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +1 -0
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/core/agent-session.d.ts +13 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +70 -11
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +14 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/buddy/buddy-controller.d.ts.map +1 -1
- package/dist/core/buddy/buddy-controller.js +13 -4
- package/dist/core/buddy/buddy-controller.js.map +1 -1
- package/dist/core/buddy/buddy-manager.d.ts.map +1 -1
- package/dist/core/buddy/buddy-manager.js +2 -0
- package/dist/core/buddy/buddy-manager.js.map +1 -1
- package/dist/core/daily-cost-tracker.d.ts.map +1 -1
- package/dist/core/daily-cost-tracker.js +2 -0
- package/dist/core/daily-cost-tracker.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +3 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +24 -8
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +2 -0
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +3 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +11 -3
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +3 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +69 -29
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +17 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +6 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +5 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +8 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/dreb-paths.d.ts.map +1 -1
- package/dist/core/tools/dreb-paths.js +1 -0
- package/dist/core/tools/dreb-paths.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +1 -0
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +1 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +1 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +8 -0
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +1 -0
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/web.d.ts.map +1 -1
- package/dist/core/tools/web.js +1 -0
- package/dist/core/tools/web.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +1 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +5 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +4 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +2 -2
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +3 -0
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +1 -0
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +5 -3
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +2 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +1 -0
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js +3 -0
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +1 -0
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +20 -0
- package/docs/sdk.md +5 -0
- package/examples/sdk/12-full-control.ts +1 -0
- package/package.json +1 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve, sep } from "node:path";
|
|
4
|
-
import chalk from "chalk";
|
|
5
4
|
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
6
5
|
import { loadThemeFromPath } from "../modes/interactive/theme/theme.js";
|
|
7
6
|
import { findGitRoot } from "./git-root.js";
|
|
@@ -12,7 +11,7 @@ import { loadPromptTemplates } from "./prompt-templates.js";
|
|
|
12
11
|
import { SettingsManager } from "./settings-manager.js";
|
|
13
12
|
import { loadSkills } from "./skills.js";
|
|
14
13
|
import { createSourceInfo } from "./source-info.js";
|
|
15
|
-
function resolvePromptInput(input, description) {
|
|
14
|
+
function resolvePromptInput(input, description, diagnostics) {
|
|
16
15
|
if (!input) {
|
|
17
16
|
return undefined;
|
|
18
17
|
}
|
|
@@ -21,7 +20,11 @@ function resolvePromptInput(input, description) {
|
|
|
21
20
|
return readFileSync(input, "utf-8");
|
|
22
21
|
}
|
|
23
22
|
catch (error) {
|
|
24
|
-
|
|
23
|
+
diagnostics?.push({
|
|
24
|
+
type: "warning",
|
|
25
|
+
message: `Could not read ${description} file ${input}: ${error}`,
|
|
26
|
+
path: input,
|
|
27
|
+
});
|
|
25
28
|
return input;
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -30,7 +33,7 @@ function resolvePromptInput(input, description) {
|
|
|
30
33
|
function stripHtmlComments(content) {
|
|
31
34
|
return content.replace(/<!--[\s\S]*?-->/g, "");
|
|
32
35
|
}
|
|
33
|
-
function loadContextFilesFromDir(dir) {
|
|
36
|
+
function loadContextFilesFromDir(dir, diagnostics) {
|
|
34
37
|
const candidates = ["AGENTS.md", "CLAUDE.md", join(".claude", "CLAUDE.md"), join(".dreb", "CONTEXT.md")];
|
|
35
38
|
const results = [];
|
|
36
39
|
for (const filename of candidates) {
|
|
@@ -43,13 +46,13 @@ function loadContextFilesFromDir(dir) {
|
|
|
43
46
|
});
|
|
44
47
|
}
|
|
45
48
|
catch (error) {
|
|
46
|
-
|
|
49
|
+
diagnostics?.push({ type: "warning", message: `Could not read ${filePath}: ${error}`, path: filePath });
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
return results;
|
|
51
54
|
}
|
|
52
|
-
function loadRulesFromDir(dir, contextFiles, seenPaths, depth = 0) {
|
|
55
|
+
function loadRulesFromDir(dir, contextFiles, seenPaths, depth = 0, diagnostics) {
|
|
53
56
|
if (depth > 10)
|
|
54
57
|
return;
|
|
55
58
|
let entries;
|
|
@@ -57,13 +60,13 @@ function loadRulesFromDir(dir, contextFiles, seenPaths, depth = 0) {
|
|
|
57
60
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
58
61
|
}
|
|
59
62
|
catch (error) {
|
|
60
|
-
|
|
63
|
+
diagnostics?.push({ type: "warning", message: `Could not read rules directory ${dir}: ${error}`, path: dir });
|
|
61
64
|
return;
|
|
62
65
|
}
|
|
63
66
|
for (const entry of entries) {
|
|
64
67
|
const fullPath = join(dir, entry.name);
|
|
65
68
|
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
66
|
-
loadRulesFromDir(fullPath, contextFiles, seenPaths, depth + 1);
|
|
69
|
+
loadRulesFromDir(fullPath, contextFiles, seenPaths, depth + 1, diagnostics);
|
|
67
70
|
}
|
|
68
71
|
else if (entry.isFile() && entry.name.endsWith(".md") && !seenPaths.has(fullPath)) {
|
|
69
72
|
try {
|
|
@@ -82,12 +85,16 @@ function loadRulesFromDir(dir, contextFiles, seenPaths, depth = 0) {
|
|
|
82
85
|
contextFiles.push({ path: fullPath, content: stripHtmlComments(content) });
|
|
83
86
|
}
|
|
84
87
|
catch (error) {
|
|
85
|
-
|
|
88
|
+
diagnostics?.push({
|
|
89
|
+
type: "warning",
|
|
90
|
+
message: `Could not read rule ${fullPath}: ${error}`,
|
|
91
|
+
path: fullPath,
|
|
92
|
+
});
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
|
-
function loadProjectContextFiles(options = {}) {
|
|
97
|
+
function loadProjectContextFiles(options = {}, diagnostics) {
|
|
91
98
|
const resolvedCwd = options.cwd ?? process.cwd();
|
|
92
99
|
const resolvedAgentDir = options.agentDir ?? getAgentDir();
|
|
93
100
|
const contextFiles = [];
|
|
@@ -109,7 +116,7 @@ function loadProjectContextFiles(options = {}) {
|
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
catch (error) {
|
|
112
|
-
|
|
119
|
+
diagnostics?.push({ type: "warning", message: `Could not read ${filePath}: ${error}`, path: filePath });
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
122
|
}
|
|
@@ -118,7 +125,7 @@ function loadProjectContextFiles(options = {}) {
|
|
|
118
125
|
let currentDir = resolvedCwd;
|
|
119
126
|
const root = resolve("/");
|
|
120
127
|
while (true) {
|
|
121
|
-
const dirFiles = loadContextFilesFromDir(currentDir);
|
|
128
|
+
const dirFiles = loadContextFilesFromDir(currentDir, diagnostics);
|
|
122
129
|
const newFiles = dirFiles.filter((f) => !seenPaths.has(f.path));
|
|
123
130
|
for (const file of newFiles) {
|
|
124
131
|
seenPaths.add(file.path);
|
|
@@ -141,10 +148,14 @@ function loadProjectContextFiles(options = {}) {
|
|
|
141
148
|
for (const rulesDir of rulesSearchDirs) {
|
|
142
149
|
if (existsSync(rulesDir)) {
|
|
143
150
|
try {
|
|
144
|
-
loadRulesFromDir(rulesDir, contextFiles, seenPaths);
|
|
151
|
+
loadRulesFromDir(rulesDir, contextFiles, seenPaths, 0, diagnostics);
|
|
145
152
|
}
|
|
146
153
|
catch (error) {
|
|
147
|
-
|
|
154
|
+
diagnostics?.push({
|
|
155
|
+
type: "warning",
|
|
156
|
+
message: `Could not read rules from ${rulesDir}: ${error}`,
|
|
157
|
+
path: rulesDir,
|
|
158
|
+
});
|
|
148
159
|
}
|
|
149
160
|
}
|
|
150
161
|
}
|
|
@@ -159,7 +170,7 @@ const MEMORY_INDEX_MAX_LINES = 200;
|
|
|
159
170
|
export function encodeClaudeProjectPath(absolutePath) {
|
|
160
171
|
return absolutePath.replace(/[/_]/g, "-");
|
|
161
172
|
}
|
|
162
|
-
function readMemoryIndex(dir) {
|
|
173
|
+
function readMemoryIndex(dir, diagnostics) {
|
|
163
174
|
const indexPath = join(dir, "MEMORY.md");
|
|
164
175
|
try {
|
|
165
176
|
if (!existsSync(indexPath))
|
|
@@ -167,17 +178,21 @@ function readMemoryIndex(dir) {
|
|
|
167
178
|
const content = readFileSync(indexPath, "utf-8");
|
|
168
179
|
const lines = content.split("\n");
|
|
169
180
|
if (lines.length > MEMORY_INDEX_MAX_LINES) {
|
|
170
|
-
|
|
181
|
+
diagnostics?.push({
|
|
182
|
+
type: "warning",
|
|
183
|
+
message: `${indexPath} has ${lines.length} lines, truncated to ${MEMORY_INDEX_MAX_LINES}. Consider cleaning up older entries.`,
|
|
184
|
+
path: indexPath,
|
|
185
|
+
});
|
|
171
186
|
return lines.slice(0, MEMORY_INDEX_MAX_LINES).join("\n");
|
|
172
187
|
}
|
|
173
188
|
return content;
|
|
174
189
|
}
|
|
175
190
|
catch (error) {
|
|
176
|
-
|
|
191
|
+
diagnostics?.push({ type: "warning", message: `Could not read ${indexPath}: ${error}`, path: indexPath });
|
|
177
192
|
return undefined;
|
|
178
193
|
}
|
|
179
194
|
}
|
|
180
|
-
function loadMemoryIndexes(options) {
|
|
195
|
+
function loadMemoryIndexes(options, diagnostics) {
|
|
181
196
|
const resolvedCwd = options.cwd ?? process.cwd();
|
|
182
197
|
const projectRoot = findGitRoot(resolvedCwd) ?? resolvedCwd;
|
|
183
198
|
const drebRoot = options.agentDir ? resolve(options.agentDir, "..") : join(homedir(), ".dreb");
|
|
@@ -190,22 +205,22 @@ function loadMemoryIndexes(options) {
|
|
|
190
205
|
const globalSources = [];
|
|
191
206
|
const projectSources = [];
|
|
192
207
|
// Load dreb memory (primary)
|
|
193
|
-
const drebGlobal = readMemoryIndex(globalMemoryDir);
|
|
208
|
+
const drebGlobal = readMemoryIndex(globalMemoryDir, diagnostics);
|
|
194
209
|
if (drebGlobal) {
|
|
195
210
|
globalSources.push({ content: drebGlobal, dir: globalMemoryDir, source: "dreb" });
|
|
196
211
|
}
|
|
197
|
-
const drebProject = globalMemoryDir !== projectMemoryDir ? readMemoryIndex(projectMemoryDir) : undefined;
|
|
212
|
+
const drebProject = globalMemoryDir !== projectMemoryDir ? readMemoryIndex(projectMemoryDir, diagnostics) : undefined;
|
|
198
213
|
if (drebProject) {
|
|
199
214
|
projectSources.push({ content: drebProject, dir: projectMemoryDir, source: "dreb" });
|
|
200
215
|
}
|
|
201
216
|
// Load Claude Code memory (read-only, compat)
|
|
202
|
-
const claudeGlobal = readMemoryIndex(claudeGlobalMemoryDir);
|
|
217
|
+
const claudeGlobal = readMemoryIndex(claudeGlobalMemoryDir, diagnostics);
|
|
203
218
|
if (claudeGlobal) {
|
|
204
219
|
globalSources.push({ content: claudeGlobal, dir: claudeGlobalMemoryDir, source: "claude" });
|
|
205
220
|
}
|
|
206
221
|
// Only load Claude project memory if it's a different path than Claude global
|
|
207
222
|
if (claudeProjectMemoryDir !== claudeGlobalMemoryDir) {
|
|
208
|
-
const claudeProject = readMemoryIndex(claudeProjectMemoryDir);
|
|
223
|
+
const claudeProject = readMemoryIndex(claudeProjectMemoryDir, diagnostics);
|
|
209
224
|
if (claudeProject) {
|
|
210
225
|
projectSources.push({ content: claudeProject, dir: claudeProjectMemoryDir, source: "claude" });
|
|
211
226
|
}
|
|
@@ -252,6 +267,7 @@ export class DefaultResourceLoader {
|
|
|
252
267
|
memoryIndexes;
|
|
253
268
|
systemPrompt;
|
|
254
269
|
appendSystemPrompt;
|
|
270
|
+
contextDiagnostics;
|
|
255
271
|
lastSkillPaths;
|
|
256
272
|
extensionSkillSourceInfos;
|
|
257
273
|
extensionPromptSourceInfos;
|
|
@@ -301,6 +317,7 @@ export class DefaultResourceLoader {
|
|
|
301
317
|
projectMemoryDir: join(this.cwd, ".dreb", "memory"),
|
|
302
318
|
};
|
|
303
319
|
this.appendSystemPrompt = [];
|
|
320
|
+
this.contextDiagnostics = [];
|
|
304
321
|
this.lastSkillPaths = [];
|
|
305
322
|
this.extensionSkillSourceInfos = new Map();
|
|
306
323
|
this.extensionPromptSourceInfos = new Map();
|
|
@@ -320,6 +337,9 @@ export class DefaultResourceLoader {
|
|
|
320
337
|
getThemes() {
|
|
321
338
|
return { themes: this.themes, diagnostics: this.themeDiagnostics };
|
|
322
339
|
}
|
|
340
|
+
getContextDiagnostics() {
|
|
341
|
+
return this.contextDiagnostics;
|
|
342
|
+
}
|
|
323
343
|
getAgentsFiles() {
|
|
324
344
|
return { agentsFiles: this.agentsFiles };
|
|
325
345
|
}
|
|
@@ -359,6 +379,7 @@ export class DefaultResourceLoader {
|
|
|
359
379
|
}
|
|
360
380
|
}
|
|
361
381
|
async reload() {
|
|
382
|
+
this.contextDiagnostics = [];
|
|
362
383
|
const resolvedPaths = await this.packageManager.resolve();
|
|
363
384
|
const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {
|
|
364
385
|
temporary: true,
|
|
@@ -392,6 +413,7 @@ export class DefaultResourceLoader {
|
|
|
392
413
|
}
|
|
393
414
|
}
|
|
394
415
|
catch {
|
|
416
|
+
// stat failed — path may not exist yet; use as-is
|
|
395
417
|
return resource.path;
|
|
396
418
|
}
|
|
397
419
|
const skillFile = join(resource.path, "SKILL.md");
|
|
@@ -449,27 +471,36 @@ export class DefaultResourceLoader {
|
|
|
449
471
|
: this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);
|
|
450
472
|
this.lastThemePaths = themePaths;
|
|
451
473
|
this.updateThemesFromPaths(themePaths, metadataByPath);
|
|
452
|
-
const agentsFiles = {
|
|
474
|
+
const agentsFiles = {
|
|
475
|
+
agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }, this.contextDiagnostics),
|
|
476
|
+
};
|
|
453
477
|
const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
|
|
454
478
|
this.agentsFiles = resolvedAgentsFiles.agentsFiles;
|
|
455
479
|
// Load memory indexes and ensure global memory directory exists.
|
|
456
480
|
// Wrapped in try/catch so memory loading failures degrade gracefully rather than crashing the session.
|
|
457
481
|
try {
|
|
458
|
-
this.memoryIndexes = loadMemoryIndexes({ cwd: this.cwd, agentDir: this.agentDir });
|
|
482
|
+
this.memoryIndexes = loadMemoryIndexes({ cwd: this.cwd, agentDir: this.agentDir }, this.contextDiagnostics);
|
|
459
483
|
try {
|
|
460
484
|
mkdirSync(this.memoryIndexes.globalMemoryDir, { recursive: true });
|
|
461
485
|
}
|
|
462
486
|
catch (error) {
|
|
463
|
-
|
|
487
|
+
this.contextDiagnostics.push({
|
|
488
|
+
type: "warning",
|
|
489
|
+
message: `Could not create memory directory ${this.memoryIndexes.globalMemoryDir}: ${error}. Memory saves to this directory will fail.`,
|
|
490
|
+
path: this.memoryIndexes.globalMemoryDir,
|
|
491
|
+
});
|
|
464
492
|
}
|
|
465
493
|
}
|
|
466
494
|
catch (error) {
|
|
467
|
-
|
|
495
|
+
this.contextDiagnostics.push({
|
|
496
|
+
type: "warning",
|
|
497
|
+
message: `Could not load memory indexes: ${error}. Session will start without memory context.`,
|
|
498
|
+
});
|
|
468
499
|
}
|
|
469
|
-
const baseSystemPrompt = resolvePromptInput(this.systemPromptSource ?? this.discoverSystemPromptFile(), "system prompt");
|
|
500
|
+
const baseSystemPrompt = resolvePromptInput(this.systemPromptSource ?? this.discoverSystemPromptFile(), "system prompt", this.contextDiagnostics);
|
|
470
501
|
this.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;
|
|
471
502
|
const appendSource = this.appendSystemPromptSource ?? this.discoverAppendSystemPromptFile();
|
|
472
|
-
const resolvedAppend = resolvePromptInput(appendSource, "append system prompt");
|
|
503
|
+
const resolvedAppend = resolvePromptInput(appendSource, "append system prompt", this.contextDiagnostics);
|
|
473
504
|
const baseAppend = resolvedAppend ? [resolvedAppend] : [];
|
|
474
505
|
this.appendSystemPrompt = this.appendSystemPromptOverride
|
|
475
506
|
? this.appendSystemPromptOverride(baseAppend)
|
|
@@ -625,12 +656,20 @@ export class DefaultResourceLoader {
|
|
|
625
656
|
return { path: filePath, source: "local", scope: "project", origin: "top-level", baseDir: root };
|
|
626
657
|
}
|
|
627
658
|
}
|
|
659
|
+
let baseDir;
|
|
660
|
+
try {
|
|
661
|
+
baseDir = statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, "..");
|
|
662
|
+
}
|
|
663
|
+
catch {
|
|
664
|
+
// Path doesn't exist (deleted file, broken symlink, race condition) — fall back to parent dir
|
|
665
|
+
baseDir = resolve(normalizedPath, "..");
|
|
666
|
+
}
|
|
628
667
|
return {
|
|
629
668
|
path: filePath,
|
|
630
669
|
source: "local",
|
|
631
670
|
scope: "temporary",
|
|
632
671
|
origin: "top-level",
|
|
633
|
-
baseDir
|
|
672
|
+
baseDir,
|
|
634
673
|
};
|
|
635
674
|
}
|
|
636
675
|
mergePaths(primary, additional) {
|
|
@@ -706,6 +745,7 @@ export class DefaultResourceLoader {
|
|
|
706
745
|
isFile = statSync(join(dir, entry.name)).isFile();
|
|
707
746
|
}
|
|
708
747
|
catch {
|
|
748
|
+
// Broken symlink — skip entry
|
|
709
749
|
continue;
|
|
710
750
|
}
|
|
711
751
|
}
|