sparkecoder 0.1.56 → 0.1.58

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 (131) hide show
  1. package/dist/agent/index.d.ts +2 -2
  2. package/dist/agent/index.js +706 -68
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +824 -186
  5. package/dist/cli.js.map +1 -1
  6. package/dist/{index-CqKMYoJv.d.ts → index-DqLDYWhb.d.ts} +1 -1
  7. package/dist/index.d.ts +3 -3
  8. package/dist/index.js +811 -173
  9. package/dist/index.js.map +1 -1
  10. package/dist/{search-CZsTAZ90.d.ts → search-DINnDTgj.d.ts} +1 -0
  11. package/dist/server/index.js +811 -173
  12. package/dist/server/index.js.map +1 -1
  13. package/dist/tools/index.d.ts +49 -3
  14. package/dist/tools/index.js +659 -60
  15. package/dist/tools/index.js.map +1 -1
  16. package/package.json +1 -1
  17. package/web/.next/BUILD_ID +1 -1
  18. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  19. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  20. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  21. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  22. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  23. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  25. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  40. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  41. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
  82. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.rsc +2 -2
  85. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +2 -2
  88. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  90. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  91. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_f661d73d._.js → 2374f_076f03ec._.js} +1 -1
  92. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e35df3d7._.js → 2374f_19289e11._.js} +1 -1
  93. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6ced4caf._.js → 2374f_2f0d9f6f._.js} +1 -1
  94. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_aade2a6d._.js → 2374f_35475cbe._.js} +1 -1
  95. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_562d2f4f._.js → 2374f_40e35a02._.js} +1 -1
  96. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_05c00b91._.js → 2374f_4666c827._.js} +1 -1
  97. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_ac284eb3._.js → 2374f_4858a1ea._.js} +1 -1
  98. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_39f76acc._.js → 2374f_51385fed._.js} +1 -1
  99. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_ef435bac._.js → 2374f_7db22cde._.js} +1 -1
  100. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_800db4e3._.js → 2374f_90b8e4fb._.js} +1 -1
  101. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1fa4a79a._.js → 2374f_b17fce11._.js} +1 -1
  102. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d118a207._.js → 2374f_b4b86c1f._.js} +1 -1
  103. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_934cb548._.js → 2374f_d8b9ce38._.js} +1 -1
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_c272cbb4._.js → 2374f_fb95e3c9._.js} +1 -1
  105. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__f44222d9._.js → [root-of-the-server]__7775f784._.js} +2 -2
  106. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__8cdc7b0b._.js → [root-of-the-server]__bd396152._.js} +4 -4
  107. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_0a13adb9._.js → web_645f4b90._.js} +2 -2
  108. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  109. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  110. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  111. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  112. package/web/.next/standalone/web/.next/static/chunks/2868b007ce5163fc.css +1 -0
  113. package/web/.next/standalone/web/.next/static/chunks/{ca717ddd7c8f37e8.js → 631b023d37a08635.js} +6 -6
  114. package/web/.next/standalone/web/.next/static/static/chunks/2868b007ce5163fc.css +1 -0
  115. package/web/.next/standalone/web/.next/static/static/chunks/{ca717ddd7c8f37e8.js → 631b023d37a08635.js} +6 -6
  116. package/web/.next/standalone/web/src/components/ai-elements/code-graph-tool.tsx +202 -0
  117. package/web/.next/standalone/web/src/components/chat-interface.tsx +49 -0
  118. package/web/.next/static/chunks/2868b007ce5163fc.css +1 -0
  119. package/web/.next/static/chunks/{ca717ddd7c8f37e8.js → 631b023d37a08635.js} +6 -6
  120. package/web/.next/standalone/web/.next/static/chunks/7228b2394d1fb347.css +0 -1
  121. package/web/.next/standalone/web/.next/static/static/chunks/7228b2394d1fb347.css +0 -1
  122. package/web/.next/static/chunks/7228b2394d1fb347.css +0 -1
  123. /package/web/.next/standalone/web/.next/static/{static/yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_buildManifest.js +0 -0
  124. /package/web/.next/standalone/web/.next/static/{static/yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_clientMiddlewareManifest.json +0 -0
  125. /package/web/.next/standalone/web/.next/static/{static/yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_ssgManifest.js +0 -0
  126. /package/web/.next/standalone/web/.next/static/{yfBGAcI8gI55lwQllPu-z → static/TuFKgULSvgTGHxXzZoeMo}/_buildManifest.js +0 -0
  127. /package/web/.next/standalone/web/.next/static/{yfBGAcI8gI55lwQllPu-z → static/TuFKgULSvgTGHxXzZoeMo}/_clientMiddlewareManifest.json +0 -0
  128. /package/web/.next/standalone/web/.next/static/{yfBGAcI8gI55lwQllPu-z → static/TuFKgULSvgTGHxXzZoeMo}/_ssgManifest.js +0 -0
  129. /package/web/.next/static/{yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_buildManifest.js +0 -0
  130. /package/web/.next/static/{yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_clientMiddlewareManifest.json +0 -0
  131. /package/web/.next/static/{yfBGAcI8gI55lwQllPu-z → TuFKgULSvgTGHxXzZoeMo}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -1461,13 +1461,13 @@ var semantic_search_exports = {};
1461
1461
  __export(semantic_search_exports, {
1462
1462
  createSemanticSearchTool: () => createSemanticSearchTool
1463
1463
  });
1464
- import { tool as tool7 } from "ai";
1465
- import { z as z8 } from "zod";
1466
- import { existsSync as existsSync10, readFileSync as readFileSync4 } from "fs";
1464
+ import { tool as tool8 } from "ai";
1465
+ import { z as z9 } from "zod";
1466
+ import { existsSync as existsSync11, readFileSync as readFileSync4 } from "fs";
1467
1467
  import { join as join4 } from "path";
1468
1468
  import { minimatch as minimatch3 } from "minimatch";
1469
1469
  function createSemanticSearchTool(options) {
1470
- return tool7({
1470
+ return tool8({
1471
1471
  description: `Search the codebase using semantic similarity. This tool finds code by understanding its meaning, not just matching text.
1472
1472
 
1473
1473
  Use this tool when:
@@ -1532,7 +1532,7 @@ Returns matching code snippets with file paths, line numbers, and relevance scor
1532
1532
  continue;
1533
1533
  }
1534
1534
  const fullPath = join4(options.workingDirectory, filePath);
1535
- if (!existsSync10(fullPath)) {
1535
+ if (!existsSync11(fullPath)) {
1536
1536
  continue;
1537
1537
  }
1538
1538
  let snippet = "";
@@ -1587,11 +1587,11 @@ var init_semantic_search = __esm({
1587
1587
  "use strict";
1588
1588
  init_semantic();
1589
1589
  init_config();
1590
- semanticSearchInputSchema = z8.object({
1591
- query: z8.string().describe("Natural language search query describing what you want to find"),
1592
- topK: z8.number().optional().default(10).describe("Number of results to return (default: 10, max: 50)"),
1593
- filePattern: z8.string().optional().describe('Filter results by file glob pattern (e.g., "*.ts", "src/**/*.py")'),
1594
- language: z8.string().optional().describe('Filter by programming language (e.g., "typescript", "python")')
1590
+ semanticSearchInputSchema = z9.object({
1591
+ query: z9.string().describe("Natural language search query describing what you want to find"),
1592
+ topK: z9.number().optional().default(10).describe("Number of results to return (default: 10, max: 50)"),
1593
+ filePattern: z9.string().optional().describe('Filter results by file glob pattern (e.g., "*.ts", "src/**/*.py")'),
1594
+ language: z9.string().optional().describe('Filter by programming language (e.g., "typescript", "python")')
1595
1595
  });
1596
1596
  }
1597
1597
  });
@@ -1600,7 +1600,7 @@ var init_semantic_search = __esm({
1600
1600
  import {
1601
1601
  streamText as streamText2,
1602
1602
  generateText as generateText3,
1603
- tool as tool10,
1603
+ tool as tool11,
1604
1604
  stepCountIs as stepCountIs2
1605
1605
  } from "ai";
1606
1606
 
@@ -1623,7 +1623,7 @@ var SUBAGENT_MODELS = {
1623
1623
  // src/agent/index.ts
1624
1624
  init_db();
1625
1625
  init_config();
1626
- import { z as z11 } from "zod";
1626
+ import { z as z12 } from "zod";
1627
1627
  import { nanoid as nanoid3 } from "nanoid";
1628
1628
 
1629
1629
  // src/tools/bash.ts
@@ -1927,8 +1927,8 @@ async function listSessionTerminals(sessionId, workingDirectory) {
1927
1927
  const terminalsDir = join2(workingDirectory, LOG_BASE_DIR, sessionId, "terminals");
1928
1928
  const terminals2 = [];
1929
1929
  try {
1930
- const { readdir: readdir5 } = await import("fs/promises");
1931
- const entries = await readdir5(terminalsDir, { withFileTypes: true });
1930
+ const { readdir: readdir6 } = await import("fs/promises");
1931
+ const entries = await readdir6(terminalsDir, { withFileTypes: true });
1932
1932
  for (const entry of entries) {
1933
1933
  if (entry.isDirectory()) {
1934
1934
  const meta = await getMeta(entry.name, workingDirectory, sessionId);
@@ -2731,7 +2731,11 @@ async function createClient(serverId, handle, root) {
2731
2731
  dynamicRegistration: true
2732
2732
  },
2733
2733
  documentSymbol: {
2734
- dynamicRegistration: true
2734
+ dynamicRegistration: true,
2735
+ hierarchicalDocumentSymbolSupport: true,
2736
+ symbolKind: {
2737
+ valueSet: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
2738
+ }
2735
2739
  }
2736
2740
  },
2737
2741
  workspace: {
@@ -2828,7 +2832,7 @@ async function createClient(serverId, handle, root) {
2828
2832
  },
2829
2833
  async waitForDiagnostics(filePath, timeoutMs = 5e3) {
2830
2834
  const normalized = normalizePath(filePath);
2831
- return new Promise((resolve10) => {
2835
+ return new Promise((resolve11) => {
2832
2836
  const startTime = Date.now();
2833
2837
  let debounceTimer;
2834
2838
  let resolved = false;
@@ -2847,7 +2851,7 @@ async function createClient(serverId, handle, root) {
2847
2851
  if (resolved) return;
2848
2852
  resolved = true;
2849
2853
  cleanup();
2850
- resolve10(diagnostics.get(normalized) || []);
2854
+ resolve11(diagnostics.get(normalized) || []);
2851
2855
  };
2852
2856
  const onDiagnostic = () => {
2853
2857
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -2873,6 +2877,100 @@ async function createClient(serverId, handle, root) {
2873
2877
  getAllDiagnostics() {
2874
2878
  return new Map(diagnostics);
2875
2879
  },
2880
+ async getDefinition(filePath, line, character) {
2881
+ const normalized = normalizePath(filePath);
2882
+ if (!fileVersions.has(normalized)) {
2883
+ await client.notifyOpen(normalized);
2884
+ }
2885
+ try {
2886
+ const result = await connection.sendRequest("textDocument/definition", {
2887
+ textDocument: { uri: pathToFileURL(normalized).href },
2888
+ position: { line, character }
2889
+ });
2890
+ if (!result) return [];
2891
+ const items = Array.isArray(result) ? result : [result];
2892
+ return items.map((r) => ({
2893
+ uri: r.targetUri || r.uri,
2894
+ range: r.targetRange || r.range
2895
+ }));
2896
+ } catch (error) {
2897
+ console.error("[lsp] Error getting definition:", error);
2898
+ return [];
2899
+ }
2900
+ },
2901
+ async getReferences(filePath, line, character, includeDeclaration = false) {
2902
+ const normalized = normalizePath(filePath);
2903
+ if (!fileVersions.has(normalized)) {
2904
+ await client.notifyOpen(normalized);
2905
+ }
2906
+ try {
2907
+ const result = await connection.sendRequest("textDocument/references", {
2908
+ textDocument: { uri: pathToFileURL(normalized).href },
2909
+ position: { line, character },
2910
+ context: { includeDeclaration }
2911
+ });
2912
+ return result || [];
2913
+ } catch (error) {
2914
+ console.error("[lsp] Error getting references:", error);
2915
+ return [];
2916
+ }
2917
+ },
2918
+ async getHover(filePath, line, character) {
2919
+ const normalized = normalizePath(filePath);
2920
+ if (!fileVersions.has(normalized)) {
2921
+ await client.notifyOpen(normalized);
2922
+ }
2923
+ try {
2924
+ const result = await connection.sendRequest("textDocument/hover", {
2925
+ textDocument: { uri: pathToFileURL(normalized).href },
2926
+ position: { line, character }
2927
+ });
2928
+ if (!result || !result.contents) return null;
2929
+ if (typeof result.contents === "string") return result.contents;
2930
+ if (result.contents.value) return result.contents.value;
2931
+ if (Array.isArray(result.contents)) {
2932
+ return result.contents.map((c) => typeof c === "string" ? c : c.value).join("\n");
2933
+ }
2934
+ return null;
2935
+ } catch (error) {
2936
+ console.error("[lsp] Error getting hover:", error);
2937
+ return null;
2938
+ }
2939
+ },
2940
+ async getDocumentSymbols(filePath) {
2941
+ const normalized = normalizePath(filePath);
2942
+ if (!fileVersions.has(normalized)) {
2943
+ await client.notifyOpen(normalized);
2944
+ }
2945
+ try {
2946
+ const result = await connection.sendRequest("textDocument/documentSymbol", {
2947
+ textDocument: { uri: pathToFileURL(normalized).href }
2948
+ });
2949
+ if (!result || result.length === 0) return [];
2950
+ if (result[0].range) {
2951
+ return result;
2952
+ }
2953
+ return result.map((si) => ({
2954
+ name: si.name,
2955
+ kind: si.kind,
2956
+ range: si.location?.range ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
2957
+ selectionRange: si.location?.range ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
2958
+ detail: si.containerName
2959
+ }));
2960
+ } catch (error) {
2961
+ console.error("[lsp] Error getting document symbols:", error);
2962
+ return [];
2963
+ }
2964
+ },
2965
+ async findWorkspaceSymbols(query) {
2966
+ try {
2967
+ const result = await connection.sendRequest("workspace/symbol", { query });
2968
+ return result || [];
2969
+ } catch (error) {
2970
+ console.error("[lsp] Error finding workspace symbols:", error);
2971
+ return [];
2972
+ }
2973
+ },
2876
2974
  async shutdown() {
2877
2975
  try {
2878
2976
  await connection.sendRequest("shutdown");
@@ -2995,6 +3093,24 @@ async function getAllDiagnostics() {
2995
3093
  }
2996
3094
  return results;
2997
3095
  }
3096
+ async function getReferences(filePath, line, character, includeDeclaration = false) {
3097
+ const normalized = normalizePath(filePath);
3098
+ const client = await getClientForFile(normalized);
3099
+ if (!client) return [];
3100
+ return client.getReferences(normalized, line, character, includeDeclaration);
3101
+ }
3102
+ async function getHover(filePath, line, character) {
3103
+ const normalized = normalizePath(filePath);
3104
+ const client = await getClientForFile(normalized);
3105
+ if (!client) return null;
3106
+ return client.getHover(normalized, line, character);
3107
+ }
3108
+ async function getDocumentSymbols(filePath) {
3109
+ const normalized = normalizePath(filePath);
3110
+ const client = await getClientForFile(normalized);
3111
+ if (!client) return [];
3112
+ return client.getDocumentSymbols(normalized);
3113
+ }
2998
3114
  async function formatDiagnosticsOutput(filePath, options = {}) {
2999
3115
  const diagnostics = await getDiagnostics(filePath);
3000
3116
  return formatDiagnosticsForAgent(filePath, diagnostics, options);
@@ -3090,7 +3206,7 @@ Working directory: ${options.workingDirectory}`,
3090
3206
  isChunked: true
3091
3207
  });
3092
3208
  if (chunkCount > 1) {
3093
- await new Promise((resolve10) => setTimeout(resolve10, 0));
3209
+ await new Promise((resolve11) => setTimeout(resolve11, 0));
3094
3210
  }
3095
3211
  }
3096
3212
  }
@@ -3618,8 +3734,8 @@ ${file.relativePath}:`);
3618
3734
  }
3619
3735
 
3620
3736
  // src/tools/search.ts
3621
- import { tool as tool9 } from "ai";
3622
- import { z as z10 } from "zod";
3737
+ import { tool as tool10 } from "ai";
3738
+ import { z as z11 } from "zod";
3623
3739
 
3624
3740
  // src/agent/subagent.ts
3625
3741
  import {
@@ -3791,8 +3907,8 @@ var Subagent = class {
3791
3907
  if (eventQueue.length > 0) {
3792
3908
  yield eventQueue.shift();
3793
3909
  } else if (!done) {
3794
- const event = await new Promise((resolve10) => {
3795
- resolveNext = resolve10;
3910
+ const event = await new Promise((resolve11) => {
3911
+ resolveNext = resolve11;
3796
3912
  });
3797
3913
  if (event) {
3798
3914
  yield event;
@@ -3804,14 +3920,466 @@ var Subagent = class {
3804
3920
  };
3805
3921
 
3806
3922
  // src/agent/subagents/search.ts
3807
- import { tool as tool8 } from "ai";
3808
- import { z as z9 } from "zod";
3923
+ import { tool as tool9 } from "ai";
3924
+ import { z as z10 } from "zod";
3809
3925
  import { exec as exec4 } from "child_process";
3810
3926
  import { promisify as promisify4 } from "util";
3811
- import { readFile as readFile7, stat as stat3, readdir as readdir3 } from "fs/promises";
3812
- import { resolve as resolve8, relative as relative7, isAbsolute as isAbsolute4 } from "path";
3813
- import { existsSync as existsSync11 } from "fs";
3927
+ import { readFile as readFile8, stat as stat3, readdir as readdir4 } from "fs/promises";
3928
+ import { resolve as resolve9, relative as relative8, isAbsolute as isAbsolute5 } from "path";
3929
+ import { existsSync as existsSync12 } from "fs";
3814
3930
  init_semantic();
3931
+
3932
+ // src/tools/code-graph.ts
3933
+ import { tool as tool7 } from "ai";
3934
+ import { z as z8 } from "zod";
3935
+ import { resolve as resolve8, relative as relative7, isAbsolute as isAbsolute4, basename as basename3 } from "path";
3936
+ import { readFile as readFile7, readdir as readdir3 } from "fs/promises";
3937
+ import { existsSync as existsSync10 } from "fs";
3938
+ import { fileURLToPath as fileURLToPath2 } from "url";
3939
+ import { execFileSync } from "child_process";
3940
+ var codeGraphInputSchema = z8.object({
3941
+ symbol: z8.string().describe(
3942
+ "The symbol name to inspect (function, component, class, type, variable, etc.)"
3943
+ ),
3944
+ filePath: z8.string().optional().describe(
3945
+ "File path where the symbol is defined. If omitted, searches the workspace via grep."
3946
+ ),
3947
+ depth: z8.number().optional().default(2).describe(
3948
+ "How many levels of references to traverse upward (default: 2, max: 3). Level 1 = direct usages, level 2 = usages of those usages."
3949
+ )
3950
+ });
3951
+ function isPageFile(filePath) {
3952
+ const normalized = filePath.replace(/\\/g, "/");
3953
+ if (/\/app\/(.+\/)?(page|layout|loading|error|not-found)\.(tsx?|jsx?)$/.test(normalized)) return true;
3954
+ if (/\/pages\/(?!_|api\/).+\.(tsx?|jsx?)$/.test(normalized)) return true;
3955
+ return false;
3956
+ }
3957
+ function extractRoutePath(filePath, workingDirectory) {
3958
+ const rel = relative7(workingDirectory, filePath).replace(/\\/g, "/");
3959
+ const appMatch = rel.match(/(?:src\/)?app((?:\/[^/]+)*?)\/(?:page|layout|loading|error|not-found)\.\w+$/);
3960
+ if (appMatch) return appMatch[1] || "/";
3961
+ const pagesMatch = rel.match(/(?:src\/)?pages(\/.*?)(?:\/index)?\.\w+$/);
3962
+ if (pagesMatch) return pagesMatch[1] || "/";
3963
+ return void 0;
3964
+ }
3965
+ function symbolKindName(kind) {
3966
+ const names = {
3967
+ [5 /* Class */]: "class",
3968
+ [12 /* Function */]: "function",
3969
+ [6 /* Method */]: "method",
3970
+ [7 /* Property */]: "property",
3971
+ [13 /* Variable */]: "variable",
3972
+ [11 /* Interface */]: "interface",
3973
+ [10 /* Enum */]: "enum",
3974
+ [14 /* Constant */]: "constant",
3975
+ [9 /* Constructor */]: "constructor",
3976
+ [2 /* Module */]: "module",
3977
+ [3 /* Namespace */]: "namespace",
3978
+ [26 /* TypeParameter */]: "type_param",
3979
+ [8 /* Field */]: "field",
3980
+ [22 /* EnumMember */]: "enum_member",
3981
+ [19 /* Object */]: "object"
3982
+ };
3983
+ return names[kind] || "symbol";
3984
+ }
3985
+ function findContainingSymbol(symbols, line, character) {
3986
+ for (const sym of symbols) {
3987
+ if (!sym.range) continue;
3988
+ const { start, end } = sym.range;
3989
+ const afterStart = line > start.line || line === start.line && character >= start.character;
3990
+ const beforeEnd = line < end.line || line === end.line && character < end.character;
3991
+ if (afterStart && beforeEnd) {
3992
+ if (sym.children?.length) {
3993
+ const child = findContainingSymbol(sym.children, line, character);
3994
+ if (child) return child;
3995
+ }
3996
+ return sym;
3997
+ }
3998
+ }
3999
+ return null;
4000
+ }
4001
+ function findSymbolByName(symbols, name) {
4002
+ for (const sym of symbols) {
4003
+ if (sym.name === name && sym.selectionRange) return sym;
4004
+ if (sym.children) {
4005
+ const found = findSymbolByName(sym.children, name);
4006
+ if (found) return found;
4007
+ }
4008
+ }
4009
+ return null;
4010
+ }
4011
+ function cleanHoverText(text) {
4012
+ return text.replace(/```\w*\n?/g, "").replace(/\n```/g, "").trim();
4013
+ }
4014
+ async function grepForSymbol(symbol, workingDirectory) {
4015
+ const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4016
+ const rgPatterns = [
4017
+ `(export\\s+)?(default\\s+)?(function|const|let|var|class|interface|type|enum)\\s+${escaped}\\b`,
4018
+ `(export\\s+)?(default\\s+)?\\b${escaped}\\s*[=:(]`
4019
+ ];
4020
+ for (const pattern of rgPatterns) {
4021
+ try {
4022
+ const result = execFileSync("rg", [
4023
+ "-n",
4024
+ "--no-heading",
4025
+ "-e",
4026
+ pattern,
4027
+ "--glob",
4028
+ "*.{ts,tsx,js,jsx}",
4029
+ "-m",
4030
+ "5"
4031
+ ], {
4032
+ cwd: workingDirectory,
4033
+ encoding: "utf-8",
4034
+ timeout: 5e3,
4035
+ stdio: ["pipe", "pipe", "pipe"]
4036
+ }).trim();
4037
+ if (result) {
4038
+ const firstLine = result.split("\n")[0];
4039
+ const match = firstLine.match(/^(.+?):(\d+):(.*)/);
4040
+ if (match) {
4041
+ const col = match[3].indexOf(symbol);
4042
+ return {
4043
+ filePath: resolve8(workingDirectory, match[1]),
4044
+ line: parseInt(match[2]) - 1,
4045
+ char: col >= 0 ? col : 0
4046
+ };
4047
+ }
4048
+ }
4049
+ } catch {
4050
+ }
4051
+ }
4052
+ const defPattern = new RegExp(
4053
+ `(export|function|const|let|var|class|interface|type|enum)\\s+.*\\b${escaped}\\b`
4054
+ );
4055
+ const SUPPORTED_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
4056
+ const IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "coverage"]);
4057
+ async function search(dir, maxFiles) {
4058
+ if (maxFiles <= 0) return null;
4059
+ let remaining = maxFiles;
4060
+ try {
4061
+ const entries = await readdir3(dir, { withFileTypes: true });
4062
+ for (const entry of entries) {
4063
+ if (remaining <= 0) return null;
4064
+ const fullPath = resolve8(dir, entry.name);
4065
+ if (entry.isDirectory()) {
4066
+ if (IGNORED_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
4067
+ const found = await search(fullPath, remaining);
4068
+ if (found) return found;
4069
+ remaining -= 10;
4070
+ } else if (entry.isFile()) {
4071
+ const ext = entry.name.substring(entry.name.lastIndexOf("."));
4072
+ if (!SUPPORTED_EXTS.has(ext)) continue;
4073
+ remaining--;
4074
+ const content = await readFile7(fullPath, "utf-8");
4075
+ const lines = content.split("\n");
4076
+ for (let i = 0; i < lines.length; i++) {
4077
+ if (defPattern.test(lines[i])) {
4078
+ const col = lines[i].indexOf(symbol);
4079
+ if (col >= 0) {
4080
+ return { filePath: fullPath, line: i, char: col };
4081
+ }
4082
+ }
4083
+ }
4084
+ }
4085
+ }
4086
+ } catch {
4087
+ }
4088
+ return null;
4089
+ }
4090
+ return search(workingDirectory, 200);
4091
+ }
4092
+ var MAX_REF_FILES = 15;
4093
+ var MAX_LEVEL2_PARENTS = 8;
4094
+ var MAX_LEVEL2_SYMBOLS_PER_PARENT = 3;
4095
+ function createCodeGraphTool(options) {
4096
+ return tool7({
4097
+ description: `Inspect a symbol's type information and usage graph using the TypeScript language server.
4098
+
4099
+ Given a symbol name (function, component, class, type, etc.), this tool will:
4100
+ 1. Find its definition and full type signature (parameters, return type)
4101
+ 2. Find all references \u2014 what components/functions/files use this symbol
4102
+ 3. Identify which pages/routes contain it in their component tree
4103
+ 4. Show the file's symbol structure for surrounding context
4104
+
4105
+ Use this to understand:
4106
+ - Component hierarchies (what renders what, which pages are affected)
4107
+ - Type signatures and parameter/return types before making changes
4108
+ - How deeply a symbol is used across the codebase
4109
+ - What will break if you change something
4110
+
4111
+ Supports TypeScript, JavaScript, TSX, JSX files.
4112
+ Working directory: ${options.workingDirectory}`,
4113
+ inputSchema: codeGraphInputSchema,
4114
+ execute: async ({ symbol, filePath, depth }) => {
4115
+ const maxDepth = Math.min(depth ?? 2, 3);
4116
+ try {
4117
+ let defFilePath;
4118
+ let defLine = 0;
4119
+ let defChar = 0;
4120
+ let defSymbol = null;
4121
+ if (filePath) {
4122
+ const absPath = isAbsolute4(filePath) ? filePath : resolve8(options.workingDirectory, filePath);
4123
+ if (!existsSync10(absPath)) {
4124
+ return { success: false, error: `File not found: ${filePath}` };
4125
+ }
4126
+ if (!isSupported(absPath)) {
4127
+ return { success: false, error: `File type not supported. Supports: ${getSupportedExtensions().join(", ")}` };
4128
+ }
4129
+ await touchFile(absPath, true);
4130
+ const symbols = await getDocumentSymbols(absPath);
4131
+ defSymbol = findSymbolByName(symbols, symbol);
4132
+ if (defSymbol) {
4133
+ defFilePath = absPath;
4134
+ defLine = defSymbol.selectionRange.start.line;
4135
+ defChar = defSymbol.selectionRange.start.character;
4136
+ } else {
4137
+ const content = await readFile7(absPath, "utf-8");
4138
+ const lines2 = content.split("\n");
4139
+ const defPattern = new RegExp(
4140
+ `(export|function|const|let|var|class|interface|type|enum)\\s+.*\\b${symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`
4141
+ );
4142
+ for (let i = 0; i < lines2.length; i++) {
4143
+ if (defPattern.test(lines2[i])) {
4144
+ const col = lines2[i].indexOf(symbol);
4145
+ if (col !== -1) {
4146
+ defFilePath = absPath;
4147
+ defLine = i;
4148
+ defChar = col;
4149
+ break;
4150
+ }
4151
+ }
4152
+ }
4153
+ if (!defFilePath) {
4154
+ for (let i = 0; i < lines2.length; i++) {
4155
+ const col = lines2[i].indexOf(symbol);
4156
+ if (col !== -1) {
4157
+ defFilePath = absPath;
4158
+ defLine = i;
4159
+ defChar = col;
4160
+ break;
4161
+ }
4162
+ }
4163
+ }
4164
+ }
4165
+ } else {
4166
+ const found = await grepForSymbol(symbol, options.workingDirectory);
4167
+ if (found) {
4168
+ defFilePath = found.filePath;
4169
+ defLine = found.line;
4170
+ defChar = found.char;
4171
+ }
4172
+ }
4173
+ if (!defFilePath) {
4174
+ return {
4175
+ success: false,
4176
+ error: `Could not find symbol "${symbol}" in the codebase. Try providing a filePath.`
4177
+ };
4178
+ }
4179
+ await touchFile(defFilePath, true);
4180
+ const rawHover = await getHover(defFilePath, defLine, defChar);
4181
+ const typeInfo = rawHover ? cleanHoverText(rawHover) : null;
4182
+ const fileSymbols = await getDocumentSymbols(defFilePath);
4183
+ if (!defSymbol && fileSymbols.length > 0) {
4184
+ defSymbol = findSymbolByName(fileSymbols, symbol);
4185
+ }
4186
+ const references = await getReferences(defFilePath, defLine, defChar, false);
4187
+ const refsByFile = /* @__PURE__ */ new Map();
4188
+ for (const ref of references) {
4189
+ const refPath = fileURLToPath2(ref.uri);
4190
+ if (!refsByFile.has(refPath)) {
4191
+ refsByFile.set(refPath, []);
4192
+ }
4193
+ refsByFile.get(refPath).push(ref);
4194
+ }
4195
+ const refFileInfos = [];
4196
+ let processed = 0;
4197
+ for (const [refPath, locs] of refsByFile) {
4198
+ if (processed >= MAX_REF_FILES) break;
4199
+ if (refPath === defFilePath) continue;
4200
+ processed++;
4201
+ const relPath = relative7(options.workingDirectory, refPath);
4202
+ const pageFile = isPageFile(refPath);
4203
+ const routePath = pageFile ? extractRoutePath(refPath, options.workingDirectory) : void 0;
4204
+ await touchFile(refPath, false);
4205
+ const refFileSymbols = await getDocumentSymbols(refPath);
4206
+ const seen = /* @__PURE__ */ new Map();
4207
+ for (const loc of locs) {
4208
+ const container = findContainingSymbol(
4209
+ refFileSymbols,
4210
+ loc.range.start.line,
4211
+ loc.range.start.character
4212
+ );
4213
+ if (container && !seen.has(container.name)) {
4214
+ let containerHover = null;
4215
+ try {
4216
+ const raw = await getHover(
4217
+ refPath,
4218
+ container.selectionRange.start.line,
4219
+ container.selectionRange.start.character
4220
+ );
4221
+ if (raw) containerHover = cleanHoverText(raw).split("\n")[0];
4222
+ } catch {
4223
+ }
4224
+ seen.set(container.name, {
4225
+ name: container.name,
4226
+ kind: symbolKindName(container.kind),
4227
+ line: container.selectionRange.start.line + 1,
4228
+ char: container.selectionRange.start.character,
4229
+ typeInfo: containerHover || void 0
4230
+ });
4231
+ }
4232
+ }
4233
+ refFileInfos.push({
4234
+ filePath: refPath,
4235
+ relativePath: relPath,
4236
+ isPage: pageFile,
4237
+ routePath,
4238
+ containingSymbols: Array.from(seen.values())
4239
+ });
4240
+ }
4241
+ const level2Refs = [];
4242
+ if (maxDepth >= 2) {
4243
+ for (const refFile of refFileInfos.slice(0, MAX_LEVEL2_PARENTS)) {
4244
+ for (const sym of refFile.containingSymbols.slice(0, MAX_LEVEL2_SYMBOLS_PER_PARENT)) {
4245
+ try {
4246
+ const symLineIdx = sym.line - 1;
4247
+ const symChar = sym.char;
4248
+ const l2Locations = await getReferences(
4249
+ refFile.filePath,
4250
+ symLineIdx,
4251
+ symChar,
4252
+ false
4253
+ );
4254
+ const l2Nodes = [];
4255
+ const seenPaths = /* @__PURE__ */ new Set();
4256
+ for (const loc of l2Locations.slice(0, 10)) {
4257
+ const l2Path = fileURLToPath2(loc.uri);
4258
+ if (l2Path === refFile.filePath || l2Path === defFilePath) continue;
4259
+ if (seenPaths.has(l2Path)) continue;
4260
+ seenPaths.add(l2Path);
4261
+ const l2Rel = relative7(options.workingDirectory, l2Path);
4262
+ const l2Page = isPageFile(l2Path);
4263
+ const l2Route = l2Page ? extractRoutePath(l2Path, options.workingDirectory) : void 0;
4264
+ let containerName;
4265
+ try {
4266
+ await touchFile(l2Path, false);
4267
+ const l2Symbols = await getDocumentSymbols(l2Path);
4268
+ const container = findContainingSymbol(l2Symbols, loc.range.start.line, loc.range.start.character);
4269
+ if (container) containerName = container.name;
4270
+ } catch {
4271
+ }
4272
+ l2Nodes.push({
4273
+ relativePath: l2Rel,
4274
+ isPage: l2Page,
4275
+ routePath: l2Route,
4276
+ containingSymbol: containerName
4277
+ });
4278
+ }
4279
+ if (l2Nodes.length > 0) {
4280
+ level2Refs.push({
4281
+ parentSymbol: sym.name,
4282
+ parentFile: refFile.relativePath,
4283
+ refs: l2Nodes
4284
+ });
4285
+ }
4286
+ } catch {
4287
+ }
4288
+ }
4289
+ }
4290
+ }
4291
+ const relDefPath = relative7(options.workingDirectory, defFilePath);
4292
+ const lines = [];
4293
+ lines.push(`=== ${symbol} ===`);
4294
+ lines.push(`File: ${relDefPath}:${defLine + 1}`);
4295
+ if (defSymbol) lines.push(`Kind: ${symbolKindName(defSymbol.kind)}`);
4296
+ if (typeInfo) lines.push(`Type: ${typeInfo}`);
4297
+ const externalRefCount = references.filter((r) => fileURLToPath2(r.uri) !== defFilePath).length;
4298
+ const externalFileCount = refsByFile.size - (refsByFile.has(defFilePath) ? 1 : 0);
4299
+ if (refFileInfos.length > 0) {
4300
+ lines.push("");
4301
+ lines.push(`=== Referenced by (${externalRefCount} usages across ${externalFileCount} files) ===`);
4302
+ const pages = refFileInfos.filter((r) => r.isPage);
4303
+ const nonPages = refFileInfos.filter((r) => !r.isPage);
4304
+ if (pages.length > 0) {
4305
+ lines.push("");
4306
+ lines.push("Pages/Routes:");
4307
+ for (const page of pages) {
4308
+ lines.push(` ${page.relativePath}${page.routePath ? ` \u2192 ${page.routePath}` : ""}`);
4309
+ for (const s of page.containingSymbols) {
4310
+ lines.push(` \u2514\u2500\u2500 ${s.name} (${s.kind}:${s.line})${s.typeInfo ? ` \u2014 ${s.typeInfo}` : ""}`);
4311
+ }
4312
+ }
4313
+ }
4314
+ if (nonPages.length > 0) {
4315
+ lines.push("");
4316
+ lines.push("Components/Functions:");
4317
+ for (const ref of nonPages) {
4318
+ lines.push(` ${ref.relativePath}`);
4319
+ for (const s of ref.containingSymbols) {
4320
+ const typePart = s.typeInfo && s.typeInfo.length < 120 ? ` \u2014 ${s.typeInfo}` : "";
4321
+ lines.push(` \u2514\u2500\u2500 ${s.name} (${s.kind}:${s.line})${typePart}`);
4322
+ }
4323
+ }
4324
+ }
4325
+ } else {
4326
+ lines.push("");
4327
+ lines.push("No external references found (symbol may be unused or only used within the same file).");
4328
+ }
4329
+ if (level2Refs.length > 0) {
4330
+ lines.push("");
4331
+ lines.push("=== Extended tree (level 2) ===");
4332
+ for (const l2 of level2Refs) {
4333
+ lines.push("");
4334
+ lines.push(`${l2.parentSymbol} (${l2.parentFile}) is used by:`);
4335
+ for (const ref of l2.refs) {
4336
+ const tag = ref.isPage ? " [PAGE]" : "";
4337
+ const route = ref.routePath ? ` \u2192 ${ref.routePath}` : "";
4338
+ const container = ref.containingSymbol ? ` in ${ref.containingSymbol}` : "";
4339
+ lines.push(` \u2514\u2500\u2500 ${ref.relativePath}${tag}${route}${container}`);
4340
+ }
4341
+ }
4342
+ }
4343
+ if (fileSymbols.length > 0) {
4344
+ lines.push("");
4345
+ lines.push(`=== File structure (${basename3(defFilePath)}) ===`);
4346
+ for (const sym of fileSymbols) {
4347
+ const marker = sym.name === symbol ? " \u2190 target" : "";
4348
+ lines.push(` ${sym.name} (${symbolKindName(sym.kind)}:${sym.selectionRange.start.line + 1})${marker}`);
4349
+ if (sym.children) {
4350
+ for (const child of sym.children.slice(0, 10)) {
4351
+ lines.push(` \u2514\u2500\u2500 ${child.name} (${symbolKindName(child.kind)}:${child.selectionRange.start.line + 1})`);
4352
+ }
4353
+ if (sym.children.length > 10) {
4354
+ lines.push(` ... and ${sym.children.length - 10} more`);
4355
+ }
4356
+ }
4357
+ }
4358
+ }
4359
+ const formattedResult = lines.join("\n");
4360
+ return {
4361
+ success: true,
4362
+ symbol,
4363
+ filePath: relDefPath,
4364
+ line: defLine + 1,
4365
+ kind: defSymbol ? symbolKindName(defSymbol.kind) : void 0,
4366
+ typeInfo: typeInfo || void 0,
4367
+ referenceCount: externalRefCount,
4368
+ referenceFiles: externalFileCount,
4369
+ pages: refFileInfos.filter((r) => r.isPage).map((r) => ({ path: r.relativePath, route: r.routePath })),
4370
+ formattedResult
4371
+ };
4372
+ } catch (error) {
4373
+ return {
4374
+ success: false,
4375
+ error: error instanceof Error ? error.message : String(error)
4376
+ };
4377
+ }
4378
+ }
4379
+ });
4380
+ }
4381
+
4382
+ // src/agent/subagents/search.ts
3815
4383
  var execAsync4 = promisify4(exec4);
3816
4384
  var MAX_OUTPUT_CHARS4 = 1e4;
3817
4385
  var MAX_FILE_SIZE3 = 1 * 1024 * 1024;
@@ -3841,17 +4409,20 @@ ${contextBlock}
3841
4409
  - **glob**: Find files matching a name pattern. Best for file discovery.
3842
4410
  - **read_file**: Read contents of a specific file. Use to examine code found in searches.
3843
4411
  - **list_dir**: List directory contents. Use to understand project structure.
4412
+ - **code_graph**: Inspect a symbol's type hierarchy, references, and usage graph via the TypeScript language server. Returns type signatures, all files that reference the symbol, and which pages/routes contain it. Best for understanding component/function relationships and impact analysis.
3844
4413
 
3845
4414
  ## Search Strategy
3846
4415
 
3847
4416
  1. **Start with semantic_search** if available - it finds code by meaning, which is the fastest way to explore
3848
4417
  2. **Use grep** for exact symbol/string matches (function names, class names, imports)
3849
- 3. **Use glob** for file discovery by name patterns
3850
- 4. **Read key files** to get actual code content and understand context
3851
- 5. **Run searches in PARALLEL** - make multiple tool calls at once to cover different angles simultaneously. This is critical for speed.
4418
+ 3. **Use code_graph** when you need to understand a symbol's type signature, what depends on it, or which pages use it. It's much more precise than grep for understanding relationships.
4419
+ 4. **Use glob** for file discovery by name patterns
4420
+ 5. **Read key files** to get actual code content and understand context
4421
+ 6. **Run searches in PARALLEL** - make multiple tool calls at once to cover different angles simultaneously. This is critical for speed.
3852
4422
 
3853
4423
  ### Tool Selection Guide
3854
4424
  - Know the exact name? Use **grep** (e.g. \`getUserById\`, \`class AuthService\`)
4425
+ - Need type info, references, or impact analysis? Use **code_graph** (e.g. \`code_graph({ symbol: "UserCard" })\`)
3855
4426
  - Exploring a concept? Use **semantic_search** (e.g. "how does authentication work")
3856
4427
  - Looking for files? Use **glob** (e.g. \`**/*.config.ts\`, \`**/auth/**\`)
3857
4428
  - Need file content? Use **read_file** with optional line ranges for large files
@@ -3888,17 +4459,17 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
3888
4459
  async getToolsAsync(options) {
3889
4460
  const workingDirectory = options.workingDirectory;
3890
4461
  const tools = {
3891
- grep: tool8({
4462
+ grep: tool9({
3892
4463
  description: "Search for patterns in files using ripgrep. Returns matching lines with file paths and line numbers.",
3893
- inputSchema: z9.object({
3894
- pattern: z9.string().describe("The regex pattern to search for"),
3895
- path: z9.string().optional().describe("Subdirectory or file to search in (relative to working directory)"),
3896
- fileType: z9.string().optional().describe('File type to filter (e.g., "ts", "js", "py")'),
3897
- maxResults: z9.number().optional().default(50).describe("Maximum number of results to return")
4464
+ inputSchema: z10.object({
4465
+ pattern: z10.string().describe("The regex pattern to search for"),
4466
+ path: z10.string().optional().describe("Subdirectory or file to search in (relative to working directory)"),
4467
+ fileType: z10.string().optional().describe('File type to filter (e.g., "ts", "js", "py")'),
4468
+ maxResults: z10.number().optional().default(50).describe("Maximum number of results to return")
3898
4469
  }),
3899
4470
  execute: async ({ pattern, path, fileType, maxResults }) => {
3900
4471
  try {
3901
- const searchPath = path ? resolve8(workingDirectory, path) : workingDirectory;
4472
+ const searchPath = path ? resolve9(workingDirectory, path) : workingDirectory;
3902
4473
  let args = ["rg", "--line-number", "--no-heading"];
3903
4474
  if (fileType) {
3904
4475
  args.push("--type", fileType);
@@ -3935,11 +4506,11 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
3935
4506
  }
3936
4507
  }
3937
4508
  }),
3938
- glob: tool8({
4509
+ glob: tool9({
3939
4510
  description: "Find files matching a glob pattern. Returns list of matching file paths.",
3940
- inputSchema: z9.object({
3941
- pattern: z9.string().describe('Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json")'),
3942
- maxResults: z9.number().optional().default(100).describe("Maximum number of files to return")
4511
+ inputSchema: z10.object({
4512
+ pattern: z10.string().describe('Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json")'),
4513
+ maxResults: z10.number().optional().default(100).describe("Maximum number of files to return")
3943
4514
  }),
3944
4515
  execute: async ({ pattern, maxResults }) => {
3945
4516
  try {
@@ -3966,17 +4537,17 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
3966
4537
  }
3967
4538
  }
3968
4539
  }),
3969
- read_file: tool8({
4540
+ read_file: tool9({
3970
4541
  description: "Read the contents of a file. Use this to examine specific files found in search.",
3971
- inputSchema: z9.object({
3972
- path: z9.string().describe("Path to the file (relative to working directory or absolute)"),
3973
- startLine: z9.number().optional().describe("Start reading from this line (1-indexed)"),
3974
- endLine: z9.number().optional().describe("Stop reading at this line (1-indexed, inclusive)")
4542
+ inputSchema: z10.object({
4543
+ path: z10.string().describe("Path to the file (relative to working directory or absolute)"),
4544
+ startLine: z10.number().optional().describe("Start reading from this line (1-indexed)"),
4545
+ endLine: z10.number().optional().describe("Stop reading at this line (1-indexed, inclusive)")
3975
4546
  }),
3976
4547
  execute: async ({ path, startLine, endLine }) => {
3977
4548
  try {
3978
- const absolutePath = isAbsolute4(path) ? path : resolve8(workingDirectory, path);
3979
- if (!existsSync11(absolutePath)) {
4549
+ const absolutePath = isAbsolute5(path) ? path : resolve9(workingDirectory, path);
4550
+ if (!existsSync12(absolutePath)) {
3980
4551
  return {
3981
4552
  success: false,
3982
4553
  error: `File not found: ${path}`
@@ -3989,7 +4560,7 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
3989
4560
  error: `File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Use startLine/endLine to read portions.`
3990
4561
  };
3991
4562
  }
3992
- let content = await readFile7(absolutePath, "utf-8");
4563
+ let content = await readFile8(absolutePath, "utf-8");
3993
4564
  if (startLine !== void 0 || endLine !== void 0) {
3994
4565
  const lines = content.split("\n");
3995
4566
  const start = (startLine ?? 1) - 1;
@@ -3998,7 +4569,7 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
3998
4569
  }
3999
4570
  return {
4000
4571
  success: true,
4001
- path: relative7(workingDirectory, absolutePath),
4572
+ path: relative8(workingDirectory, absolutePath),
4002
4573
  content: truncateOutput(content, MAX_OUTPUT_CHARS4),
4003
4574
  lineCount: content.split("\n").length
4004
4575
  };
@@ -4010,17 +4581,17 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
4010
4581
  }
4011
4582
  }
4012
4583
  }),
4013
- list_dir: tool8({
4584
+ list_dir: tool9({
4014
4585
  description: "List contents of a directory. Shows files and subdirectories.",
4015
- inputSchema: z9.object({
4016
- path: z9.string().optional().default(".").describe("Directory path (relative to working directory)"),
4017
- recursive: z9.boolean().optional().default(false).describe("List recursively (be careful with large directories)"),
4018
- maxDepth: z9.number().optional().default(2).describe("Maximum depth for recursive listing")
4586
+ inputSchema: z10.object({
4587
+ path: z10.string().optional().default(".").describe("Directory path (relative to working directory)"),
4588
+ recursive: z10.boolean().optional().default(false).describe("List recursively (be careful with large directories)"),
4589
+ maxDepth: z10.number().optional().default(2).describe("Maximum depth for recursive listing")
4019
4590
  }),
4020
4591
  execute: async ({ path, recursive, maxDepth }) => {
4021
4592
  try {
4022
- const absolutePath = isAbsolute4(path) ? path : resolve8(workingDirectory, path);
4023
- if (!existsSync11(absolutePath)) {
4593
+ const absolutePath = isAbsolute5(path) ? path : resolve9(workingDirectory, path);
4594
+ if (!existsSync12(absolutePath)) {
4024
4595
  return {
4025
4596
  success: false,
4026
4597
  error: `Directory not found: ${path}`
@@ -4044,20 +4615,20 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
4044
4615
  const files = stdout.trim().split("\n").filter(Boolean);
4045
4616
  return {
4046
4617
  success: true,
4047
- path: relative7(workingDirectory, absolutePath) || ".",
4618
+ path: relative8(workingDirectory, absolutePath) || ".",
4048
4619
  files,
4049
4620
  count: files.length,
4050
4621
  recursive: true
4051
4622
  };
4052
4623
  } else {
4053
- const entries = await readdir3(absolutePath, { withFileTypes: true });
4624
+ const entries = await readdir4(absolutePath, { withFileTypes: true });
4054
4625
  const items = entries.slice(0, 200).map((e) => ({
4055
4626
  name: e.name,
4056
4627
  type: e.isDirectory() ? "directory" : "file"
4057
4628
  }));
4058
4629
  return {
4059
4630
  success: true,
4060
- path: relative7(workingDirectory, absolutePath) || ".",
4631
+ path: relative8(workingDirectory, absolutePath) || ".",
4061
4632
  items,
4062
4633
  count: items.length
4063
4634
  };
@@ -4069,6 +4640,9 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
4069
4640
  };
4070
4641
  }
4071
4642
  }
4643
+ }),
4644
+ code_graph: createCodeGraphTool({
4645
+ workingDirectory
4072
4646
  })
4073
4647
  };
4074
4648
  try {
@@ -4162,6 +4736,26 @@ Keep it concise but INCLUDE THE ACTUAL DATA.`;
4162
4736
  context: m.symbolName || m.language
4163
4737
  });
4164
4738
  }
4739
+ } else if (step.toolName === "code_graph" && output.success) {
4740
+ matchCount += output.referenceCount || 0;
4741
+ if (output.filePath) {
4742
+ findings.push({
4743
+ type: "file",
4744
+ path: output.filePath,
4745
+ lineNumber: output.line,
4746
+ content: output.typeInfo ? truncateOutput(output.typeInfo, 300) : void 0,
4747
+ relevance: "high",
4748
+ context: `${output.kind || "symbol"}${output.referenceCount ? `, ${output.referenceCount} refs` : ""}`
4749
+ });
4750
+ }
4751
+ for (const page of (output.pages || []).slice(0, 10)) {
4752
+ findings.push({
4753
+ type: "file",
4754
+ path: page.path,
4755
+ relevance: "high",
4756
+ context: page.route ? `route: ${page.route}` : "page"
4757
+ });
4758
+ }
4165
4759
  }
4166
4760
  }
4167
4761
  }
@@ -4183,7 +4777,7 @@ function createSearchSubagent(model) {
4183
4777
  // src/tools/search.ts
4184
4778
  var MAX_RESULT_CHARS = 1e4;
4185
4779
  function createSearchTool(options) {
4186
- return tool9({
4780
+ return tool10({
4187
4781
  description: `Delegate an explore task to the explore_agent tool. Use this when you need to:
4188
4782
  - Find files or code matching a pattern
4189
4783
  - Explore the codebase structure
@@ -4193,11 +4787,12 @@ function createSearchTool(options) {
4193
4787
  The Explore agent will explore the codebase and return a summary of findings.
4194
4788
  This is more thorough than a simple grep because it can follow references and understand context.
4195
4789
  It also has access to semantic search to find code by meaning, not just text.
4790
+ It can also use code_graph to inspect a symbol's type hierarchy, references, and which pages/routes use it.
4196
4791
 
4197
4792
  CRITICAL: The explore agent has ZERO context. It cannot see the conversation, the user's message, devtools data, or any prior context. You MUST pass ALL relevant context via the "context" parameter. If the user selected a component (component name, file path, HTML, component stack) or there is a <devtools-context> block, you MUST copy that information into the "context" field verbatim. Without it the explore agent is searching blind.`,
4198
- inputSchema: z10.object({
4199
- query: z10.string().describe("What to search for. Be specific about what you're looking for."),
4200
- context: z10.string().describe("ALL context the explore agent needs. It has ZERO context on its own - no conversation history, no devtools data, nothing. You MUST include: any selected component info (name, file path, HTML, component stack), any <devtools-context> block (page URL, path, viewport), and any other relevant details from the user message. The explore agent literally only sees the query and this context field.")
4793
+ inputSchema: z11.object({
4794
+ query: z11.string().describe("What to search for. Be specific about what you're looking for."),
4795
+ context: z11.string().describe("ALL context the explore agent needs. It has ZERO context on its own - no conversation history, no devtools data, nothing. You MUST include: any selected component info (name, file path, HTML, component stack), any <devtools-context> block (page URL, path, viewport), and any other relevant details from the user message. The explore agent literally only sees the query and this context field.")
4201
4796
  }),
4202
4797
  execute: async ({ query, context }, toolOptions) => {
4203
4798
  const toolCallId = toolOptions.toolCallId || `explore_agent_${Date.now()}`;
@@ -4341,6 +4936,9 @@ async function createTools(options) {
4341
4936
  sessionId: options.sessionId,
4342
4937
  workingDirectory: options.workingDirectory,
4343
4938
  onProgress: options.onSearchProgress
4939
+ }),
4940
+ code_graph: createCodeGraphTool({
4941
+ workingDirectory: options.workingDirectory
4344
4942
  })
4345
4943
  };
4346
4944
  if (options.enableSemanticSearch !== false) {
@@ -4432,6 +5030,7 @@ You have access to powerful tools for:
4432
5030
  - **todo**: Manage your task list to track progress on complex operations
4433
5031
  - **load_skill**: Load specialized knowledge documents for specific tasks
4434
5032
  - **explore_agent**: Explore agent for semantic discovery - for exploratory questions and finding code by meaning
5033
+ - **code_graph**: Inspect a symbol's type hierarchy and usage graph via the TypeScript language server
4435
5034
 
4436
5035
 
4437
5036
  IMPORTANT: If you have zero context of where you are working, always explore it first to understand the structure before doing things for the user.
@@ -4521,6 +5120,33 @@ linter({ paths: ["src/"] }) // Check all files in a directory
4521
5120
  \`\`\`
4522
5121
  Use this proactively after making code changes to catch errors early.
4523
5122
 
5123
+ ### Code Graph Tool
5124
+ The code_graph tool uses the TypeScript language server to inspect a symbol's type hierarchy and usage graph:
5125
+ \`\`\`
5126
+ code_graph({ symbol: "UserCard" }) // Search workspace for symbol
5127
+ code_graph({ symbol: "UserCard", filePath: "src/components.tsx" }) // Look up in a specific file
5128
+ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Traverse 2 levels up the reference tree
5129
+ \`\`\`
5130
+
5131
+ **What it returns:**
5132
+ - The symbol's full type signature (parameters, return type)
5133
+ - All files/functions/components that reference it (grouped into pages vs components)
5134
+ - Which Next.js pages/routes contain it in their component tree
5135
+ - Level-2 transitive usages (who uses the things that use this symbol)
5136
+ - The file's symbol structure for surrounding context
5137
+
5138
+ **When to use code_graph:**
5139
+ - **To locate a component/function by name** when you don't have the file path \u2014 e.g. a user mentions a component from devtools but the path is missing or mangled. Just pass the symbol name and it will find the definition.
5140
+ - **Before making changes** to a function/component \u2014 understand what depends on it and what will break
5141
+ - **To understand component hierarchies** \u2014 what renders what, which pages are affected across the *entire* codebase (not just the current page)
5142
+ - **To get type signatures** (props, params, return types) without reading entire files
5143
+ - **After a devtools selection** when the task involves refactoring, changing props, or anything that could impact other consumers
5144
+
5145
+ **When NOT to use code_graph:**
5146
+ - For exploratory "how does X work?" questions \u2014 use \`explore_agent\` instead
5147
+ - For exact string searches \u2014 use grep/rg directly
5148
+ - For non-TypeScript/JavaScript files \u2014 code_graph only supports TS/JS/TSX/JSX
5149
+
4524
5150
  ### Searching and Exploration
4525
5151
 
4526
5152
  **Choose the right search approach:**
@@ -4528,7 +5154,8 @@ Use this proactively after making code changes to catch errors early.
4528
5154
  0. **Use paths to your advantage \u2014 skip searching if you already have what you need.**
4529
5155
  - If the user selected a component via devtools and you can see the component name, file path, and/or line number, you ALREADY know where the code is. Just use \`read_file\` to read that file directly \u2014 do NOT call \`explore_agent\` to "find" something you already have the location of.
4530
5156
  - If you received a **page path** (e.g. \`/dashboard\`, \`/settings/profile\`), map it to the corresponding file in the project structure. In Next.js this means \`app/dashboard/page.tsx\`, \`app/settings/profile/page.tsx\`, etc. In other frameworks, check the routing convention (e.g. \`pages/\`, \`src/routes/\`). Use \`read_file\` on the mapped path directly.
4531
- - If the file path doesn't exist or \`read_file\` fails, fall back to grep to locate it (e.g. \`rg "ComponentName" --type ts -l\`) since devtools paths can sometimes be slightly off or truncated.
5157
+ - **If the file path is missing, truncated, or doesn't exist** (common with devtools \u2014 webpack paths can be mangled), use \`code_graph({ symbol: "ComponentName" })\` to locate the component. This searches the workspace for the symbol definition AND returns its type info, references, and page locations in one call \u2014 much better than raw grep for components.
5158
+ - **After reading a devtools-selected component**, if the task involves changes that could affect other consumers (refactoring, changing props, renaming), use \`code_graph\` to see ALL files and pages that depend on it \u2014 the devtools component stack only shows the current page's hierarchy, not the full picture.
4532
5159
  - Read up and down component trees when you have the file path or page path to find what you're looking for.
4533
5160
  1. **Use the \`explore_agent\` tool (Explore agent)** for:
4534
5161
  - Semantic/exploratory questions: "How does authentication work?", "Where is user data processed?"
@@ -4546,7 +5173,14 @@ Use this proactively after making code changes to catch errors early.
4546
5173
  - If you skip the \`context\` field, the explore agent is searching completely blind and will waste time guessing.
4547
5174
  - NEVER call \`explore_agent\` with only a \`query\` and no \`context\` when the user's message contains devtools or component information.
4548
5175
 
4549
- 2. **Use direct commands (grep/rg, find)** for:
5176
+ 2. **Use the \`code_graph\` tool** for:
5177
+ - Understanding what depends on a specific symbol before changing it
5178
+ - Tracing component/function usage up to page-level routes
5179
+ - Getting type signatures (params, return types) without reading full files
5180
+ - Finding exact components usages in the codebase
5181
+ - Answering "what will break if I change this?" or "which pages use this component?"
5182
+
5183
+ 3. **Use direct commands (grep/rg, find)** for:
4550
5184
  - Exact string matches: \`rg "functionName"\`, \`rg "class MyClass"\`
4551
5185
  - Finding files by name: \`find . -name "*.config.ts"\`
4552
5186
  - Simple pattern matching when you know exactly what you're looking for
@@ -4554,7 +5188,11 @@ Use this proactively after making code changes to catch errors early.
4554
5188
 
4555
5189
  **Examples:**
4556
5190
  - User selected \`<LandingButton>\` at \`src/components/LandingButton.tsx:12\` \u2192 Just \`read_file("src/components/LandingButton.tsx")\`. Do NOT call explore_agent.
5191
+ - User selected \`<PricingCard>\` but no file path in the component stack \u2192 Use \`code_graph({ symbol: "PricingCard" })\` to find its definition, type info, and all usages at once.
5192
+ - User selected \`<UserCard>\` and says "refactor the props" \u2192 First \`read_file\` the component, then \`code_graph({ symbol: "UserCard" })\` to see every file/page that depends on it before changing the interface.
4557
5193
  - "Where is the API authentication handled?" (no file path given) \u2192 Use \`explore_agent\` tool
5194
+ - "What pages use the UserCard component?" \u2192 Use \`code_graph({ symbol: "UserCard" })\`
5195
+ - "What's the type signature of formatUser?" \u2192 Use \`code_graph({ symbol: "formatUser", filePath: "utils.ts" })\`
4558
5196
  - "Find all usages of getUserById" \u2192 Use \`rg "getUserById"\`
4559
5197
  - "How does the payment flow work?" \u2192 Use \`explore_agent\` tool
4560
5198
  - "Find files named config" \u2192 Use \`find . -name "*config*"\`
@@ -5126,9 +5764,9 @@ ${prompt}` });
5126
5764
  wrappedTools[name] = originalTool;
5127
5765
  continue;
5128
5766
  }
5129
- wrappedTools[name] = tool10({
5767
+ wrappedTools[name] = tool11({
5130
5768
  description: originalTool.description || "",
5131
- inputSchema: originalTool.inputSchema || z11.object({}),
5769
+ inputSchema: originalTool.inputSchema || z12.object({}),
5132
5770
  execute: async (input, toolOptions) => {
5133
5771
  const toolCallId = toolOptions.toolCallId || nanoid3();
5134
5772
  const execution = toolExecutionQueries.create({
@@ -5142,8 +5780,8 @@ ${prompt}` });
5142
5780
  this.pendingApprovals.set(toolCallId, await execution);
5143
5781
  options.onApprovalRequired?.(await execution);
5144
5782
  await sessionQueries.updateStatus(this.session.id, "waiting");
5145
- const approved = await new Promise((resolve10) => {
5146
- approvalResolvers.set(toolCallId, { resolve: resolve10, sessionId: this.session.id });
5783
+ const approved = await new Promise((resolve11) => {
5784
+ approvalResolvers.set(toolCallId, { resolve: resolve11, sessionId: this.session.id });
5147
5785
  });
5148
5786
  const resolverData = approvalResolvers.get(toolCallId);
5149
5787
  approvalResolvers.delete(toolCallId);
@@ -5243,20 +5881,20 @@ import { Hono as Hono5 } from "hono";
5243
5881
  import { serve } from "@hono/node-server";
5244
5882
  import { cors } from "hono/cors";
5245
5883
  import { logger } from "hono/logger";
5246
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
5247
- import { resolve as resolve9, dirname as dirname7, join as join8 } from "path";
5884
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
5885
+ import { resolve as resolve10, dirname as dirname7, join as join8 } from "path";
5248
5886
  import { spawn as spawn2 } from "child_process";
5249
5887
  import { createServer as createNetServer } from "net";
5250
- import { fileURLToPath as fileURLToPath3 } from "url";
5888
+ import { fileURLToPath as fileURLToPath4 } from "url";
5251
5889
 
5252
5890
  // src/server/routes/sessions.ts
5253
5891
  init_db();
5254
5892
  import { Hono } from "hono";
5255
5893
  import { zValidator } from "@hono/zod-validator";
5256
- import { z as z12 } from "zod";
5257
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readdirSync, statSync as statSync2, unlinkSync } from "fs";
5258
- import { readdir as readdir4 } from "fs/promises";
5259
- import { join as join5, basename as basename3, extname as extname6, relative as relative8 } from "path";
5894
+ import { z as z13 } from "zod";
5895
+ import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readdirSync, statSync as statSync2, unlinkSync } from "fs";
5896
+ import { readdir as readdir5 } from "fs/promises";
5897
+ import { join as join5, basename as basename4, extname as extname6, relative as relative9 } from "path";
5260
5898
  import { nanoid as nanoid4 } from "nanoid";
5261
5899
  init_config();
5262
5900
 
@@ -5289,18 +5927,18 @@ function cleanupPendingInputs() {
5289
5927
  }
5290
5928
  }
5291
5929
  }
5292
- var createSessionSchema = z12.object({
5293
- name: z12.string().optional(),
5294
- workingDirectory: z12.string().optional(),
5295
- model: z12.string().optional(),
5296
- toolApprovals: z12.record(z12.string(), z12.boolean()).optional()
5930
+ var createSessionSchema = z13.object({
5931
+ name: z13.string().optional(),
5932
+ workingDirectory: z13.string().optional(),
5933
+ model: z13.string().optional(),
5934
+ toolApprovals: z13.record(z13.string(), z13.boolean()).optional()
5297
5935
  });
5298
- var paginationQuerySchema = z12.object({
5299
- limit: z12.string().optional(),
5300
- offset: z12.string().optional()
5936
+ var paginationQuerySchema = z13.object({
5937
+ limit: z13.string().optional(),
5938
+ offset: z13.string().optional()
5301
5939
  });
5302
- var messagesQuerySchema = z12.object({
5303
- limit: z12.string().optional()
5940
+ var messagesQuerySchema = z13.object({
5941
+ limit: z13.string().optional()
5304
5942
  });
5305
5943
  sessions.get(
5306
5944
  "/",
@@ -5439,10 +6077,10 @@ sessions.get("/:id/tools", async (c) => {
5439
6077
  count: executions.length
5440
6078
  });
5441
6079
  });
5442
- var updateSessionSchema = z12.object({
5443
- model: z12.string().optional(),
5444
- name: z12.string().optional(),
5445
- toolApprovals: z12.record(z12.string(), z12.boolean()).optional()
6080
+ var updateSessionSchema = z13.object({
6081
+ model: z13.string().optional(),
6082
+ name: z13.string().optional(),
6083
+ toolApprovals: z13.record(z13.string(), z13.boolean()).optional()
5446
6084
  });
5447
6085
  sessions.patch(
5448
6086
  "/:id",
@@ -5512,8 +6150,8 @@ sessions.post("/:id/clear", async (c) => {
5512
6150
  await agent.clearContext();
5513
6151
  return c.json({ success: true, sessionId: id });
5514
6152
  });
5515
- var pendingInputSchema = z12.object({
5516
- text: z12.string()
6153
+ var pendingInputSchema = z13.object({
6154
+ text: z13.string()
5517
6155
  });
5518
6156
  sessions.post(
5519
6157
  "/:id/pending-input",
@@ -5544,13 +6182,13 @@ sessions.get("/:id/pending-input", async (c) => {
5544
6182
  createdAt: pending.createdAt.toISOString()
5545
6183
  });
5546
6184
  });
5547
- var devtoolsContextSchema = z12.object({
5548
- url: z12.string(),
5549
- path: z12.string(),
5550
- pageName: z12.string().optional(),
5551
- screenWidth: z12.number().optional(),
5552
- screenHeight: z12.number().optional(),
5553
- devicePixelRatio: z12.number().optional()
6185
+ var devtoolsContextSchema = z13.object({
6186
+ url: z13.string(),
6187
+ path: z13.string(),
6188
+ pageName: z13.string().optional(),
6189
+ screenWidth: z13.number().optional(),
6190
+ screenHeight: z13.number().optional(),
6191
+ devicePixelRatio: z13.number().optional()
5554
6192
  });
5555
6193
  sessions.post(
5556
6194
  "/:id/devtools-context",
@@ -5722,7 +6360,7 @@ function getAttachmentsDir(sessionId) {
5722
6360
  }
5723
6361
  function ensureAttachmentsDir(sessionId) {
5724
6362
  const dir = getAttachmentsDir(sessionId);
5725
- if (!existsSync12(dir)) {
6363
+ if (!existsSync13(dir)) {
5726
6364
  mkdirSync3(dir, { recursive: true });
5727
6365
  }
5728
6366
  return dir;
@@ -5734,7 +6372,7 @@ sessions.get("/:id/attachments", async (c) => {
5734
6372
  return c.json({ error: "Session not found" }, 404);
5735
6373
  }
5736
6374
  const dir = getAttachmentsDir(sessionId);
5737
- if (!existsSync12(dir)) {
6375
+ if (!existsSync13(dir)) {
5738
6376
  return c.json({ sessionId, attachments: [], count: 0 });
5739
6377
  }
5740
6378
  const files = readdirSync(dir);
@@ -5773,7 +6411,7 @@ sessions.post("/:id/attachments", async (c) => {
5773
6411
  const dir = ensureAttachmentsDir(sessionId);
5774
6412
  const id = nanoid4(10);
5775
6413
  const ext = extname6(file.name) || "";
5776
- const safeFilename = `${id}_${basename3(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
6414
+ const safeFilename = `${id}_${basename4(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
5777
6415
  const filePath = join5(dir, safeFilename);
5778
6416
  const arrayBuffer = await file.arrayBuffer();
5779
6417
  writeFileSync2(filePath, Buffer.from(arrayBuffer));
@@ -5799,7 +6437,7 @@ sessions.post("/:id/attachments", async (c) => {
5799
6437
  const dir = ensureAttachmentsDir(sessionId);
5800
6438
  const id = nanoid4(10);
5801
6439
  const ext = extname6(body.filename) || "";
5802
- const safeFilename = `${id}_${basename3(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
6440
+ const safeFilename = `${id}_${basename4(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
5803
6441
  const filePath = join5(dir, safeFilename);
5804
6442
  let base64Data = body.data;
5805
6443
  if (base64Data.includes(",")) {
@@ -5829,7 +6467,7 @@ sessions.delete("/:id/attachments/:attachmentId", async (c) => {
5829
6467
  return c.json({ error: "Session not found" }, 404);
5830
6468
  }
5831
6469
  const dir = getAttachmentsDir(sessionId);
5832
- if (!existsSync12(dir)) {
6470
+ if (!existsSync13(dir)) {
5833
6471
  return c.json({ error: "Attachment not found" }, 404);
5834
6472
  }
5835
6473
  const files = readdirSync(dir);
@@ -5841,10 +6479,10 @@ sessions.delete("/:id/attachments/:attachmentId", async (c) => {
5841
6479
  unlinkSync(filePath);
5842
6480
  return c.json({ success: true, id: attachmentId });
5843
6481
  });
5844
- var filesQuerySchema = z12.object({
5845
- query: z12.string().optional(),
6482
+ var filesQuerySchema = z13.object({
6483
+ query: z13.string().optional(),
5846
6484
  // Filter query (e.g., "src/com" to match "src/components")
5847
- limit: z12.string().optional()
6485
+ limit: z13.string().optional()
5848
6486
  // Max results (default 50)
5849
6487
  });
5850
6488
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -5917,11 +6555,11 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
5917
6555
  return results;
5918
6556
  }
5919
6557
  try {
5920
- const entries = await readdir4(currentDir, { withFileTypes: true });
6558
+ const entries = await readdir5(currentDir, { withFileTypes: true });
5921
6559
  for (const entry of entries) {
5922
6560
  if (results.length >= limit * 2) break;
5923
6561
  const fullPath = join5(currentDir, entry.name);
5924
- const relativePath = relative8(baseDir, fullPath);
6562
+ const relativePath = relative9(baseDir, fullPath);
5925
6563
  if (entry.isDirectory() && IGNORED_DIRECTORIES.has(entry.name)) {
5926
6564
  continue;
5927
6565
  }
@@ -5968,7 +6606,7 @@ sessions.get(
5968
6606
  return c.json({ error: "Session not found" }, 404);
5969
6607
  }
5970
6608
  const workingDirectory = session.workingDirectory;
5971
- if (!existsSync12(workingDirectory)) {
6609
+ if (!existsSync13(workingDirectory)) {
5972
6610
  return c.json({
5973
6611
  sessionId,
5974
6612
  workingDirectory,
@@ -6022,8 +6660,8 @@ sessions.get(
6022
6660
  init_db();
6023
6661
  import { Hono as Hono2 } from "hono";
6024
6662
  import { zValidator as zValidator2 } from "@hono/zod-validator";
6025
- import { z as z13 } from "zod";
6026
- import { existsSync as existsSync13, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
6663
+ import { z as z14 } from "zod";
6664
+ import { existsSync as existsSync14, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
6027
6665
  import { join as join6 } from "path";
6028
6666
  init_config();
6029
6667
 
@@ -6164,7 +6802,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
6164
6802
  toolCallId,
6165
6803
  argsTextDelta: chunk
6166
6804
  }));
6167
- await new Promise((resolve10) => setTimeout(resolve10, 0));
6805
+ await new Promise((resolve11) => setTimeout(resolve11, 0));
6168
6806
  }
6169
6807
  }
6170
6808
  function buildDevtoolsContextXml(sessionId) {
@@ -6187,30 +6825,30 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
6187
6825
  ${prompt}`;
6188
6826
  }
6189
6827
  var agents = new Hono2();
6190
- var attachmentSchema = z13.object({
6191
- type: z13.enum(["image", "file"]),
6192
- data: z13.string(),
6828
+ var attachmentSchema = z14.object({
6829
+ type: z14.enum(["image", "file"]),
6830
+ data: z14.string(),
6193
6831
  // base64 data URL or raw base64
6194
- mediaType: z13.string().optional(),
6195
- filename: z13.string().optional()
6832
+ mediaType: z14.string().optional(),
6833
+ filename: z14.string().optional()
6196
6834
  });
6197
- var runPromptSchema = z13.object({
6198
- prompt: z13.string(),
6835
+ var runPromptSchema = z14.object({
6836
+ prompt: z14.string(),
6199
6837
  // Can be empty if attachments are provided
6200
- attachments: z13.array(attachmentSchema).optional()
6838
+ attachments: z14.array(attachmentSchema).optional()
6201
6839
  }).refine(
6202
6840
  (data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
6203
6841
  { message: "Either prompt or attachments must be provided" }
6204
6842
  );
6205
- var quickStartSchema = z13.object({
6206
- prompt: z13.string().min(1),
6207
- name: z13.string().optional(),
6208
- workingDirectory: z13.string().optional(),
6209
- model: z13.string().optional(),
6210
- toolApprovals: z13.record(z13.string(), z13.boolean()).optional()
6843
+ var quickStartSchema = z14.object({
6844
+ prompt: z14.string().min(1),
6845
+ name: z14.string().optional(),
6846
+ workingDirectory: z14.string().optional(),
6847
+ model: z14.string().optional(),
6848
+ toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
6211
6849
  });
6212
- var rejectSchema = z13.object({
6213
- reason: z13.string().optional()
6850
+ var rejectSchema = z14.object({
6851
+ reason: z14.string().optional()
6214
6852
  }).optional();
6215
6853
  var streamAbortControllers = /* @__PURE__ */ new Map();
6216
6854
  function getAttachmentsDirectory(sessionId) {
@@ -6219,7 +6857,7 @@ function getAttachmentsDirectory(sessionId) {
6219
6857
  }
6220
6858
  function saveAttachmentToDisk(sessionId, attachment, index) {
6221
6859
  const attachmentsDir = getAttachmentsDirectory(sessionId);
6222
- if (!existsSync13(attachmentsDir)) {
6860
+ if (!existsSync14(attachmentsDir)) {
6223
6861
  mkdirSync4(attachmentsDir, { recursive: true });
6224
6862
  }
6225
6863
  let filename = attachment.filename;
@@ -6397,7 +7035,7 @@ ${prompt}` });
6397
7035
  chunkIndex,
6398
7036
  chunkCount
6399
7037
  }));
6400
- await new Promise((resolve10) => setTimeout(resolve10, 0));
7038
+ await new Promise((resolve11) => setTimeout(resolve11, 0));
6401
7039
  }
6402
7040
  },
6403
7041
  onStepFinish: async () => {
@@ -6861,7 +7499,7 @@ agents.post(
6861
7499
  chunkIndex,
6862
7500
  chunkCount
6863
7501
  }));
6864
- await new Promise((resolve10) => setTimeout(resolve10, 0));
7502
+ await new Promise((resolve11) => setTimeout(resolve11, 0));
6865
7503
  }
6866
7504
  },
6867
7505
  onStepFinish: async () => {
@@ -6998,11 +7636,11 @@ agents.post(
6998
7636
  init_config();
6999
7637
  import { Hono as Hono3 } from "hono";
7000
7638
  import { zValidator as zValidator3 } from "@hono/zod-validator";
7001
- import { z as z14 } from "zod";
7639
+ import { z as z15 } from "zod";
7002
7640
  import { readFileSync as readFileSync5 } from "fs";
7003
- import { fileURLToPath as fileURLToPath2 } from "url";
7641
+ import { fileURLToPath as fileURLToPath3 } from "url";
7004
7642
  import { dirname as dirname6, join as join7 } from "path";
7005
- var __filename = fileURLToPath2(import.meta.url);
7643
+ var __filename = fileURLToPath3(import.meta.url);
7006
7644
  var __dirname = dirname6(__filename);
7007
7645
  var possiblePaths = [
7008
7646
  join7(__dirname, "../package.json"),
@@ -7108,9 +7746,9 @@ health.get("/api-keys", async (c) => {
7108
7746
  supportedProviders: SUPPORTED_PROVIDERS
7109
7747
  });
7110
7748
  });
7111
- var setApiKeySchema = z14.object({
7112
- provider: z14.string(),
7113
- apiKey: z14.string().min(1)
7749
+ var setApiKeySchema = z15.object({
7750
+ provider: z15.string(),
7751
+ apiKey: z15.string().min(1)
7114
7752
  });
7115
7753
  health.post(
7116
7754
  "/api-keys",
@@ -7149,13 +7787,13 @@ health.delete("/api-keys/:provider", async (c) => {
7149
7787
  // src/server/routes/terminals.ts
7150
7788
  import { Hono as Hono4 } from "hono";
7151
7789
  import { zValidator as zValidator4 } from "@hono/zod-validator";
7152
- import { z as z15 } from "zod";
7790
+ import { z as z16 } from "zod";
7153
7791
  init_db();
7154
7792
  var terminals = new Hono4();
7155
- var spawnSchema = z15.object({
7156
- command: z15.string(),
7157
- cwd: z15.string().optional(),
7158
- name: z15.string().optional()
7793
+ var spawnSchema = z16.object({
7794
+ command: z16.string(),
7795
+ cwd: z16.string().optional(),
7796
+ name: z16.string().optional()
7159
7797
  });
7160
7798
  terminals.post(
7161
7799
  "/:sessionId/terminals",
@@ -7236,8 +7874,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
7236
7874
  // We don't track exit codes in tmux mode
7237
7875
  });
7238
7876
  });
7239
- var logsQuerySchema = z15.object({
7240
- tail: z15.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
7877
+ var logsQuerySchema = z16.object({
7878
+ tail: z16.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
7241
7879
  });
7242
7880
  terminals.get(
7243
7881
  "/:sessionId/terminals/:terminalId/logs",
@@ -7261,8 +7899,8 @@ terminals.get(
7261
7899
  });
7262
7900
  }
7263
7901
  );
7264
- var killSchema = z15.object({
7265
- signal: z15.enum(["SIGTERM", "SIGKILL"]).optional()
7902
+ var killSchema = z16.object({
7903
+ signal: z16.enum(["SIGTERM", "SIGKILL"]).optional()
7266
7904
  });
7267
7905
  terminals.post(
7268
7906
  "/:sessionId/terminals/:terminalId/kill",
@@ -7276,8 +7914,8 @@ terminals.post(
7276
7914
  return c.json({ success: true, message: "Terminal killed" });
7277
7915
  }
7278
7916
  );
7279
- var writeSchema = z15.object({
7280
- input: z15.string()
7917
+ var writeSchema = z16.object({
7918
+ input: z16.string()
7281
7919
  });
7282
7920
  terminals.post(
7283
7921
  "/:sessionId/terminals/:terminalId/write",
@@ -7546,13 +8184,13 @@ var DEFAULT_WEB_PORT = 6969;
7546
8184
  var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
7547
8185
  function getWebDirectory() {
7548
8186
  try {
7549
- const currentDir = dirname7(fileURLToPath3(import.meta.url));
7550
- const webDir = resolve9(currentDir, "..", "web");
7551
- if (existsSync14(webDir) && existsSync14(join8(webDir, "package.json"))) {
8187
+ const currentDir = dirname7(fileURLToPath4(import.meta.url));
8188
+ const webDir = resolve10(currentDir, "..", "web");
8189
+ if (existsSync15(webDir) && existsSync15(join8(webDir, "package.json"))) {
7552
8190
  return webDir;
7553
8191
  }
7554
- const altWebDir = resolve9(currentDir, "..", "..", "web");
7555
- if (existsSync14(altWebDir) && existsSync14(join8(altWebDir, "package.json"))) {
8192
+ const altWebDir = resolve10(currentDir, "..", "..", "web");
8193
+ if (existsSync15(altWebDir) && existsSync15(join8(altWebDir, "package.json"))) {
7556
8194
  return altWebDir;
7557
8195
  }
7558
8196
  return null;
@@ -7575,18 +8213,18 @@ async function isSparkcoderWebRunning(port) {
7575
8213
  }
7576
8214
  }
7577
8215
  function isPortInUse(port) {
7578
- return new Promise((resolve10) => {
8216
+ return new Promise((resolve11) => {
7579
8217
  const server = createNetServer();
7580
8218
  server.once("error", (err) => {
7581
8219
  if (err.code === "EADDRINUSE") {
7582
- resolve10(true);
8220
+ resolve11(true);
7583
8221
  } else {
7584
- resolve10(false);
8222
+ resolve11(false);
7585
8223
  }
7586
8224
  });
7587
8225
  server.once("listening", () => {
7588
8226
  server.close();
7589
- resolve10(false);
8227
+ resolve11(false);
7590
8228
  });
7591
8229
  server.listen(port, "0.0.0.0");
7592
8230
  });
@@ -7611,14 +8249,14 @@ async function findWebPort(preferredPort) {
7611
8249
  }
7612
8250
  function hasProductionBuild(webDir) {
7613
8251
  const buildIdPath = join8(webDir, ".next", "BUILD_ID");
7614
- return existsSync14(buildIdPath);
8252
+ return existsSync15(buildIdPath);
7615
8253
  }
7616
8254
  function hasSourceFiles(webDir) {
7617
8255
  const appDir = join8(webDir, "src", "app");
7618
8256
  const pagesDir = join8(webDir, "src", "pages");
7619
8257
  const rootAppDir = join8(webDir, "app");
7620
8258
  const rootPagesDir = join8(webDir, "pages");
7621
- return existsSync14(appDir) || existsSync14(pagesDir) || existsSync14(rootAppDir) || existsSync14(rootPagesDir);
8259
+ return existsSync15(appDir) || existsSync15(pagesDir) || existsSync15(rootAppDir) || existsSync15(rootPagesDir);
7622
8260
  }
7623
8261
  function getStandaloneServerPath(webDir) {
7624
8262
  const possiblePaths2 = [
@@ -7626,14 +8264,14 @@ function getStandaloneServerPath(webDir) {
7626
8264
  join8(webDir, ".next", "standalone", "web", "server.js")
7627
8265
  ];
7628
8266
  for (const serverPath of possiblePaths2) {
7629
- if (existsSync14(serverPath)) {
8267
+ if (existsSync15(serverPath)) {
7630
8268
  return serverPath;
7631
8269
  }
7632
8270
  }
7633
8271
  return null;
7634
8272
  }
7635
8273
  function runCommand(command, args, cwd, env) {
7636
- return new Promise((resolve10) => {
8274
+ return new Promise((resolve11) => {
7637
8275
  const child = spawn2(command, args, {
7638
8276
  cwd,
7639
8277
  stdio: ["ignore", "pipe", "pipe"],
@@ -7648,10 +8286,10 @@ function runCommand(command, args, cwd, env) {
7648
8286
  output += data.toString();
7649
8287
  });
7650
8288
  child.on("close", (code) => {
7651
- resolve10({ success: code === 0, output });
8289
+ resolve11({ success: code === 0, output });
7652
8290
  });
7653
8291
  child.on("error", (err) => {
7654
- resolve10({ success: false, output: err.message });
8292
+ resolve11({ success: false, output: err.message });
7655
8293
  });
7656
8294
  });
7657
8295
  }
@@ -7666,8 +8304,8 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
7666
8304
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
7667
8305
  return { process: null, port: actualPort };
7668
8306
  }
7669
- const usePnpm = existsSync14(join8(webDir, "pnpm-lock.yaml"));
7670
- const useNpm = !usePnpm && existsSync14(join8(webDir, "package-lock.json"));
8307
+ const usePnpm = existsSync15(join8(webDir, "pnpm-lock.yaml"));
8308
+ const useNpm = !usePnpm && existsSync15(join8(webDir, "package-lock.json"));
7671
8309
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
7672
8310
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
7673
8311
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
@@ -7735,10 +8373,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
7735
8373
  let started = false;
7736
8374
  let exited = false;
7737
8375
  let exitCode = null;
7738
- const startedPromise = new Promise((resolve10) => {
8376
+ const startedPromise = new Promise((resolve11) => {
7739
8377
  const timeout = setTimeout(() => {
7740
8378
  if (!started && !exited) {
7741
- resolve10(false);
8379
+ resolve11(false);
7742
8380
  }
7743
8381
  }, startupTimeout);
7744
8382
  child.stdout?.on("data", (data) => {
@@ -7752,7 +8390,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
7752
8390
  if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
7753
8391
  started = true;
7754
8392
  clearTimeout(timeout);
7755
- resolve10(true);
8393
+ resolve11(true);
7756
8394
  }
7757
8395
  });
7758
8396
  child.stderr?.on("data", (data) => {
@@ -7764,14 +8402,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
7764
8402
  child.on("error", (err) => {
7765
8403
  if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
7766
8404
  clearTimeout(timeout);
7767
- resolve10(false);
8405
+ resolve11(false);
7768
8406
  });
7769
8407
  child.on("exit", (code) => {
7770
8408
  exited = true;
7771
8409
  exitCode = code;
7772
8410
  if (!started) {
7773
8411
  clearTimeout(timeout);
7774
- resolve10(false);
8412
+ resolve11(false);
7775
8413
  }
7776
8414
  webUIProcess = null;
7777
8415
  });
@@ -7864,7 +8502,7 @@ async function startServer(options = {}) {
7864
8502
  if (options.workingDirectory) {
7865
8503
  config.resolvedWorkingDirectory = options.workingDirectory;
7866
8504
  }
7867
- if (!existsSync14(config.resolvedWorkingDirectory)) {
8505
+ if (!existsSync15(config.resolvedWorkingDirectory)) {
7868
8506
  mkdirSync5(config.resolvedWorkingDirectory, { recursive: true });
7869
8507
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
7870
8508
  }