@mastra/core 1.16.1-alpha.0 → 1.17.0-alpha.2

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 (192) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dist/agent/index.cjs +8 -8
  3. package/dist/agent/index.js +1 -1
  4. package/dist/{chunk-XKOCRXCP.js → chunk-4UTQD6B5.js} +3 -3
  5. package/dist/{chunk-XKOCRXCP.js.map → chunk-4UTQD6B5.js.map} +1 -1
  6. package/dist/{chunk-WJEUD4JG.js → chunk-5TKRQNGW.js} +4 -4
  7. package/dist/{chunk-WJEUD4JG.js.map → chunk-5TKRQNGW.js.map} +1 -1
  8. package/dist/{chunk-BEDQJNIR.cjs → chunk-6HSR64XA.cjs} +15 -5
  9. package/dist/chunk-6HSR64XA.cjs.map +1 -0
  10. package/dist/{chunk-LFZXBZR5.cjs → chunk-76NWBCBU.cjs} +9 -9
  11. package/dist/{chunk-LFZXBZR5.cjs.map → chunk-76NWBCBU.cjs.map} +1 -1
  12. package/dist/{chunk-J3NJXIJ4.js → chunk-ABA3KD3X.js} +524 -246
  13. package/dist/chunk-ABA3KD3X.js.map +1 -0
  14. package/dist/{chunk-SNASZNHI.js → chunk-AGEYVARR.js} +2 -2
  15. package/dist/{chunk-SNASZNHI.js.map → chunk-AGEYVARR.js.map} +1 -1
  16. package/dist/{chunk-RQBBPR64.cjs → chunk-AH2ZNH4Y.cjs} +30 -28
  17. package/dist/chunk-AH2ZNH4Y.cjs.map +1 -0
  18. package/dist/{chunk-EXIQD6L3.cjs → chunk-AX5EPGND.cjs} +51 -51
  19. package/dist/{chunk-EXIQD6L3.cjs.map → chunk-AX5EPGND.cjs.map} +1 -1
  20. package/dist/{chunk-BSMSIRKQ.js → chunk-E7L2JB4A.js} +8 -8
  21. package/dist/{chunk-BSMSIRKQ.js.map → chunk-E7L2JB4A.js.map} +1 -1
  22. package/dist/{chunk-RLAMKAFZ.js → chunk-FLW4344C.js} +3 -3
  23. package/dist/{chunk-RLAMKAFZ.js.map → chunk-FLW4344C.js.map} +1 -1
  24. package/dist/{chunk-DKQA3ER2.cjs → chunk-I2Z4GKQ6.cjs} +15 -15
  25. package/dist/{chunk-DKQA3ER2.cjs.map → chunk-I2Z4GKQ6.cjs.map} +1 -1
  26. package/dist/{chunk-LO7V2FG6.cjs → chunk-ID5X55KA.cjs} +7 -7
  27. package/dist/{chunk-LO7V2FG6.cjs.map → chunk-ID5X55KA.cjs.map} +1 -1
  28. package/dist/{chunk-53YOAG3E.js → chunk-JMYTEYXJ.js} +5 -5
  29. package/dist/{chunk-53YOAG3E.js.map → chunk-JMYTEYXJ.js.map} +1 -1
  30. package/dist/{chunk-5TZP6NN4.js → chunk-K76OKOAK.js} +3 -3
  31. package/dist/{chunk-5TZP6NN4.js.map → chunk-K76OKOAK.js.map} +1 -1
  32. package/dist/{chunk-ZJMETLCP.js → chunk-LOGX3EQD.js} +30 -28
  33. package/dist/chunk-LOGX3EQD.js.map +1 -0
  34. package/dist/{chunk-BLBX5SP3.js → chunk-MNIWCQYZ.js} +4 -4
  35. package/dist/{chunk-BLBX5SP3.js.map → chunk-MNIWCQYZ.js.map} +1 -1
  36. package/dist/{chunk-DSFXGE5Y.cjs → chunk-O54IMECL.cjs} +185 -185
  37. package/dist/{chunk-DSFXGE5Y.cjs.map → chunk-O54IMECL.cjs.map} +1 -1
  38. package/dist/{chunk-OC5SNZ6R.cjs → chunk-OBHOUEDZ.cjs} +83 -83
  39. package/dist/{chunk-OC5SNZ6R.cjs.map → chunk-OBHOUEDZ.cjs.map} +1 -1
  40. package/dist/{chunk-OTQY4UJ4.js → chunk-OIZT4TON.js} +476 -27
  41. package/dist/chunk-OIZT4TON.js.map +1 -0
  42. package/dist/{chunk-LIVMJB3N.cjs → chunk-P54SNCAD.cjs} +3 -3
  43. package/dist/{chunk-LIVMJB3N.cjs.map → chunk-P54SNCAD.cjs.map} +1 -1
  44. package/dist/{chunk-DXRM6H35.js → chunk-PICHLY3C.js} +4 -4
  45. package/dist/{chunk-DXRM6H35.js.map → chunk-PICHLY3C.js.map} +1 -1
  46. package/dist/{chunk-7L2ICIDI.cjs → chunk-PQ4CVQXD.cjs} +6 -6
  47. package/dist/{chunk-7L2ICIDI.cjs.map → chunk-PQ4CVQXD.cjs.map} +1 -1
  48. package/dist/{chunk-O7JQYUXP.cjs → chunk-PTRJHO2K.cjs} +7 -7
  49. package/dist/{chunk-O7JQYUXP.cjs.map → chunk-PTRJHO2K.cjs.map} +1 -1
  50. package/dist/{chunk-SQACXTWK.cjs → chunk-QVQ3PGG2.cjs} +2 -2
  51. package/dist/{chunk-SQACXTWK.cjs.map → chunk-QVQ3PGG2.cjs.map} +1 -1
  52. package/dist/{chunk-XW4B2RAG.cjs → chunk-QVVWKMFM.cjs} +525 -248
  53. package/dist/chunk-QVVWKMFM.cjs.map +1 -0
  54. package/dist/{chunk-5S7MQ37C.cjs → chunk-R47HLGU7.cjs} +512 -61
  55. package/dist/chunk-R47HLGU7.cjs.map +1 -0
  56. package/dist/{chunk-R67VVUDR.cjs → chunk-SDSIVJMT.cjs} +16 -16
  57. package/dist/{chunk-R67VVUDR.cjs.map → chunk-SDSIVJMT.cjs.map} +1 -1
  58. package/dist/{chunk-UGXRRSSU.js → chunk-UOCBF4IP.js} +3 -3
  59. package/dist/{chunk-UGXRRSSU.js.map → chunk-UOCBF4IP.js.map} +1 -1
  60. package/dist/{chunk-GVHOPNRI.js → chunk-X234OVG3.js} +14 -4
  61. package/dist/chunk-X234OVG3.js.map +1 -0
  62. package/dist/{chunk-XVP3C4KW.cjs → chunk-XTN63GKI.cjs} +7 -7
  63. package/dist/{chunk-XVP3C4KW.cjs.map → chunk-XTN63GKI.cjs.map} +1 -1
  64. package/dist/{chunk-NJONWVEJ.js → chunk-YBNI2A6Y.js} +8 -8
  65. package/dist/{chunk-NJONWVEJ.js.map → chunk-YBNI2A6Y.js.map} +1 -1
  66. package/dist/{chunk-UXFQJJQG.js → chunk-ZT26XXEB.js} +5 -5
  67. package/dist/{chunk-UXFQJJQG.js.map → chunk-ZT26XXEB.js.map} +1 -1
  68. package/dist/datasets/index.cjs +17 -17
  69. package/dist/datasets/index.js +2 -2
  70. package/dist/docs/SKILL.md +4 -1
  71. package/dist/docs/assets/SOURCE_MAP.json +364 -354
  72. package/dist/docs/references/docs-memory-observational-memory.md +7 -5
  73. package/dist/docs/references/docs-observability-tracing-bridges-otel.md +3 -3
  74. package/dist/docs/references/docs-workspace-lsp.md +116 -0
  75. package/dist/docs/references/docs-workspace-overview.md +15 -1
  76. package/dist/docs/references/guides-agent-frameworks-ai-sdk.md +3 -3
  77. package/dist/docs/references/reference-ai-sdk-with-mastra.md +2 -2
  78. package/dist/docs/references/reference-auth-okta.md +162 -0
  79. package/dist/docs/references/reference-client-js-agents.md +2 -2
  80. package/dist/docs/references/reference-harness-harness-class.md +2 -0
  81. package/dist/docs/references/reference-memory-observational-memory.md +2 -2
  82. package/dist/docs/references/reference-observability-tracing-interfaces.md +1 -1
  83. package/dist/docs/references/reference-processors-message-history-processor.md +1 -1
  84. package/dist/docs/references/reference-processors-processor-interface.md +3 -3
  85. package/dist/docs/references/reference-processors-semantic-recall-processor.md +1 -1
  86. package/dist/docs/references/reference-processors-skill-search-processor.md +93 -0
  87. package/dist/docs/references/reference-processors-tool-call-filter.md +2 -2
  88. package/dist/docs/references/reference-processors-working-memory-processor.md +1 -1
  89. package/dist/docs/references/reference-tools-mcp-client.md +1 -1
  90. package/dist/docs/references/reference.md +2 -0
  91. package/dist/evals/index.cjs +20 -20
  92. package/dist/evals/index.js +3 -3
  93. package/dist/evals/scoreTraces/index.cjs +5 -5
  94. package/dist/evals/scoreTraces/index.js +2 -2
  95. package/dist/harness/harness.d.ts +4 -5
  96. package/dist/harness/harness.d.ts.map +1 -1
  97. package/dist/harness/index.cjs +44 -12
  98. package/dist/harness/index.cjs.map +1 -1
  99. package/dist/harness/index.d.ts +1 -1
  100. package/dist/harness/index.d.ts.map +1 -1
  101. package/dist/harness/index.js +39 -7
  102. package/dist/harness/index.js.map +1 -1
  103. package/dist/harness/types.d.ts +18 -4
  104. package/dist/harness/types.d.ts.map +1 -1
  105. package/dist/index.cjs +2 -2
  106. package/dist/index.js +1 -1
  107. package/dist/llm/index.cjs +16 -16
  108. package/dist/llm/index.js +5 -5
  109. package/dist/llm/model/provider-types.generated.d.ts +5 -0
  110. package/dist/loop/index.cjs +14 -14
  111. package/dist/loop/index.js +1 -1
  112. package/dist/mastra/index.cjs +2 -2
  113. package/dist/mastra/index.js +1 -1
  114. package/dist/memory/index.cjs +14 -14
  115. package/dist/memory/index.js +1 -1
  116. package/dist/memory/types.d.ts +4 -0
  117. package/dist/memory/types.d.ts.map +1 -1
  118. package/dist/models-dev-DYILKQKY.js +3 -0
  119. package/dist/{models-dev-DMH6Y26P.js.map → models-dev-DYILKQKY.js.map} +1 -1
  120. package/dist/models-dev-EX67IAAF.cjs +12 -0
  121. package/dist/{models-dev-YEVVUBSG.cjs.map → models-dev-EX67IAAF.cjs.map} +1 -1
  122. package/dist/netlify-EDK4WKCW.cjs +12 -0
  123. package/dist/{netlify-CQVRCF2F.cjs.map → netlify-EDK4WKCW.cjs.map} +1 -1
  124. package/dist/netlify-RQLBHLLX.js +3 -0
  125. package/dist/{netlify-IAN7GQOF.js.map → netlify-RQLBHLLX.js.map} +1 -1
  126. package/dist/processor-provider/index.cjs +10 -10
  127. package/dist/processor-provider/index.js +1 -1
  128. package/dist/processors/index.cjs +50 -42
  129. package/dist/processors/index.js +1 -1
  130. package/dist/processors/processors/index.d.ts +2 -0
  131. package/dist/processors/processors/index.d.ts.map +1 -1
  132. package/dist/processors/processors/skill-search.d.ts +111 -0
  133. package/dist/processors/processors/skill-search.d.ts.map +1 -0
  134. package/dist/processors/tool-result-reminder.d.ts +32 -0
  135. package/dist/processors/tool-result-reminder.d.ts.map +1 -0
  136. package/dist/provider-registry-3RCP7DTQ.js +3 -0
  137. package/dist/{provider-registry-PBDYA2JQ.js.map → provider-registry-3RCP7DTQ.js.map} +1 -1
  138. package/dist/provider-registry-MBXOBTD4.cjs +40 -0
  139. package/dist/{provider-registry-CCLGCN3B.cjs.map → provider-registry-MBXOBTD4.cjs.map} +1 -1
  140. package/dist/provider-registry.json +10 -0
  141. package/dist/relevance/index.cjs +3 -3
  142. package/dist/relevance/index.js +1 -1
  143. package/dist/storage/constants.cjs +56 -56
  144. package/dist/storage/constants.js +1 -1
  145. package/dist/storage/index.cjs +160 -160
  146. package/dist/storage/index.js +2 -2
  147. package/dist/storage/types.d.ts +2 -0
  148. package/dist/storage/types.d.ts.map +1 -1
  149. package/dist/stream/index.cjs +8 -8
  150. package/dist/stream/index.js +1 -1
  151. package/dist/test-utils/llm-mock.cjs +4 -4
  152. package/dist/test-utils/llm-mock.js +1 -1
  153. package/dist/tool-loop-agent/index.cjs +4 -4
  154. package/dist/tool-loop-agent/index.js +1 -1
  155. package/dist/tools/tool-builder/builder.d.ts.map +1 -1
  156. package/dist/utils.cjs +23 -23
  157. package/dist/utils.js +1 -1
  158. package/dist/vector/index.cjs +7 -7
  159. package/dist/vector/index.js +1 -1
  160. package/dist/workflows/evented/index.cjs +10 -10
  161. package/dist/workflows/evented/index.js +1 -1
  162. package/dist/workflows/index.cjs +24 -24
  163. package/dist/workflows/index.js +1 -1
  164. package/dist/workspace/constants/index.d.ts +4 -1
  165. package/dist/workspace/constants/index.d.ts.map +1 -1
  166. package/dist/workspace/index.cjs +68 -68
  167. package/dist/workspace/index.js +1 -1
  168. package/dist/workspace/lsp/client.d.ts +30 -0
  169. package/dist/workspace/lsp/client.d.ts.map +1 -1
  170. package/dist/workspace/lsp/manager.d.ts +11 -0
  171. package/dist/workspace/lsp/manager.d.ts.map +1 -1
  172. package/dist/workspace/tools/index.d.ts +1 -0
  173. package/dist/workspace/tools/index.d.ts.map +1 -1
  174. package/dist/workspace/tools/lsp-inspect.d.ts +13 -0
  175. package/dist/workspace/tools/lsp-inspect.d.ts.map +1 -0
  176. package/dist/workspace/tools/tools.d.ts.map +1 -1
  177. package/package.json +4 -4
  178. package/src/llm/model/provider-types.generated.d.ts +5 -0
  179. package/dist/chunk-5S7MQ37C.cjs.map +0 -1
  180. package/dist/chunk-BEDQJNIR.cjs.map +0 -1
  181. package/dist/chunk-GVHOPNRI.js.map +0 -1
  182. package/dist/chunk-J3NJXIJ4.js.map +0 -1
  183. package/dist/chunk-OTQY4UJ4.js.map +0 -1
  184. package/dist/chunk-RQBBPR64.cjs.map +0 -1
  185. package/dist/chunk-XW4B2RAG.cjs.map +0 -1
  186. package/dist/chunk-ZJMETLCP.js.map +0 -1
  187. package/dist/models-dev-DMH6Y26P.js +0 -3
  188. package/dist/models-dev-YEVVUBSG.cjs +0 -12
  189. package/dist/netlify-CQVRCF2F.cjs +0 -12
  190. package/dist/netlify-IAN7GQOF.js +0 -3
  191. package/dist/provider-registry-CCLGCN3B.cjs +0 -40
  192. package/dist/provider-registry-PBDYA2JQ.js +0 -3
@@ -6,11 +6,12 @@ import nodePath__default, { parse, join, dirname } from 'path';
6
6
  import posixPath from 'path/posix';
7
7
  import { constants, existsSync } from 'fs';
8
8
  import * as fs2 from 'fs/promises';
9
+ import fs2__default from 'fs/promises';
9
10
  import * as os3 from 'os';
10
11
  import os3__default from 'os';
11
12
  import picomatch from 'picomatch';
12
13
  import { createRequire } from 'module';
13
- import { pathToFileURL } from 'url';
14
+ import { fileURLToPath, pathToFileURL } from 'url';
14
15
  import { execFileSync } from 'child_process';
15
16
  import * as crypto from 'crypto';
16
17
  import { createHash } from 'crypto';
@@ -71,68 +72,68 @@ var WorkspaceReadOnlyError = class extends WorkspaceError {
71
72
  }
72
73
  };
73
74
  var FilesystemError = class extends Error {
74
- constructor(message, code, path7) {
75
+ constructor(message, code, path8) {
75
76
  super(message);
76
77
  this.code = code;
77
- this.path = path7;
78
+ this.path = path8;
78
79
  this.name = "FilesystemError";
79
80
  }
80
81
  };
81
82
  var FileNotFoundError = class extends FilesystemError {
82
- constructor(path7) {
83
- super(`File not found: ${path7}`, "ENOENT", path7);
83
+ constructor(path8) {
84
+ super(`File not found: ${path8}`, "ENOENT", path8);
84
85
  this.name = "FileNotFoundError";
85
86
  }
86
87
  };
87
88
  var DirectoryNotFoundError = class extends FilesystemError {
88
- constructor(path7) {
89
- super(`Directory not found: ${path7}`, "ENOENT", path7);
89
+ constructor(path8) {
90
+ super(`Directory not found: ${path8}`, "ENOENT", path8);
90
91
  this.name = "DirectoryNotFoundError";
91
92
  }
92
93
  };
93
94
  var FileExistsError = class extends FilesystemError {
94
- constructor(path7) {
95
- super(`File already exists: ${path7}`, "EEXIST", path7);
95
+ constructor(path8) {
96
+ super(`File already exists: ${path8}`, "EEXIST", path8);
96
97
  this.name = "FileExistsError";
97
98
  }
98
99
  };
99
100
  var IsDirectoryError = class extends FilesystemError {
100
- constructor(path7) {
101
- super(`Path is a directory: ${path7}`, "EISDIR", path7);
101
+ constructor(path8) {
102
+ super(`Path is a directory: ${path8}`, "EISDIR", path8);
102
103
  this.name = "IsDirectoryError";
103
104
  }
104
105
  };
105
106
  var NotDirectoryError = class extends FilesystemError {
106
- constructor(path7) {
107
- super(`Path is not a directory: ${path7}`, "ENOTDIR", path7);
107
+ constructor(path8) {
108
+ super(`Path is not a directory: ${path8}`, "ENOTDIR", path8);
108
109
  this.name = "NotDirectoryError";
109
110
  }
110
111
  };
111
112
  var DirectoryNotEmptyError = class extends FilesystemError {
112
- constructor(path7) {
113
- super(`Directory not empty: ${path7}`, "ENOTEMPTY", path7);
113
+ constructor(path8) {
114
+ super(`Directory not empty: ${path8}`, "ENOTEMPTY", path8);
114
115
  this.name = "DirectoryNotEmptyError";
115
116
  }
116
117
  };
117
118
  var PermissionError = class extends FilesystemError {
118
- constructor(path7, operation) {
119
- super(`Permission denied: ${operation} on ${path7}`, "EACCES", path7);
119
+ constructor(path8, operation) {
120
+ super(`Permission denied: ${operation} on ${path8}`, "EACCES", path8);
120
121
  this.operation = operation;
121
122
  this.name = "PermissionError";
122
123
  }
123
124
  };
124
125
  var FileReadRequiredError = class extends FilesystemError {
125
- constructor(path7, reason) {
126
- super(reason, "EREAD_REQUIRED", path7);
126
+ constructor(path8, reason) {
127
+ super(reason, "EREAD_REQUIRED", path8);
127
128
  this.name = "FileReadRequiredError";
128
129
  }
129
130
  };
130
131
  var StaleFileError = class extends FilesystemError {
131
- constructor(path7, expectedMtime, actualMtime) {
132
+ constructor(path8, expectedMtime, actualMtime) {
132
133
  super(
133
- `File was modified externally: ${path7} (expected mtime ${expectedMtime.toISOString()}, actual ${actualMtime.toISOString()})`,
134
+ `File was modified externally: ${path8} (expected mtime ${expectedMtime.toISOString()}, actual ${actualMtime.toISOString()})`,
134
135
  "ESTALE",
135
- path7
136
+ path8
136
137
  );
137
138
  this.expectedMtime = expectedMtime;
138
139
  this.actualMtime = actualMtime;
@@ -171,14 +172,14 @@ var CompositeFilesystem = class {
171
172
  constructor(config) {
172
173
  this.id = `cfs-${Date.now().toString(36)}`;
173
174
  this._mounts = /* @__PURE__ */ new Map();
174
- for (const [path7, fs5] of Object.entries(config.mounts)) {
175
- const normalized = this.normalizePath(path7);
176
- this._mounts.set(normalized, fs5);
175
+ for (const [path8, fs6] of Object.entries(config.mounts)) {
176
+ const normalized = this.normalizePath(path8);
177
+ this._mounts.set(normalized, fs6);
177
178
  }
178
179
  if (this._mounts.size === 0) {
179
180
  throw new Error("CompositeFilesystem requires at least one mount");
180
181
  }
181
- this.readOnly = [...this._mounts.values()].every((fs5) => fs5.readOnly) || void 0;
182
+ this.readOnly = [...this._mounts.values()].every((fs6) => fs6.readOnly) || void 0;
182
183
  const mountPaths = [...this._mounts.keys()];
183
184
  for (const a of mountPaths) {
184
185
  for (const b of mountPaths) {
@@ -207,8 +208,8 @@ var CompositeFilesystem = class {
207
208
  */
208
209
  async getInfo() {
209
210
  const mounts = {};
210
- for (const [mountPath, fs5] of this._mounts) {
211
- mounts[mountPath] = await fs5.getInfo?.() ?? null;
211
+ for (const [mountPath, fs6] of this._mounts) {
212
+ mounts[mountPath] = await fs6.getInfo?.() ?? null;
212
213
  }
213
214
  return {
214
215
  id: this.id,
@@ -223,42 +224,42 @@ var CompositeFilesystem = class {
223
224
  * Get the underlying filesystem for a given path.
224
225
  * Returns undefined if the path doesn't resolve to any mount.
225
226
  */
226
- getFilesystemForPath(path7) {
227
- const resolved = this.resolveMount(path7);
227
+ getFilesystemForPath(path8) {
228
+ const resolved = this.resolveMount(path8);
228
229
  return resolved?.fs;
229
230
  }
230
231
  /**
231
232
  * Get the mount path for a given path.
232
233
  * Returns undefined if the path doesn't resolve to any mount.
233
234
  */
234
- getMountPathForPath(path7) {
235
- const resolved = this.resolveMount(path7);
235
+ getMountPathForPath(path8) {
236
+ const resolved = this.resolveMount(path8);
236
237
  return resolved?.mountPath;
237
238
  }
238
239
  /**
239
240
  * Resolve a workspace-relative path to an absolute disk path.
240
241
  * Strips the mount prefix and delegates to the underlying filesystem.
241
242
  */
242
- resolveAbsolutePath(path7) {
243
- const r = this.resolveMount(path7);
243
+ resolveAbsolutePath(path8) {
244
+ const r = this.resolveMount(path8);
244
245
  if (!r) return void 0;
245
246
  return r.fs.resolveAbsolutePath?.(r.fsPath);
246
247
  }
247
- normalizePath(path7) {
248
- if (!path7 || path7 === "/" || path7 === ".") return "/";
249
- let n = posixPath.normalize(path7);
248
+ normalizePath(path8) {
249
+ if (!path8 || path8 === "/" || path8 === ".") return "/";
250
+ let n = posixPath.normalize(path8);
250
251
  if (n === ".") return "/";
251
252
  if (!n.startsWith("/")) n = `/${n}`;
252
253
  if (n.length > 1 && n.endsWith("/")) n = n.slice(0, -1);
253
254
  return n;
254
255
  }
255
- resolveMount(path7) {
256
- const normalized = this.normalizePath(path7);
256
+ resolveMount(path8) {
257
+ const normalized = this.normalizePath(path8);
257
258
  let best = null;
258
- for (const [mountPath, fs5] of this._mounts) {
259
+ for (const [mountPath, fs6] of this._mounts) {
259
260
  if (normalized === mountPath || normalized.startsWith(mountPath + "/")) {
260
261
  if (!best || mountPath.length > best.mountPath.length) {
261
- best = { mountPath, fs: fs5 };
262
+ best = { mountPath, fs: fs6 };
262
263
  }
263
264
  }
264
265
  }
@@ -268,11 +269,11 @@ var CompositeFilesystem = class {
268
269
  else if (fsPath.startsWith("/")) fsPath = fsPath.slice(1);
269
270
  return { fs: best.fs, fsPath, mountPath: best.mountPath };
270
271
  }
271
- getVirtualEntries(path7) {
272
- const normalized = this.normalizePath(path7);
272
+ getVirtualEntries(path8) {
273
+ const normalized = this.normalizePath(path8);
273
274
  if (this.resolveMount(normalized)) return null;
274
275
  const entriesMap = /* @__PURE__ */ new Map();
275
- for (const [mountPath, fs5] of this._mounts.entries()) {
276
+ for (const [mountPath, fs6] of this._mounts.entries()) {
276
277
  const isUnder = normalized === "/" ? mountPath.startsWith("/") : mountPath.startsWith(normalized + "/");
277
278
  if (isUnder) {
278
279
  const remaining = normalized === "/" ? mountPath.slice(1) : mountPath.slice(normalized.length + 1);
@@ -282,12 +283,12 @@ var CompositeFilesystem = class {
282
283
  const entry = { name: next, type: "directory" };
283
284
  if (isDirectMount) {
284
285
  entry.mount = {
285
- provider: fs5.provider,
286
- icon: fs5.icon,
287
- displayName: fs5.displayName,
288
- description: fs5.description,
289
- status: fs5.status,
290
- error: fs5.error
286
+ provider: fs6.provider,
287
+ icon: fs6.icon,
288
+ displayName: fs6.displayName,
289
+ description: fs6.description,
290
+ status: fs6.status,
291
+ error: fs6.error
291
292
  };
292
293
  }
293
294
  entriesMap.set(next, entry);
@@ -296,8 +297,8 @@ var CompositeFilesystem = class {
296
297
  }
297
298
  return entriesMap.size > 0 ? Array.from(entriesMap.values()) : null;
298
299
  }
299
- isVirtualPath(path7) {
300
- const normalized = this.normalizePath(path7);
300
+ isVirtualPath(path8) {
301
+ const normalized = this.normalizePath(path8);
301
302
  if (normalized === "/" && !this._mounts.has("/")) return true;
302
303
  for (const mountPath of this._mounts.keys()) {
303
304
  if (mountPath.startsWith(normalized + "/")) return true;
@@ -308,9 +309,9 @@ var CompositeFilesystem = class {
308
309
  * Assert that a filesystem is writable (not read-only).
309
310
  * @throws {PermissionError} if the filesystem is read-only
310
311
  */
311
- assertWritable(fs5, path7, operation) {
312
- if (fs5.readOnly) {
313
- throw new PermissionError(path7, `${operation} (filesystem is read-only)`);
312
+ assertWritable(fs6, path8, operation) {
313
+ if (fs6.readOnly) {
314
+ throw new PermissionError(path8, `${operation} (filesystem is read-only)`);
314
315
  }
315
316
  }
316
317
  // ===========================================================================
@@ -318,9 +319,9 @@ var CompositeFilesystem = class {
318
319
  // ===========================================================================
319
320
  async init() {
320
321
  this.status = "initializing";
321
- for (const [mountPath, fs5] of this._mounts.entries()) {
322
+ for (const [mountPath, fs6] of this._mounts.entries()) {
322
323
  try {
323
- await callLifecycle(fs5, "init");
324
+ await callLifecycle(fs6, "init");
324
325
  } catch (e) {
325
326
  const message = e instanceof Error ? e.message : String(e);
326
327
  console.warn(`[CompositeFilesystem] Mount "${mountPath}" failed to initialize: ${message}`);
@@ -331,9 +332,9 @@ var CompositeFilesystem = class {
331
332
  async destroy() {
332
333
  this.status = "destroying";
333
334
  const errors = [];
334
- for (const fs5 of this._mounts.values()) {
335
+ for (const fs6 of this._mounts.values()) {
335
336
  try {
336
- await callLifecycle(fs5, "destroy");
337
+ await callLifecycle(fs6, "destroy");
337
338
  } catch (e) {
338
339
  errors.push(e instanceof Error ? e : new Error(String(e)));
339
340
  }
@@ -344,27 +345,27 @@ var CompositeFilesystem = class {
344
345
  }
345
346
  this.status = "destroyed";
346
347
  }
347
- async readFile(path7, options) {
348
- const r = this.resolveMount(path7);
349
- if (!r) throw new Error(`No mount for path: ${path7}`);
348
+ async readFile(path8, options) {
349
+ const r = this.resolveMount(path8);
350
+ if (!r) throw new Error(`No mount for path: ${path8}`);
350
351
  return r.fs.readFile(r.fsPath, options);
351
352
  }
352
- async writeFile(path7, content, options) {
353
- const r = this.resolveMount(path7);
354
- if (!r) throw new Error(`No mount for path: ${path7}`);
355
- this.assertWritable(r.fs, path7, "writeFile");
353
+ async writeFile(path8, content, options) {
354
+ const r = this.resolveMount(path8);
355
+ if (!r) throw new Error(`No mount for path: ${path8}`);
356
+ this.assertWritable(r.fs, path8, "writeFile");
356
357
  return r.fs.writeFile(r.fsPath, content, options);
357
358
  }
358
- async appendFile(path7, content) {
359
- const r = this.resolveMount(path7);
360
- if (!r) throw new Error(`No mount for path: ${path7}`);
361
- this.assertWritable(r.fs, path7, "appendFile");
359
+ async appendFile(path8, content) {
360
+ const r = this.resolveMount(path8);
361
+ if (!r) throw new Error(`No mount for path: ${path8}`);
362
+ this.assertWritable(r.fs, path8, "appendFile");
362
363
  return r.fs.appendFile(r.fsPath, content);
363
364
  }
364
- async deleteFile(path7, options) {
365
- const r = this.resolveMount(path7);
366
- if (!r) throw new Error(`No mount for path: ${path7}`);
367
- this.assertWritable(r.fs, path7, "deleteFile");
365
+ async deleteFile(path8, options) {
366
+ const r = this.resolveMount(path8);
367
+ if (!r) throw new Error(`No mount for path: ${path8}`);
368
+ this.assertWritable(r.fs, path8, "deleteFile");
368
369
  return r.fs.deleteFile(r.fsPath, options);
369
370
  }
370
371
  async copyFile(src, dest, options) {
@@ -392,35 +393,35 @@ var CompositeFilesystem = class {
392
393
  await this.copyFile(src, dest, options);
393
394
  await srcR.fs.deleteFile(srcR.fsPath);
394
395
  }
395
- async readdir(path7, options) {
396
- const virtual = this.getVirtualEntries(path7);
396
+ async readdir(path8, options) {
397
+ const virtual = this.getVirtualEntries(path8);
397
398
  if (virtual) return virtual;
398
- const r = this.resolveMount(path7);
399
- if (!r) throw new Error(`No mount for path: ${path7}`);
399
+ const r = this.resolveMount(path8);
400
+ if (!r) throw new Error(`No mount for path: ${path8}`);
400
401
  return r.fs.readdir(r.fsPath, options);
401
402
  }
402
- async mkdir(path7, options) {
403
- const r = this.resolveMount(path7);
404
- if (!r) throw new Error(`No mount for path: ${path7}`);
405
- this.assertWritable(r.fs, path7, "mkdir");
403
+ async mkdir(path8, options) {
404
+ const r = this.resolveMount(path8);
405
+ if (!r) throw new Error(`No mount for path: ${path8}`);
406
+ this.assertWritable(r.fs, path8, "mkdir");
406
407
  return r.fs.mkdir(r.fsPath, options);
407
408
  }
408
- async rmdir(path7, options) {
409
- const r = this.resolveMount(path7);
410
- if (!r) throw new Error(`No mount for path: ${path7}`);
411
- this.assertWritable(r.fs, path7, "rmdir");
409
+ async rmdir(path8, options) {
410
+ const r = this.resolveMount(path8);
411
+ if (!r) throw new Error(`No mount for path: ${path8}`);
412
+ this.assertWritable(r.fs, path8, "rmdir");
412
413
  return r.fs.rmdir(r.fsPath, options);
413
414
  }
414
- async exists(path7) {
415
- if (this.isVirtualPath(path7)) return true;
416
- const r = this.resolveMount(path7);
415
+ async exists(path8) {
416
+ if (this.isVirtualPath(path8)) return true;
417
+ const r = this.resolveMount(path8);
417
418
  if (!r) return false;
418
419
  if (r.fsPath === "") return true;
419
420
  return r.fs.exists(r.fsPath);
420
421
  }
421
- async stat(path7) {
422
- const normalized = this.normalizePath(path7);
423
- if (this.isVirtualPath(path7)) {
422
+ async stat(path8) {
423
+ const normalized = this.normalizePath(path8);
424
+ if (this.isVirtualPath(path8)) {
424
425
  const parts = normalized.split("/").filter(Boolean);
425
426
  const now = /* @__PURE__ */ new Date();
426
427
  return {
@@ -432,8 +433,8 @@ var CompositeFilesystem = class {
432
433
  modifiedAt: now
433
434
  };
434
435
  }
435
- const r = this.resolveMount(path7);
436
- if (!r) throw new Error(`No mount for path: ${path7}`);
436
+ const r = this.resolveMount(path8);
437
+ if (!r) throw new Error(`No mount for path: ${path8}`);
437
438
  if (r.fsPath === "") {
438
439
  const parts = normalized.split("/").filter(Boolean);
439
440
  const now = /* @__PURE__ */ new Date();
@@ -448,9 +449,9 @@ var CompositeFilesystem = class {
448
449
  }
449
450
  return r.fs.stat(r.fsPath);
450
451
  }
451
- async isFile(path7) {
452
- if (this.isVirtualPath(path7)) return false;
453
- const r = this.resolveMount(path7);
452
+ async isFile(path8) {
453
+ if (this.isVirtualPath(path8)) return false;
454
+ const r = this.resolveMount(path8);
454
455
  if (!r) return false;
455
456
  try {
456
457
  const stat3 = await r.fs.stat(r.fsPath);
@@ -459,9 +460,9 @@ var CompositeFilesystem = class {
459
460
  return false;
460
461
  }
461
462
  }
462
- async isDirectory(path7) {
463
- if (this.isVirtualPath(path7)) return true;
464
- const r = this.resolveMount(path7);
463
+ async isDirectory(path8) {
464
+ if (this.isVirtualPath(path8)) return true;
465
+ const r = this.resolveMount(path8);
465
466
  if (!r) return false;
466
467
  if (r.fsPath === "") return true;
467
468
  try {
@@ -476,9 +477,9 @@ var CompositeFilesystem = class {
476
477
  * Used by agents to understand available storage locations.
477
478
  */
478
479
  getInstructions(_opts) {
479
- const mountDescriptions = Array.from(this._mounts.entries()).map(([mountPath, fs5]) => {
480
- const name = fs5.displayName || fs5.provider;
481
- const access3 = fs5.readOnly ? "(read-only)" : "(read-write)";
480
+ const mountDescriptions = Array.from(this._mounts.entries()).map(([mountPath, fs6]) => {
481
+ const name = fs6.displayName || fs6.provider;
482
+ const access3 = fs6.readOnly ? "(read-only)" : "(read-write)";
482
483
  return `- ${mountPath}: ${name} ${access3}`;
483
484
  }).join("\n");
484
485
  return `Filesystem mount points:
@@ -1346,35 +1347,35 @@ var LocalFilesystem = class extends MastraFilesystem {
1346
1347
  };
1347
1348
  var InMemoryFileReadTracker = class {
1348
1349
  records = /* @__PURE__ */ new Map();
1349
- recordRead(path7, modifiedAt) {
1350
- const normalizedPath = this.normalizePath(path7);
1350
+ recordRead(path8, modifiedAt) {
1351
+ const normalizedPath = this.normalizePath(path8);
1351
1352
  this.records.set(normalizedPath, {
1352
1353
  path: normalizedPath,
1353
1354
  readAt: /* @__PURE__ */ new Date(),
1354
1355
  modifiedAtRead: modifiedAt
1355
1356
  });
1356
1357
  }
1357
- getReadRecord(path7) {
1358
- return this.records.get(this.normalizePath(path7));
1358
+ getReadRecord(path8) {
1359
+ return this.records.get(this.normalizePath(path8));
1359
1360
  }
1360
- needsReRead(path7, currentModifiedAt) {
1361
- const record = this.getReadRecord(path7);
1361
+ needsReRead(path8, currentModifiedAt) {
1362
+ const record = this.getReadRecord(path8);
1362
1363
  if (!record) {
1363
1364
  return {
1364
1365
  needsReRead: true,
1365
- reason: `File "${path7}" has not been read. You must read a file before writing to it.`
1366
+ reason: `File "${path8}" has not been read. You must read a file before writing to it.`
1366
1367
  };
1367
1368
  }
1368
1369
  if (currentModifiedAt.getTime() > record.modifiedAtRead.getTime()) {
1369
1370
  return {
1370
1371
  needsReRead: true,
1371
- reason: `File "${path7}" was modified since last read (read at: ${record.modifiedAtRead.toISOString()}, current: ${currentModifiedAt.toISOString()}). Please re-read the file to get the latest contents.`
1372
+ reason: `File "${path8}" was modified since last read (read at: ${record.modifiedAtRead.toISOString()}, current: ${currentModifiedAt.toISOString()}). Please re-read the file to get the latest contents.`
1372
1373
  };
1373
1374
  }
1374
1375
  return { needsReRead: false };
1375
1376
  }
1376
- clearReadRecord(path7) {
1377
- this.records.delete(this.normalizePath(path7));
1377
+ clearReadRecord(path8) {
1378
+ this.records.delete(this.normalizePath(path8));
1378
1379
  }
1379
1380
  clear() {
1380
1381
  this.records.clear();
@@ -1462,10 +1463,10 @@ function createGlobMatcher(patterns, options) {
1462
1463
  posix: true,
1463
1464
  dot: options?.dot ?? false
1464
1465
  });
1465
- return (path7) => matcher(normalizeForMatch(path7));
1466
+ return (path8) => matcher(normalizeForMatch(path8));
1466
1467
  }
1467
- function matchGlob(path7, pattern, options) {
1468
- return createGlobMatcher(pattern, options)(path7);
1468
+ function matchGlob(path8, pattern, options) {
1469
+ return createGlobMatcher(pattern, options)(path8);
1469
1470
  }
1470
1471
  async function walkAll(readdir4, dir, depth, maxDepth) {
1471
1472
  if (depth >= maxDepth) return [];
@@ -1591,6 +1592,15 @@ async function loadLSPDeps() {
1591
1592
  function toFileUri(fsPath) {
1592
1593
  return pathToFileURL(fsPath).toString();
1593
1594
  }
1595
+ async function withTimeout(promise, ms, errorMessage) {
1596
+ let timer;
1597
+ return Promise.race([
1598
+ promise,
1599
+ new Promise((_, reject) => {
1600
+ timer = setTimeout(() => reject(new Error(errorMessage)), ms);
1601
+ })
1602
+ ]).finally(() => clearTimeout(timer));
1603
+ }
1594
1604
  var LSPClient = class {
1595
1605
  connection = null;
1596
1606
  handle = null;
@@ -1608,6 +1618,10 @@ var LSPClient = class {
1608
1618
  get isAlive() {
1609
1619
  return this.handle !== null && this.handle.exitCode === void 0;
1610
1620
  }
1621
+ /** Name of the LSP server. */
1622
+ get serverName() {
1623
+ return this.serverDef.name;
1624
+ }
1611
1625
  /**
1612
1626
  * Initialize the LSP connection — spawns the server and performs the handshake.
1613
1627
  */
@@ -1779,6 +1793,56 @@ var LSPClient = class {
1779
1793
  textDocument: { uri }
1780
1794
  });
1781
1795
  }
1796
+ /**
1797
+ * Query hover information at a position.
1798
+ */
1799
+ async queryHover(uri, position, timeoutMs = 5e3) {
1800
+ if (!this.connection) return null;
1801
+ return withTimeout(
1802
+ this.connection.sendRequest("textDocument/hover", { textDocument: { uri }, position }),
1803
+ timeoutMs,
1804
+ "Hover request timed out"
1805
+ );
1806
+ }
1807
+ /**
1808
+ * Query definition(s) at a position.
1809
+ */
1810
+ async queryDefinition(uri, position, timeoutMs = 5e3) {
1811
+ if (!this.connection) return [];
1812
+ const result = await withTimeout(
1813
+ this.connection.sendRequest("textDocument/definition", { textDocument: { uri }, position }),
1814
+ timeoutMs,
1815
+ "Definition request timed out"
1816
+ );
1817
+ if (!result) return [];
1818
+ return Array.isArray(result) ? result : result.uri ? [result] : [];
1819
+ }
1820
+ /**
1821
+ * Query type definition(s) at a position.
1822
+ */
1823
+ async queryTypeDefinition(uri, position, timeoutMs = 5e3) {
1824
+ if (!this.connection) return [];
1825
+ const result = await withTimeout(
1826
+ this.connection.sendRequest("textDocument/typeDefinition", { textDocument: { uri }, position }),
1827
+ timeoutMs,
1828
+ "Type definition request timed out"
1829
+ );
1830
+ if (!result) return [];
1831
+ return Array.isArray(result) ? result : result.uri ? [result] : [];
1832
+ }
1833
+ /**
1834
+ * Query implementation(s) at a position.
1835
+ */
1836
+ async queryImplementation(uri, position, timeoutMs = 5e3) {
1837
+ if (!this.connection) return [];
1838
+ const result = await withTimeout(
1839
+ this.connection.sendRequest("textDocument/implementation", { textDocument: { uri }, position }),
1840
+ timeoutMs,
1841
+ "Implementation request timed out"
1842
+ );
1843
+ if (!result) return [];
1844
+ return Array.isArray(result) ? result : result.uri ? [result] : [];
1845
+ }
1782
1846
  /**
1783
1847
  * Shutdown the connection and kill the process.
1784
1848
  */
@@ -1874,12 +1938,12 @@ function walkUp(startDir, markers) {
1874
1938
  }
1875
1939
  return null;
1876
1940
  }
1877
- async function walkUpAsync(startDir, markers, fs5) {
1941
+ async function walkUpAsync(startDir, markers, fs6) {
1878
1942
  let current = startDir;
1879
1943
  const fsRoot = parse(current).root;
1880
1944
  while (true) {
1881
1945
  for (const marker of markers) {
1882
- if (await fs5.exists(join(current, marker))) {
1946
+ if (await fs6.exists(join(current, marker))) {
1883
1947
  return current;
1884
1948
  }
1885
1949
  }
@@ -2126,6 +2190,28 @@ var LSPManager = class {
2126
2190
  }
2127
2191
  return this.initClient(serverDef, projectRoot, key);
2128
2192
  }
2193
+ /**
2194
+ * Get LSP client ready to query a file.
2195
+ * Opens the file in the client so queries can be made.
2196
+ * Returns null when no LSP client is available.
2197
+ */
2198
+ async prepareQuery(filePath) {
2199
+ const client = await this.getClient(filePath);
2200
+ if (!client) return null;
2201
+ const languageId = getLanguageId(filePath);
2202
+ if (!languageId) return null;
2203
+ const fs6 = await import('fs/promises');
2204
+ let content = "";
2205
+ try {
2206
+ content = await fs6.readFile(filePath, "utf-8");
2207
+ } catch {
2208
+ content = "";
2209
+ }
2210
+ client.notifyOpen(filePath, content, languageId);
2211
+ const { pathToFileURL: pathToFileURL3 } = await import('url');
2212
+ const uri = pathToFileURL3(filePath).toString();
2213
+ return { client, uri, languageId, serverName: client.serverName };
2214
+ }
2129
2215
  /**
2130
2216
  * Convenience method: open file, send content, wait for diagnostics, return normalized results.
2131
2217
  * Returns null when no LSP client is available; otherwise returns diagnostics
@@ -2709,14 +2795,14 @@ var MountManager = class {
2709
2795
  /**
2710
2796
  * Get a mount entry by path.
2711
2797
  */
2712
- get(path7) {
2713
- return this._entries.get(path7);
2798
+ get(path8) {
2799
+ return this._entries.get(path8);
2714
2800
  }
2715
2801
  /**
2716
2802
  * Check if a mount exists at the given path.
2717
2803
  */
2718
- has(path7) {
2719
- return this._entries.has(path7);
2804
+ has(path8) {
2805
+ return this._entries.has(path8);
2720
2806
  }
2721
2807
  // ---------------------------------------------------------------------------
2722
2808
  // Entry Modification
@@ -2728,8 +2814,8 @@ var MountManager = class {
2728
2814
  add(mounts) {
2729
2815
  const paths = Object.keys(mounts);
2730
2816
  this.logger.debug(`Adding ${paths.length} pending mount(s)`, { paths });
2731
- for (const [path7, filesystem] of Object.entries(mounts)) {
2732
- this._entries.set(path7, {
2817
+ for (const [path8, filesystem] of Object.entries(mounts)) {
2818
+ this._entries.set(path8, {
2733
2819
  filesystem,
2734
2820
  state: "pending"
2735
2821
  });
@@ -2739,8 +2825,8 @@ var MountManager = class {
2739
2825
  * Update a mount entry's state.
2740
2826
  * Creates the entry if it doesn't exist.
2741
2827
  */
2742
- set(path7, updates) {
2743
- const existing = this._entries.get(path7);
2828
+ set(path8, updates) {
2829
+ const existing = this._entries.get(path8);
2744
2830
  if (existing) {
2745
2831
  existing.state = updates.state;
2746
2832
  if (updates.config) {
@@ -2751,7 +2837,7 @@ var MountManager = class {
2751
2837
  existing.error = updates.error;
2752
2838
  }
2753
2839
  } else if (updates.filesystem) {
2754
- this._entries.set(path7, {
2840
+ this._entries.set(path8, {
2755
2841
  filesystem: updates.filesystem,
2756
2842
  state: updates.state,
2757
2843
  config: updates.config,
@@ -2759,14 +2845,14 @@ var MountManager = class {
2759
2845
  error: updates.error
2760
2846
  });
2761
2847
  } else {
2762
- this.logger.debug(`set() called for unknown path "${path7}" without filesystem \u2014 no entry created`);
2848
+ this.logger.debug(`set() called for unknown path "${path8}" without filesystem \u2014 no entry created`);
2763
2849
  }
2764
2850
  }
2765
2851
  /**
2766
2852
  * Delete a mount entry.
2767
2853
  */
2768
- delete(path7) {
2769
- return this._entries.delete(path7);
2854
+ delete(path8) {
2855
+ return this._entries.delete(path8);
2770
2856
  }
2771
2857
  /**
2772
2858
  * Clear all mount entries.
@@ -2787,7 +2873,7 @@ var MountManager = class {
2787
2873
  return;
2788
2874
  }
2789
2875
  this.logger.debug(`Processing ${pendingCount} pending mount(s)`);
2790
- for (const [path7, entry] of this._entries) {
2876
+ for (const [path8, entry] of this._entries) {
2791
2877
  if (entry.state !== "pending") {
2792
2878
  continue;
2793
2879
  }
@@ -2797,7 +2883,7 @@ var MountManager = class {
2797
2883
  try {
2798
2884
  const hookResult = await this._onMount({
2799
2885
  filesystem: entry.filesystem,
2800
- mountPath: path7,
2886
+ mountPath: path8,
2801
2887
  config,
2802
2888
  sandbox: this._sandbox,
2803
2889
  workspace: this._workspace
@@ -2805,7 +2891,7 @@ var MountManager = class {
2805
2891
  if (hookResult === false) {
2806
2892
  entry.state = "unsupported";
2807
2893
  entry.error = "Skipped by onMount hook";
2808
- this.logger.debug(`Mount skipped by onMount hook`, { path: path7, provider: fsProvider });
2894
+ this.logger.debug(`Mount skipped by onMount hook`, { path: path8, provider: fsProvider });
2809
2895
  continue;
2810
2896
  }
2811
2897
  if (hookResult && typeof hookResult === "object") {
@@ -2813,54 +2899,54 @@ var MountManager = class {
2813
2899
  entry.state = "mounted";
2814
2900
  entry.config = config;
2815
2901
  entry.configHash = config ? this.hashConfig(config) : void 0;
2816
- this.logger.info(`Mount handled by onMount hook`, { path: path7, provider: fsProvider });
2902
+ this.logger.info(`Mount handled by onMount hook`, { path: path8, provider: fsProvider });
2817
2903
  } else {
2818
2904
  entry.state = "error";
2819
2905
  entry.error = hookResult.error ?? "Mount hook failed";
2820
- this.logger.error(`Mount hook failed`, { path: path7, provider: fsProvider, error: entry.error });
2906
+ this.logger.error(`Mount hook failed`, { path: path8, provider: fsProvider, error: entry.error });
2821
2907
  }
2822
2908
  continue;
2823
2909
  }
2824
2910
  } catch (err) {
2825
2911
  entry.state = "error";
2826
2912
  entry.error = `Mount hook error: ${String(err)}`;
2827
- this.logger.error(`Mount hook threw error`, { path: path7, provider: fsProvider, error: entry.error });
2913
+ this.logger.error(`Mount hook threw error`, { path: path8, provider: fsProvider, error: entry.error });
2828
2914
  continue;
2829
2915
  }
2830
2916
  }
2831
2917
  if (!config) {
2832
2918
  entry.state = "unsupported";
2833
2919
  entry.error = "Filesystem does not support mounting";
2834
- this.logger.debug(`Filesystem does not support mounting`, { path: path7, provider: fsProvider });
2920
+ this.logger.debug(`Filesystem does not support mounting`, { path: path8, provider: fsProvider });
2835
2921
  continue;
2836
2922
  }
2837
2923
  entry.config = config;
2838
2924
  entry.configHash = this.hashConfig(config);
2839
2925
  entry.state = "mounting";
2840
- this.logger.debug(`Mounting filesystem`, { path: path7, provider: fsProvider, type: config.type });
2926
+ this.logger.debug(`Mounting filesystem`, { path: path8, provider: fsProvider, type: config.type });
2841
2927
  try {
2842
- const result = await this._mountFn(entry.filesystem, path7);
2928
+ const result = await this._mountFn(entry.filesystem, path8);
2843
2929
  if (result.success) {
2844
2930
  entry.state = "mounted";
2845
- this.logger.info(`Mount successful`, { path: path7, provider: fsProvider });
2931
+ this.logger.info(`Mount successful`, { path: path8, provider: fsProvider });
2846
2932
  } else if (result.unavailable) {
2847
2933
  entry.state = "unavailable";
2848
2934
  entry.error = result.error ?? "FUSE tool not installed";
2849
- this.logger.warn(`FUSE mount unavailable`, { path: path7, provider: fsProvider, error: entry.error });
2935
+ this.logger.warn(`FUSE mount unavailable`, { path: path8, provider: fsProvider, error: entry.error });
2850
2936
  } else {
2851
2937
  entry.state = "error";
2852
2938
  entry.error = result.error ?? "Mount failed";
2853
- this.logger.error(`Mount failed`, { path: path7, provider: fsProvider, error: entry.error });
2939
+ this.logger.error(`Mount failed`, { path: path8, provider: fsProvider, error: entry.error });
2854
2940
  }
2855
2941
  } catch (err) {
2856
2942
  if (err instanceof MountToolNotFoundError) {
2857
2943
  entry.state = "unavailable";
2858
2944
  entry.error = String(err);
2859
- this.logger.warn(`FUSE mount unavailable`, { path: path7, provider: fsProvider, error: entry.error });
2945
+ this.logger.warn(`FUSE mount unavailable`, { path: path8, provider: fsProvider, error: entry.error });
2860
2946
  } else {
2861
2947
  entry.state = "error";
2862
2948
  entry.error = String(err);
2863
- this.logger.error(`Mount threw error`, { path: path7, provider: fsProvider, error: entry.error });
2949
+ this.logger.error(`Mount threw error`, { path: path8, provider: fsProvider, error: entry.error });
2864
2950
  }
2865
2951
  }
2866
2952
  }
@@ -2909,10 +2995,10 @@ var MountManager = class {
2909
2995
  if (separatorIndex <= 0) {
2910
2996
  return null;
2911
2997
  }
2912
- const path7 = content.slice(0, separatorIndex);
2998
+ const path8 = content.slice(0, separatorIndex);
2913
2999
  const configHash = content.slice(separatorIndex + 1);
2914
- if (!path7 || !configHash) return null;
2915
- return { path: path7, configHash };
3000
+ if (!path8 || !configHash) return null;
3001
+ return { path: path8, configHash };
2916
3002
  }
2917
3003
  /**
2918
3004
  * Check if a config hash matches the expected hash for a mount path.
@@ -3398,11 +3484,11 @@ function buildBwrapCommand(command, workspacePath, config) {
3398
3484
  }
3399
3485
  bwrapArgs.push("--proc", "/proc");
3400
3486
  bwrapArgs.push("--tmpfs", "/tmp");
3401
- for (const path7 of DEFAULT_READONLY_BINDS) {
3402
- bwrapArgs.push("--ro-bind-try", path7, path7);
3487
+ for (const path8 of DEFAULT_READONLY_BINDS) {
3488
+ bwrapArgs.push("--ro-bind-try", path8, path8);
3403
3489
  }
3404
- for (const path7 of config.readOnlyPaths ?? []) {
3405
- bwrapArgs.push("--ro-bind", path7, path7);
3490
+ for (const path8 of config.readOnlyPaths ?? []) {
3491
+ bwrapArgs.push("--ro-bind", path8, path8);
3406
3492
  }
3407
3493
  if (config.allowSystemBinaries !== false) {
3408
3494
  const nodePath4 = process.execPath;
@@ -3414,8 +3500,8 @@ function buildBwrapCommand(command, workspacePath, config) {
3414
3500
  bwrapArgs.push("--ro-bind-try", "/snap", "/snap");
3415
3501
  }
3416
3502
  bwrapArgs.push("--bind", workspacePath, workspacePath);
3417
- for (const path7 of config.readWritePaths ?? []) {
3418
- bwrapArgs.push("--bind", path7, path7);
3503
+ for (const path8 of config.readWritePaths ?? []) {
3504
+ bwrapArgs.push("--bind", path8, path8);
3419
3505
  }
3420
3506
  bwrapArgs.push("--chdir", workspacePath);
3421
3507
  bwrapArgs.push("--die-with-parent");
@@ -4823,18 +4909,18 @@ var VersionedSkillSource = class {
4823
4909
  /**
4824
4910
  * Normalize a path by stripping leading/trailing slashes and dots.
4825
4911
  */
4826
- #normalizePath(path7) {
4827
- let normalized = path7.replace(/^[./\\]+|[/\\]+$/g, "");
4912
+ #normalizePath(path8) {
4913
+ let normalized = path8.replace(/^[./\\]+|[/\\]+$/g, "");
4828
4914
  if (normalized === "") return "";
4829
4915
  return normalized;
4830
4916
  }
4831
- async exists(path7) {
4832
- const normalized = this.#normalizePath(path7);
4917
+ async exists(path8) {
4918
+ const normalized = this.#normalizePath(path8);
4833
4919
  if (this.#tree.entries[normalized]) return true;
4834
4920
  return this.#directories.has(normalized);
4835
4921
  }
4836
- async stat(path7) {
4837
- const normalized = this.#normalizePath(path7);
4922
+ async stat(path8) {
4923
+ const normalized = this.#normalizePath(path8);
4838
4924
  const name = normalized.split("/").pop() || normalized || ".";
4839
4925
  const entry = this.#tree.entries[normalized];
4840
4926
  if (entry) {
@@ -4856,27 +4942,27 @@ var VersionedSkillSource = class {
4856
4942
  modifiedAt: this.#versionCreatedAt
4857
4943
  };
4858
4944
  }
4859
- throw new Error(`Path not found in skill version tree: ${path7}`);
4945
+ throw new Error(`Path not found in skill version tree: ${path8}`);
4860
4946
  }
4861
- async readFile(path7) {
4862
- const normalized = this.#normalizePath(path7);
4947
+ async readFile(path8) {
4948
+ const normalized = this.#normalizePath(path8);
4863
4949
  const entry = this.#tree.entries[normalized];
4864
4950
  if (!entry) {
4865
- throw new Error(`File not found in skill version tree: ${path7}`);
4951
+ throw new Error(`File not found in skill version tree: ${path8}`);
4866
4952
  }
4867
4953
  const blob = await this.#blobStore.get(entry.blobHash);
4868
4954
  if (!blob) {
4869
- throw new Error(`Blob not found for hash ${entry.blobHash} (file: ${path7})`);
4955
+ throw new Error(`Blob not found for hash ${entry.blobHash} (file: ${path8})`);
4870
4956
  }
4871
4957
  if (entry.encoding === "base64") {
4872
4958
  return Buffer.from(blob.content, "base64");
4873
4959
  }
4874
4960
  return blob.content;
4875
4961
  }
4876
- async readdir(path7) {
4877
- const normalized = this.#normalizePath(path7);
4962
+ async readdir(path8) {
4963
+ const normalized = this.#normalizePath(path8);
4878
4964
  if (!this.#directories.has(normalized)) {
4879
- throw new Error(`Directory not found in skill version tree: ${path7}`);
4965
+ throw new Error(`Directory not found in skill version tree: ${path8}`);
4880
4966
  }
4881
4967
  const prefix = normalized === "" ? "" : normalized + "/";
4882
4968
  const seen = /* @__PURE__ */ new Set();
@@ -4909,15 +4995,15 @@ var CompositeVersionedSkillSource = class {
4909
4995
  this.#fallback = options?.fallback;
4910
4996
  this.#fallbackSkills = new Set(options?.fallbackSkills ?? []);
4911
4997
  }
4912
- #normalizePath(path7) {
4913
- return path7.replace(/^[./\\]+|[/\\]+$/g, "");
4998
+ #normalizePath(path8) {
4999
+ return path8.replace(/^[./\\]+|[/\\]+$/g, "");
4914
5000
  }
4915
5001
  /**
4916
5002
  * Route a path to the correct source.
4917
5003
  * Returns the source and the remaining path within that source.
4918
5004
  */
4919
- #routePath(path7) {
4920
- const normalized = this.#normalizePath(path7);
5005
+ #routePath(path8) {
5006
+ const normalized = this.#normalizePath(path8);
4921
5007
  if (normalized === "") return null;
4922
5008
  const segments = normalized.split("/");
4923
5009
  const skillDir = segments[0];
@@ -4934,15 +5020,15 @@ var CompositeVersionedSkillSource = class {
4934
5020
  }
4935
5021
  return null;
4936
5022
  }
4937
- async exists(path7) {
4938
- const normalized = this.#normalizePath(path7);
5023
+ async exists(path8) {
5024
+ const normalized = this.#normalizePath(path8);
4939
5025
  if (normalized === "") return true;
4940
- const route = this.#routePath(path7);
5026
+ const route = this.#routePath(path8);
4941
5027
  if (!route) return false;
4942
5028
  return route.source.exists(route.subPath);
4943
5029
  }
4944
- async stat(path7) {
4945
- const normalized = this.#normalizePath(path7);
5030
+ async stat(path8) {
5031
+ const normalized = this.#normalizePath(path8);
4946
5032
  if (normalized === "") {
4947
5033
  return {
4948
5034
  name: ".",
@@ -4952,21 +5038,21 @@ var CompositeVersionedSkillSource = class {
4952
5038
  modifiedAt: /* @__PURE__ */ new Date()
4953
5039
  };
4954
5040
  }
4955
- const route = this.#routePath(path7);
5041
+ const route = this.#routePath(path8);
4956
5042
  if (!route) {
4957
- throw new Error(`Path not found in composite skill source: ${path7}`);
5043
+ throw new Error(`Path not found in composite skill source: ${path8}`);
4958
5044
  }
4959
5045
  return route.source.stat(route.subPath);
4960
5046
  }
4961
- async readFile(path7) {
4962
- const route = this.#routePath(path7);
5047
+ async readFile(path8) {
5048
+ const route = this.#routePath(path8);
4963
5049
  if (!route) {
4964
- throw new Error(`File not found in composite skill source: ${path7}`);
5050
+ throw new Error(`File not found in composite skill source: ${path8}`);
4965
5051
  }
4966
5052
  return route.source.readFile(route.subPath);
4967
5053
  }
4968
- async readdir(path7) {
4969
- const normalized = this.#normalizePath(path7);
5054
+ async readdir(path8) {
5055
+ const normalized = this.#normalizePath(path8);
4970
5056
  if (normalized === "") {
4971
5057
  const entries = [];
4972
5058
  const seen = /* @__PURE__ */ new Set();
@@ -4982,9 +5068,9 @@ var CompositeVersionedSkillSource = class {
4982
5068
  }
4983
5069
  return entries;
4984
5070
  }
4985
- const route = this.#routePath(path7);
5071
+ const route = this.#routePath(path8);
4986
5072
  if (!route) {
4987
- throw new Error(`Directory not found in composite skill source: ${path7}`);
5073
+ throw new Error(`Directory not found in composite skill source: ${path8}`);
4988
5074
  }
4989
5075
  return route.source.readdir(route.subPath);
4990
5076
  }
@@ -5184,7 +5270,7 @@ var WorkspaceSkillsImpl = class _WorkspaceSkillsImpl {
5184
5270
  if (a.length !== b.length) return false;
5185
5271
  const sortedA = [...a].sort();
5186
5272
  const sortedB = [...b].sort();
5187
- return sortedA.every((path7, i) => path7 === sortedB[i]);
5273
+ return sortedA.every((path8, i) => path8 === sortedB[i]);
5188
5274
  }
5189
5275
  // ===========================================================================
5190
5276
  // Search
@@ -5790,9 +5876,9 @@ ${validation.errors.join("\n")}`);
5790
5876
  /**
5791
5877
  * Get parent path
5792
5878
  */
5793
- #getParentPath(path7) {
5794
- const lastSlash = path7.lastIndexOf("/");
5795
- return lastSlash > 0 ? path7.substring(0, lastSlash) : "/";
5879
+ #getParentPath(path8) {
5880
+ const lastSlash = path8.lastIndexOf("/");
5881
+ return lastSlash > 0 ? path8.substring(0, lastSlash) : "/";
5796
5882
  }
5797
5883
  };
5798
5884
  function hashContent(content) {
@@ -6023,14 +6109,14 @@ function createSkillReadTool(skills) {
6023
6109
  startLine: z.number().optional().describe("Starting line number (1-indexed). If omitted, starts from the beginning."),
6024
6110
  endLine: z.number().optional().describe("Ending line number (1-indexed, inclusive). If omitted, reads to the end.")
6025
6111
  }),
6026
- execute: async ({ skillName, path: path7, startLine, endLine }) => {
6112
+ execute: async ({ skillName, path: path8, startLine, endLine }) => {
6027
6113
  const resolved = await resolveSkill(skills, skillName);
6028
6114
  if ("notFound" in resolved) return resolved.notFound;
6029
6115
  const resolvedPath = resolved.skill.path;
6030
6116
  let content = null;
6031
- content = await skills.getReference(resolvedPath, path7);
6032
- if (content === null) content = await skills.getScript(resolvedPath, path7);
6033
- if (content === null) content = await skills.getAsset(resolvedPath, path7);
6117
+ content = await skills.getReference(resolvedPath, path8);
6118
+ if (content === null) content = await skills.getScript(resolvedPath, path8);
6119
+ if (content === null) content = await skills.getAsset(resolvedPath, path8);
6034
6120
  if (content === null) {
6035
6121
  const refs = (await skills.listReferences(resolvedPath)).map((f) => `references/${f}`);
6036
6122
  const scriptsList = (await skills.listScripts(resolvedPath)).map((f) => `scripts/${f}`);
@@ -6038,11 +6124,11 @@ function createSkillReadTool(skills) {
6038
6124
  const allFiles = [...refs, ...scriptsList, ...assets];
6039
6125
  const fileList = allFiles.length > 0 ? `
6040
6126
  Available files: ${allFiles.join(", ")}` : "";
6041
- return `File "${path7}" not found in skill "${skillName}".${fileList}`;
6127
+ return `File "${path8}" not found in skill "${skillName}".${fileList}`;
6042
6128
  }
6043
6129
  const textContent = typeof content === "string" ? content : content.toString("utf-8");
6044
6130
  if (textContent.slice(0, 1e3).includes("\0")) {
6045
- const fullPath = `${resolved.skill.path}/${path7}`;
6131
+ const fullPath = `${resolved.skill.path}/${path8}`;
6046
6132
  const size = typeof content === "string" ? Buffer.byteLength(content) : content.length;
6047
6133
  return `Binary file: ${fullPath} (${size} bytes)`;
6048
6134
  }
@@ -6078,8 +6164,8 @@ var Workspace = class {
6078
6164
  if (config.filesystem) {
6079
6165
  throw new WorkspaceError('Cannot use both "filesystem" and "mounts"', "INVALID_CONFIG");
6080
6166
  }
6081
- for (const [mountPath, fs5] of Object.entries(config.mounts)) {
6082
- if (fs5 instanceof LocalFilesystem && !fs5.contained) {
6167
+ for (const [mountPath, fs6] of Object.entries(config.mounts)) {
6168
+ if (fs6 instanceof LocalFilesystem && !fs6.contained) {
6083
6169
  console.warn(
6084
6170
  `[Workspace] LocalFilesystem at mount "${mountPath}" has contained: false, which is incompatible with mounts. CompositeFilesystem strips mount prefixes and produces absolute paths (e.g. "/file.txt"), which a non-contained LocalFilesystem interprets as real host paths instead of paths relative to basePath. Use contained: true (default) or allowedPaths for specific exceptions.`
6085
6171
  );
@@ -6275,13 +6361,13 @@ var Workspace = class {
6275
6361
  * @param options - Index options (metadata, type hints)
6276
6362
  * @throws {SearchNotAvailableError} if search is not configured
6277
6363
  */
6278
- async index(path7, content, options) {
6364
+ async index(path8, content, options) {
6279
6365
  if (!this._searchEngine) {
6280
6366
  throw new SearchNotAvailableError();
6281
6367
  }
6282
6368
  this.lastAccessedAt = /* @__PURE__ */ new Date();
6283
6369
  const doc = {
6284
- id: path7,
6370
+ id: path8,
6285
6371
  content,
6286
6372
  metadata: {
6287
6373
  type: options?.type,
@@ -6590,6 +6676,9 @@ var WORKSPACE_TOOLS = {
6590
6676
  SEARCH: {
6591
6677
  SEARCH: `${WORKSPACE_TOOLS_PREFIX}_search`,
6592
6678
  INDEX: `${WORKSPACE_TOOLS_PREFIX}_index`
6679
+ },
6680
+ LSP: {
6681
+ LSP_INSPECT: `${WORKSPACE_TOOLS_PREFIX}_lsp_inspect`
6593
6682
  }
6594
6683
  };
6595
6684
  function requireWorkspace(context) {
@@ -6912,7 +7001,7 @@ Pattern replace (for everything else):
6912
7001
  isDefault: z.boolean().optional().describe("Whether the first name is a default import")
6913
7002
  }).optional().describe("Required for add-import transform. Specifies the module and names to import.")
6914
7003
  }),
6915
- execute: async ({ path: path7, pattern, replacement, transform, targetName, newName, importSpec }, context) => {
7004
+ execute: async ({ path: path8, pattern, replacement, transform, targetName, newName, importSpec }, context) => {
6916
7005
  const { workspace, filesystem } = requireFilesystem(context);
6917
7006
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.AST_EDIT);
6918
7007
  if (filesystem.readOnly) {
@@ -6925,19 +7014,19 @@ Pattern replace (for everything else):
6925
7014
  const { parse: parse2, Lang } = astGrep;
6926
7015
  let content;
6927
7016
  try {
6928
- content = await filesystem.readFile(path7, { encoding: "utf-8" });
7017
+ content = await filesystem.readFile(path8, { encoding: "utf-8" });
6929
7018
  } catch (error) {
6930
7019
  if (error instanceof FileNotFoundError) {
6931
- return `File not found: ${path7}. Use the write file tool to create it first.`;
7020
+ return `File not found: ${path8}. Use the write file tool to create it first.`;
6932
7021
  }
6933
7022
  throw error;
6934
7023
  }
6935
7024
  if (typeof content !== "string") {
6936
7025
  return `Cannot perform AST edits on binary files. Use the write file tool instead.`;
6937
7026
  }
6938
- const lang = getLanguageFromPath(path7, Lang);
7027
+ const lang = getLanguageFromPath(path8, Lang);
6939
7028
  if (!lang) {
6940
- return `Unsupported file type for AST editing: ${path7}`;
7029
+ return `Unsupported file type for AST editing: ${path8}`;
6941
7030
  }
6942
7031
  const ast = parse2(lang, content);
6943
7032
  const root = ast.root();
@@ -6987,16 +7076,16 @@ Pattern replace (for everything else):
6987
7076
  }
6988
7077
  const wasModified = modifiedContent !== content;
6989
7078
  if (wasModified) {
6990
- await filesystem.writeFile(path7, modifiedContent, {
7079
+ await filesystem.writeFile(path8, modifiedContent, {
6991
7080
  overwrite: true,
6992
7081
  expectedMtime: context?.__expectedMtime
6993
7082
  });
6994
7083
  }
6995
7084
  if (!wasModified) {
6996
- return `No changes made to ${path7} (${changes.join("; ")})`;
7085
+ return `No changes made to ${path8} (${changes.join("; ")})`;
6997
7086
  }
6998
- let output = `${path7}: ${changes.join("; ")}`;
6999
- output += await getEditDiagnosticsText(workspace, path7, modifiedContent);
7087
+ let output = `${path8}: ${changes.join("; ")}`;
7088
+ output += await getEditDiagnosticsText(workspace, path8, modifiedContent);
7000
7089
  return output;
7001
7090
  }
7002
7091
  });
@@ -7007,19 +7096,19 @@ var deleteFileTool = createTool({
7007
7096
  path: z.string().describe("The path to the file or directory to delete"),
7008
7097
  recursive: z.boolean().optional().default(false).describe("If true, delete directories and their contents recursively. Required for non-empty directories.")
7009
7098
  }),
7010
- execute: async ({ path: path7, recursive }, context) => {
7099
+ execute: async ({ path: path8, recursive }, context) => {
7011
7100
  const { filesystem } = requireFilesystem(context);
7012
7101
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.DELETE);
7013
7102
  if (filesystem.readOnly) {
7014
7103
  throw new WorkspaceReadOnlyError("delete");
7015
7104
  }
7016
- const stat3 = await filesystem.stat(path7);
7105
+ const stat3 = await filesystem.stat(path8);
7017
7106
  if (stat3.type === "directory") {
7018
- await filesystem.rmdir(path7, { recursive, force: recursive });
7107
+ await filesystem.rmdir(path8, { recursive, force: recursive });
7019
7108
  } else {
7020
- await filesystem.deleteFile(path7);
7109
+ await filesystem.deleteFile(path8);
7021
7110
  }
7022
- return `Deleted ${path7}`;
7111
+ return `Deleted ${path8}`;
7023
7112
  }
7024
7113
  });
7025
7114
  var editFileTool = createTool({
@@ -7037,24 +7126,24 @@ Usage:
7037
7126
  new_string: z.string().describe("The text to replace old_string with"),
7038
7127
  replace_all: z.boolean().optional().default(false).describe("If true, replace all occurrences. If false (default), old_string must be unique.")
7039
7128
  }),
7040
- execute: async ({ path: path7, old_string, new_string, replace_all }, context) => {
7129
+ execute: async ({ path: path8, old_string, new_string, replace_all }, context) => {
7041
7130
  const { workspace, filesystem } = requireFilesystem(context);
7042
7131
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE);
7043
7132
  if (filesystem.readOnly) {
7044
7133
  throw new WorkspaceReadOnlyError("edit_file");
7045
7134
  }
7046
7135
  try {
7047
- const content = await filesystem.readFile(path7, { encoding: "utf-8" });
7136
+ const content = await filesystem.readFile(path8, { encoding: "utf-8" });
7048
7137
  if (typeof content !== "string") {
7049
7138
  return `Cannot edit binary files. Use the write file tool instead.`;
7050
7139
  }
7051
7140
  const result = replaceString(content, old_string, new_string, replace_all);
7052
- await filesystem.writeFile(path7, result.content, {
7141
+ await filesystem.writeFile(path8, result.content, {
7053
7142
  overwrite: true,
7054
7143
  expectedMtime: context?.__expectedMtime
7055
7144
  });
7056
- let output = `Replaced ${result.replacements} occurrence${result.replacements !== 1 ? "s" : ""} in ${path7}`;
7057
- output += await getEditDiagnosticsText(workspace, path7, result.content);
7145
+ let output = `Replaced ${result.replacements} occurrence${result.replacements !== 1 ? "s" : ""} in ${path8}`;
7146
+ output += await getEditDiagnosticsText(workspace, path8, result.content);
7058
7147
  return output;
7059
7148
  } catch (error) {
7060
7149
  if (error instanceof StringNotFoundError) {
@@ -7306,19 +7395,19 @@ var fileStatTool = createTool({
7306
7395
  inputSchema: z.object({
7307
7396
  path: z.string().describe("The path to check")
7308
7397
  }),
7309
- execute: async ({ path: path7 }, context) => {
7398
+ execute: async ({ path: path8 }, context) => {
7310
7399
  const { filesystem } = requireFilesystem(context);
7311
7400
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT);
7312
7401
  try {
7313
- const stat3 = await filesystem.stat(path7);
7402
+ const stat3 = await filesystem.stat(path8);
7314
7403
  const modifiedAt = stat3.modifiedAt.toISOString();
7315
- const parts = [`${path7}`, `Type: ${stat3.type}`];
7404
+ const parts = [`${path8}`, `Type: ${stat3.type}`];
7316
7405
  if (stat3.size !== void 0) parts.push(`Size: ${stat3.size} bytes`);
7317
7406
  parts.push(`Modified: ${modifiedAt}`);
7318
7407
  return parts.join(" ");
7319
7408
  } catch (error) {
7320
7409
  if (error instanceof FileNotFoundError) {
7321
- return `${path7}: not found`;
7410
+ return `${path8}: not found`;
7322
7411
  }
7323
7412
  throw error;
7324
7413
  }
@@ -7584,11 +7673,11 @@ var indexContentTool = createTool({
7584
7673
  content: z.string().describe("The text content to index"),
7585
7674
  metadata: z.record(z.string(), z.unknown()).optional().describe("Optional metadata to store with the document")
7586
7675
  }),
7587
- execute: async ({ path: path7, content, metadata }, context) => {
7676
+ execute: async ({ path: path8, content, metadata }, context) => {
7588
7677
  const workspace = requireWorkspace(context);
7589
7678
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.SEARCH.INDEX);
7590
- await workspace.index(path7, content, { metadata });
7591
- return `Indexed ${path7}`;
7679
+ await workspace.index(path8, content, { metadata });
7680
+ return `Indexed ${path8}`;
7592
7681
  }
7593
7682
  });
7594
7683
  var KILL_TAIL_LINES = 50;
@@ -7644,7 +7733,7 @@ Use this to stop a long-running background process that was started with execute
7644
7733
  });
7645
7734
 
7646
7735
  // src/workspace/tools/tree-formatter.ts
7647
- async function formatAsTree(fs5, path7, options) {
7736
+ async function formatAsTree(fs6, path8, options) {
7648
7737
  const maxDepth = options?.maxDepth ?? Infinity;
7649
7738
  const showHidden = options?.showHidden ?? false;
7650
7739
  const dirsOnly = options?.dirsOnly ?? false;
@@ -7654,9 +7743,9 @@ async function formatAsTree(fs5, path7, options) {
7654
7743
  const respectGitignore = options?.respectGitignore ?? true;
7655
7744
  let ignoreFilter = options?.ignoreFilter;
7656
7745
  if (!ignoreFilter && respectGitignore) {
7657
- const rawFilter = await loadGitignore(fs5);
7746
+ const rawFilter = await loadGitignore(fs6);
7658
7747
  if (rawFilter) {
7659
- const normalizedPath = path7.replace(/^\.\//, "").replace(/^\//, "").replace(/\/$/, "");
7748
+ const normalizedPath = path8.replace(/^\.\//, "").replace(/^\//, "").replace(/\/$/, "");
7660
7749
  const targetIsIgnored = normalizedPath && rawFilter(normalizedPath + "/");
7661
7750
  ignoreFilter = targetIsIgnored ? void 0 : rawFilter;
7662
7751
  }
@@ -7678,7 +7767,7 @@ async function formatAsTree(fs5, path7, options) {
7678
7767
  }
7679
7768
  let entries;
7680
7769
  try {
7681
- entries = await fs5.readdir(currentPath);
7770
+ entries = await fs6.readdir(currentPath);
7682
7771
  } catch (error) {
7683
7772
  if (depth === 0) {
7684
7773
  throw error;
@@ -7718,7 +7807,7 @@ async function formatAsTree(fs5, path7, options) {
7718
7807
  if (globMatcher && !dirsOnly) {
7719
7808
  filtered = filtered.filter((e) => {
7720
7809
  if (e.type === "directory") return true;
7721
- const relativePath = getRelativePath(path7, currentPath, e.name);
7810
+ const relativePath = getRelativePath(path8, currentPath, e.name);
7722
7811
  return globMatcher(relativePath);
7723
7812
  });
7724
7813
  }
@@ -7732,7 +7821,7 @@ async function formatAsTree(fs5, path7, options) {
7732
7821
  const entry = filtered[i];
7733
7822
  const displayName = entry.isSymlink && entry.symlinkTarget ? `${entry.name} -> ${entry.symlinkTarget}` : entry.name;
7734
7823
  lines.push(`${indent}${displayName}`);
7735
- paths.push(getRelativePath(path7, currentPath, entry.name));
7824
+ paths.push(getRelativePath(path8, currentPath, entry.name));
7736
7825
  if (entry.type === "directory") {
7737
7826
  dirCount++;
7738
7827
  if (!entry.isSymlink) {
@@ -7744,7 +7833,7 @@ async function formatAsTree(fs5, path7, options) {
7744
7833
  }
7745
7834
  }
7746
7835
  }
7747
- await buildTree(path7, 0);
7836
+ await buildTree(path8, 0);
7748
7837
  const dirPart = dirCount === 1 ? "1 directory" : `${dirCount} directories`;
7749
7838
  const filePart = fileCount === 1 ? "1 file" : `${fileCount} files`;
7750
7839
  let summary = `${dirPart}, ${filePart}`;
@@ -7807,10 +7896,10 @@ Examples:
7807
7896
  ),
7808
7897
  respectGitignore: z.boolean().optional().default(true).describe("Respect .gitignore in the listed directory (default: true).")
7809
7898
  }),
7810
- execute: async ({ path: path7 = ".", maxDepth = 2, showHidden, dirsOnly, exclude, extension, pattern, respectGitignore }, context) => {
7899
+ execute: async ({ path: path8 = ".", maxDepth = 2, showHidden, dirsOnly, exclude, extension, pattern, respectGitignore }, context) => {
7811
7900
  const { workspace, filesystem } = requireFilesystem(context);
7812
7901
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES);
7813
- const result = await formatAsTree(filesystem, path7, {
7902
+ const result = await formatAsTree(filesystem, path8, {
7814
7903
  maxDepth,
7815
7904
  showHidden,
7816
7905
  dirsOnly,
@@ -7828,6 +7917,194 @@ ${result.summary}`,
7828
7917
  );
7829
7918
  }
7830
7919
  });
7920
+ var CURSOR_MARKER = "<<<";
7921
+ async function getLinePreview(filePath, lineNumber) {
7922
+ try {
7923
+ const content = await fs2__default.readFile(filePath, "utf-8");
7924
+ const lines = content.split("\n");
7925
+ const line = lines[lineNumber - 1];
7926
+ return line?.trim() ?? null;
7927
+ } catch {
7928
+ return null;
7929
+ }
7930
+ }
7931
+ function getAbsolutePath(workspacePath, lspRoot, resolveAbsolutePath) {
7932
+ const resolvedPath = resolveAbsolutePath?.(workspacePath);
7933
+ if (resolvedPath) {
7934
+ return resolvedPath;
7935
+ }
7936
+ if (nodePath__default.isAbsolute(workspacePath)) {
7937
+ return workspacePath;
7938
+ }
7939
+ return nodePath__default.resolve(lspRoot, workspacePath);
7940
+ }
7941
+ function locationUriToPath(uri) {
7942
+ if (!uri.startsWith("file://")) {
7943
+ return null;
7944
+ }
7945
+ try {
7946
+ return fileURLToPath(uri);
7947
+ } catch {
7948
+ return null;
7949
+ }
7950
+ }
7951
+ function locationKey(location) {
7952
+ return `${location.path}:L${location.line}`;
7953
+ }
7954
+ function compressPath(filePath) {
7955
+ const cwd = process.cwd();
7956
+ if (filePath.startsWith(cwd)) {
7957
+ return "$cwd" + filePath.slice(cwd.length);
7958
+ }
7959
+ return filePath;
7960
+ }
7961
+ var lspInspectTool = createTool({
7962
+ id: WORKSPACE_TOOLS.LSP.LSP_INSPECT,
7963
+ description: "Inspect code at a specific symbol position using the Language Server Protocol. Provide an absolute file path, a 1-indexed line number, and the exact line content with <<< marking the cursor position. Exactly one <<< marker is required. Returns hover information, any diagnostics reported on that line, plus definition and implementation locations when available. Use this for type information, symbol navigation, and go-to-definition; use view to read the surrounding implementation.",
7964
+ inputSchema: z.object({
7965
+ path: z.string().describe("Absolute path to the file"),
7966
+ line: z.number().int().positive().describe("Line number (1-indexed)"),
7967
+ match: z.string().describe(
7968
+ 'Line content with <<< marking the cursor position. Exactly one <<< marker is required. Example: "const foo = <<<bar()" means cursor is at bar'
7969
+ )
7970
+ }),
7971
+ execute: async ({ path: filePath, line, match }, context) => {
7972
+ const workspace = requireWorkspace(context);
7973
+ await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.LSP.LSP_INSPECT);
7974
+ const cursorPositions = [];
7975
+ let searchStart = 0;
7976
+ while (true) {
7977
+ const pos = match.indexOf(CURSOR_MARKER, searchStart);
7978
+ if (pos === -1) break;
7979
+ cursorPositions.push(pos);
7980
+ searchStart = pos + CURSOR_MARKER.length;
7981
+ }
7982
+ if (cursorPositions.length === 0) {
7983
+ return {
7984
+ error: `No <<< cursor marker found in match`
7985
+ };
7986
+ }
7987
+ if (cursorPositions.length > 1) {
7988
+ return {
7989
+ error: `Multiple <<< markers found (found ${cursorPositions.length}, expected 1)`
7990
+ };
7991
+ }
7992
+ const character = cursorPositions[0] + 1;
7993
+ const lspManager = workspace.lsp;
7994
+ if (!lspManager) {
7995
+ return {
7996
+ error: "LSP is not configured for this workspace. Enable LSP in workspace config to use this tool."
7997
+ };
7998
+ }
7999
+ const absolutePath = getAbsolutePath(
8000
+ filePath,
8001
+ lspManager.root,
8002
+ workspace.filesystem?.resolveAbsolutePath?.bind(workspace.filesystem)
8003
+ );
8004
+ let fileContent = "";
8005
+ try {
8006
+ fileContent = await fs2__default.readFile(absolutePath, "utf-8");
8007
+ } catch {
8008
+ fileContent = "";
8009
+ }
8010
+ let queryResult;
8011
+ try {
8012
+ queryResult = await lspManager.prepareQuery(absolutePath);
8013
+ } catch (err) {
8014
+ return {
8015
+ error: `Failed to initialize LSP client: ${err instanceof Error ? err.message : String(err)}`
8016
+ };
8017
+ }
8018
+ if (!queryResult) {
8019
+ return {
8020
+ error: `No language server available for files of this type: ${filePath}`
8021
+ };
8022
+ }
8023
+ const { client, uri } = queryResult;
8024
+ const position = { line: line - 1, character: character - 1 };
8025
+ const result = {};
8026
+ try {
8027
+ const hoverResult = await client.queryHover(uri, position).catch(() => null);
8028
+ if (hoverResult) {
8029
+ const contents = hoverResult.contents;
8030
+ if (contents) {
8031
+ if (typeof contents === "string") {
8032
+ result.hover = { value: contents, kind: "plaintext" };
8033
+ } else if (Array.isArray(contents)) {
8034
+ const first = contents[0];
8035
+ if (typeof first === "string") {
8036
+ result.hover = { value: first, kind: "plaintext" };
8037
+ } else if (first?.value) {
8038
+ result.hover = { value: first.value, kind: first.kind ?? "markdown" };
8039
+ }
8040
+ } else if (contents.value) {
8041
+ result.hover = { value: contents.value, kind: contents.kind ?? "markdown" };
8042
+ }
8043
+ }
8044
+ }
8045
+ const diagnosticsPromise = fileContent ? Promise.resolve().then(() => {
8046
+ client.notifyChange(absolutePath, fileContent, 1);
8047
+ return client.waitForDiagnostics(absolutePath, 5e3, true);
8048
+ }).catch(() => []) : Promise.resolve([]);
8049
+ const [diagnosticsResult, definitionResult, implResult] = await Promise.all([
8050
+ diagnosticsPromise,
8051
+ client.queryDefinition(uri, position).catch(() => []),
8052
+ client.queryImplementation(uri, position).catch(() => [])
8053
+ ]);
8054
+ if (diagnosticsResult && diagnosticsResult.length > 0) {
8055
+ const lineDiagnostics = diagnosticsResult.map((diagnostic) => ({
8056
+ line: typeof diagnostic.line === "number" ? diagnostic.line : (diagnostic.range?.start?.line ?? -1) + 1,
8057
+ severity: typeof diagnostic.severity === "number" ? diagnostic.severity === 1 ? "error" : diagnostic.severity === 2 ? "warning" : diagnostic.severity === 3 ? "info" : "hint" : diagnostic.severity,
8058
+ message: diagnostic.message,
8059
+ source: diagnostic.source ?? null
8060
+ })).filter((diagnostic) => diagnostic.line === line).map(({ severity, message, source }) => ({ severity, message, source }));
8061
+ if (lineDiagnostics.length > 0) {
8062
+ result.diagnostics = lineDiagnostics;
8063
+ }
8064
+ }
8065
+ const definitionLocations = definitionResult.map((loc) => ({
8066
+ uri: loc.uri ?? loc.targetUri,
8067
+ range: loc.range ?? loc.targetRange
8068
+ })).map((loc) => {
8069
+ const resolvedPath = loc.uri ? locationUriToPath(String(loc.uri)) : null;
8070
+ return resolvedPath ? {
8071
+ path: resolvedPath,
8072
+ line: (loc.range?.start?.line ?? 0) + 1,
8073
+ character: (loc.range?.start?.character ?? 0) + 1
8074
+ } : null;
8075
+ }).filter((loc) => Boolean(loc)).filter((loc) => !(loc.path === absolutePath && loc.line === line));
8076
+ if (definitionLocations.length > 0) {
8077
+ const previews = await Promise.all(definitionLocations.map((loc) => getLinePreview(loc.path, loc.line)));
8078
+ result.definition = definitionLocations.map((loc, i) => ({
8079
+ location: `${compressPath(loc.path)}:L${loc.line}:C${loc.character}`,
8080
+ preview: previews[i]
8081
+ }));
8082
+ }
8083
+ const definitionKeys = new Set(definitionLocations.map(locationKey));
8084
+ const implementationLocations = implResult.map((loc) => ({
8085
+ uri: loc.uri ?? loc.targetUri,
8086
+ range: loc.range ?? loc.targetRange
8087
+ })).map((loc) => {
8088
+ const resolvedPath = loc.uri ? locationUriToPath(String(loc.uri)) : null;
8089
+ return resolvedPath ? {
8090
+ path: resolvedPath,
8091
+ line: (loc.range?.start?.line ?? 0) + 1,
8092
+ character: (loc.range?.start?.character ?? 0) + 1
8093
+ } : null;
8094
+ }).filter((loc) => Boolean(loc)).filter((loc) => !definitionKeys.has(locationKey(loc)) && !(loc.path === absolutePath && loc.line === line));
8095
+ if (implementationLocations.length > 0) {
8096
+ result.implementation = implementationLocations.map(
8097
+ (loc) => `${compressPath(loc.path)}:L${loc.line}:C${loc.character}`
8098
+ );
8099
+ }
8100
+ } catch (err) {
8101
+ result.error = `LSP query failed: ${err instanceof Error ? err.message : String(err)}`;
8102
+ } finally {
8103
+ client.notifyClose(absolutePath);
8104
+ }
8105
+ return result;
8106
+ }
8107
+ });
7831
8108
  var mkdirTool = createTool({
7832
8109
  id: WORKSPACE_TOOLS.FILESYSTEM.MKDIR,
7833
8110
  description: "Create a directory in the workspace filesystem",
@@ -7835,14 +8112,14 @@ var mkdirTool = createTool({
7835
8112
  path: z.string().describe("The path of the directory to create"),
7836
8113
  recursive: z.boolean().optional().default(true).describe("Whether to create parent directories if they do not exist")
7837
8114
  }),
7838
- execute: async ({ path: path7, recursive }, context) => {
8115
+ execute: async ({ path: path8, recursive }, context) => {
7839
8116
  const { filesystem } = requireFilesystem(context);
7840
8117
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.MKDIR);
7841
8118
  if (filesystem.readOnly) {
7842
8119
  throw new WorkspaceReadOnlyError("mkdir");
7843
8120
  }
7844
- await filesystem.mkdir(path7, { recursive });
7845
- return `Created directory ${path7}`;
8121
+ await filesystem.mkdir(path8, { recursive });
8122
+ return `Created directory ${path8}`;
7846
8123
  }
7847
8124
  });
7848
8125
  var readFileTool = createTool({
@@ -7855,12 +8132,12 @@ var readFileTool = createTool({
7855
8132
  limit: z.number().optional().describe("Maximum number of lines to read. If omitted, reads to the end of the file."),
7856
8133
  showLineNumbers: z.boolean().optional().default(true).describe("Whether to prefix each line with its line number (default: true)")
7857
8134
  }),
7858
- execute: async ({ path: path7, encoding, offset, limit, showLineNumbers }, context) => {
8135
+ execute: async ({ path: path8, encoding, offset, limit, showLineNumbers }, context) => {
7859
8136
  const { workspace, filesystem } = requireFilesystem(context);
7860
8137
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.READ_FILE);
7861
8138
  const effectiveEncoding = encoding ?? "utf-8";
7862
- const fullContent = await filesystem.readFile(path7, { encoding: effectiveEncoding });
7863
- const stat3 = await filesystem.stat(path7);
8139
+ const fullContent = await filesystem.readFile(path8, { encoding: effectiveEncoding });
8140
+ const stat3 = await filesystem.stat(path8);
7864
8141
  const isTextEncoding = !encoding || encoding === "utf-8" || encoding === "utf8";
7865
8142
  const tokenLimit = workspace.getToolsConfig()?.[WORKSPACE_TOOLS.FILESYSTEM.READ_FILE]?.maxOutputTokens;
7866
8143
  if (!isTextEncoding) {
@@ -7928,19 +8205,19 @@ var writeFileTool = createTool({
7928
8205
  content: z.string().describe("The content to write to the file"),
7929
8206
  overwrite: z.boolean().optional().default(true).describe("Whether to overwrite the file if it already exists")
7930
8207
  }),
7931
- execute: async ({ path: path7, content, overwrite }, context) => {
8208
+ execute: async ({ path: path8, content, overwrite }, context) => {
7932
8209
  const { workspace, filesystem } = requireFilesystem(context);
7933
8210
  await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE);
7934
8211
  if (filesystem.readOnly) {
7935
8212
  throw new WorkspaceReadOnlyError("write_file");
7936
8213
  }
7937
- await filesystem.writeFile(path7, content, {
8214
+ await filesystem.writeFile(path8, content, {
7938
8215
  overwrite,
7939
8216
  expectedMtime: context?.__expectedMtime
7940
8217
  });
7941
8218
  const size = Buffer.byteLength(content, "utf-8");
7942
- let output = `Wrote ${size} bytes to ${path7}`;
7943
- output += await getEditDiagnosticsText(workspace, path7, content);
8219
+ let output = `Wrote ${size} bytes to ${path8}`;
8220
+ output += await getEditDiagnosticsText(workspace, path8, content);
7944
8221
  return output;
7945
8222
  }
7946
8223
  });
@@ -8095,9 +8372,10 @@ function createWorkspaceTools(workspace) {
8095
8372
  addTool(WORKSPACE_TOOLS.SANDBOX.KILL_PROCESS, killProcessTool);
8096
8373
  }
8097
8374
  }
8375
+ addTool(WORKSPACE_TOOLS.LSP.LSP_INSPECT, lspInspectTool);
8098
8376
  return tools;
8099
8377
  }
8100
8378
 
8101
8379
  export { BM25Index, CompositeFilesystem, CompositeVersionedSkillSource, DirectoryNotEmptyError, DirectoryNotFoundError, FileExistsError, FileNotFoundError, FileReadRequiredError, FilesystemError, FilesystemNotAvailableError, FilesystemNotMountableError, FilesystemNotReadyError, IsDirectoryError, IsolationUnavailableError, LocalFilesystem, LocalSandbox, LocalSkillSource, MastraFilesystem, MastraSandbox, MountError, MountManager, MountNotSupportedError, NotDirectoryError, PermissionError, ProcessHandle, SandboxError, SandboxExecutionError, SandboxFeatureNotSupportedError, SandboxNotAvailableError, SandboxNotReadyError, SandboxProcessManager, SandboxTimeoutError, SearchNotAvailableError, StaleFileError, VersionedSkillSource, WORKSPACE_TOOLS, WORKSPACE_TOOLS_PREFIX, Workspace, WorkspaceError, WorkspaceNotAvailableError, WorkspaceNotReadyError, WorkspaceReadOnlyError, callLifecycle, collectSkillForPublish, createGlobMatcher, createSkillTools, createWorkspaceTools, deleteFileTool, detectIsolation, editFileTool, executeCommandTool, extractGlobBase, fileStatTool, getRecommendedIsolation, getTiktoken, indexContentTool, isGlobPattern, isIsolationAvailable, listFilesTool, matchGlob, mkdirTool, publishSkillFromSource, readFileTool, requireFilesystem, requireSandbox, requireWorkspace, resolveToolConfig, searchTool, writeFileTool };
8102
- //# sourceMappingURL=chunk-J3NJXIJ4.js.map
8103
- //# sourceMappingURL=chunk-J3NJXIJ4.js.map
8380
+ //# sourceMappingURL=chunk-ABA3KD3X.js.map
8381
+ //# sourceMappingURL=chunk-ABA3KD3X.js.map