@dreb/coding-agent 2.4.3 → 2.4.5

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.
Files changed (110) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/cli/file-processor.d.ts.map +1 -1
  3. package/dist/cli/file-processor.js +1 -0
  4. package/dist/cli/file-processor.js.map +1 -1
  5. package/dist/core/agent-session.d.ts +13 -0
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +69 -10
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/buddy/buddy-controller.d.ts.map +1 -1
  10. package/dist/core/buddy/buddy-controller.js +13 -4
  11. package/dist/core/buddy/buddy-controller.js.map +1 -1
  12. package/dist/core/buddy/buddy-manager.d.ts.map +1 -1
  13. package/dist/core/buddy/buddy-manager.js +2 -0
  14. package/dist/core/buddy/buddy-manager.js.map +1 -1
  15. package/dist/core/daily-cost-tracker.d.ts.map +1 -1
  16. package/dist/core/daily-cost-tracker.js +2 -0
  17. package/dist/core/daily-cost-tracker.js.map +1 -1
  18. package/dist/core/extensions/loader.d.ts.map +1 -1
  19. package/dist/core/extensions/loader.js +2 -0
  20. package/dist/core/extensions/loader.js.map +1 -1
  21. package/dist/core/footer-data-provider.d.ts.map +1 -1
  22. package/dist/core/footer-data-provider.js +3 -0
  23. package/dist/core/footer-data-provider.js.map +1 -1
  24. package/dist/core/keybindings.d.ts.map +1 -1
  25. package/dist/core/keybindings.js +1 -0
  26. package/dist/core/keybindings.js.map +1 -1
  27. package/dist/core/package-manager.d.ts.map +1 -1
  28. package/dist/core/package-manager.js +24 -8
  29. package/dist/core/package-manager.js.map +1 -1
  30. package/dist/core/prompt-templates.d.ts.map +1 -1
  31. package/dist/core/prompt-templates.js +2 -0
  32. package/dist/core/prompt-templates.js.map +1 -1
  33. package/dist/core/resolve-config-value.d.ts +3 -1
  34. package/dist/core/resolve-config-value.d.ts.map +1 -1
  35. package/dist/core/resolve-config-value.js +11 -3
  36. package/dist/core/resolve-config-value.js.map +1 -1
  37. package/dist/core/resource-loader.d.ts +3 -0
  38. package/dist/core/resource-loader.d.ts.map +1 -1
  39. package/dist/core/resource-loader.js +69 -29
  40. package/dist/core/resource-loader.js.map +1 -1
  41. package/dist/core/sdk.d.ts.map +1 -1
  42. package/dist/core/sdk.js +17 -0
  43. package/dist/core/sdk.js.map +1 -1
  44. package/dist/core/session-manager.d.ts.map +1 -1
  45. package/dist/core/session-manager.js +6 -1
  46. package/dist/core/session-manager.js.map +1 -1
  47. package/dist/core/skills.d.ts.map +1 -1
  48. package/dist/core/skills.js +5 -1
  49. package/dist/core/skills.js.map +1 -1
  50. package/dist/core/tools/dreb-paths.d.ts.map +1 -1
  51. package/dist/core/tools/dreb-paths.js +1 -0
  52. package/dist/core/tools/dreb-paths.js.map +1 -1
  53. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  54. package/dist/core/tools/edit-diff.js +1 -0
  55. package/dist/core/tools/edit-diff.js.map +1 -1
  56. package/dist/core/tools/edit.d.ts.map +1 -1
  57. package/dist/core/tools/edit.js +1 -0
  58. package/dist/core/tools/edit.js.map +1 -1
  59. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  60. package/dist/core/tools/file-mutation-queue.js +1 -0
  61. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  62. package/dist/core/tools/grep.d.ts.map +1 -1
  63. package/dist/core/tools/grep.js +8 -0
  64. package/dist/core/tools/grep.js.map +1 -1
  65. package/dist/core/tools/path-utils.d.ts.map +1 -1
  66. package/dist/core/tools/path-utils.js +1 -0
  67. package/dist/core/tools/path-utils.js.map +1 -1
  68. package/dist/core/tools/web.d.ts.map +1 -1
  69. package/dist/core/tools/web.js +1 -0
  70. package/dist/core/tools/web.js.map +1 -1
  71. package/dist/migrations.d.ts.map +1 -1
  72. package/dist/migrations.js +1 -0
  73. package/dist/migrations.js.map +1 -1
  74. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  75. package/dist/modes/interactive/components/tool-execution.js +2 -0
  76. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  77. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  78. package/dist/modes/interactive/interactive-mode.js +5 -1
  79. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  80. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  81. package/dist/modes/interactive/theme/theme.js +4 -0
  82. package/dist/modes/interactive/theme/theme.js.map +1 -1
  83. package/dist/utils/changelog.d.ts.map +1 -1
  84. package/dist/utils/changelog.js +2 -2
  85. package/dist/utils/changelog.js.map +1 -1
  86. package/dist/utils/clipboard-image.d.ts.map +1 -1
  87. package/dist/utils/clipboard-image.js +3 -0
  88. package/dist/utils/clipboard-image.js.map +1 -1
  89. package/dist/utils/clipboard-native.d.ts.map +1 -1
  90. package/dist/utils/clipboard-native.js +1 -0
  91. package/dist/utils/clipboard-native.js.map +1 -1
  92. package/dist/utils/clipboard.d.ts.map +1 -1
  93. package/dist/utils/clipboard.js +5 -3
  94. package/dist/utils/clipboard.js.map +1 -1
  95. package/dist/utils/git.d.ts.map +1 -1
  96. package/dist/utils/git.js +2 -0
  97. package/dist/utils/git.js.map +1 -1
  98. package/dist/utils/image-resize.d.ts.map +1 -1
  99. package/dist/utils/image-resize.js +1 -0
  100. package/dist/utils/image-resize.js.map +1 -1
  101. package/dist/utils/photon.d.ts.map +1 -1
  102. package/dist/utils/photon.js +3 -0
  103. package/dist/utils/photon.js.map +1 -1
  104. package/dist/utils/tools-manager.d.ts.map +1 -1
  105. package/dist/utils/tools-manager.js +1 -0
  106. package/dist/utils/tools-manager.js.map +1 -1
  107. package/docs/custom-provider.md +20 -0
  108. package/docs/sdk.md +5 -0
  109. package/examples/sdk/12-full-control.ts +1 -0
  110. 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
- console.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));
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
- console.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));
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
- console.error(chalk.yellow(`Warning: Could not read rules directory ${dir}: ${error}`));
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
- console.error(chalk.yellow(`Warning: Could not read rule ${fullPath}: ${error}`));
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
- console.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));
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
- console.error(chalk.yellow(`Warning: Could not read rules from ${rulesDir}: ${error}`));
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
- console.error(chalk.yellow(`Warning: ${indexPath} has ${lines.length} lines, truncated to ${MEMORY_INDEX_MAX_LINES}. Consider cleaning up older entries.`));
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
- console.error(chalk.yellow(`Warning: Could not read ${indexPath}: ${error}`));
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 = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };
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
- console.error(chalk.yellow(`Warning: Could not create memory directory ${this.memoryIndexes.globalMemoryDir}: ${error}. Memory saves to this directory will fail.`));
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
- console.error(chalk.yellow(`Warning: Could not load memory indexes: ${error}. Session will start without memory context.`));
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: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, ".."),
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
  }