@aexol/spectral 0.9.155 → 0.9.157

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 (69) hide show
  1. package/dist/cli.js +5 -13
  2. package/dist/commands/serve.d.ts.map +1 -1
  3. package/dist/commands/serve.js +8 -20
  4. package/dist/commands/update.d.ts.map +1 -1
  5. package/dist/commands/update.js +6 -15
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/mcp/direct-tools.js +1 -1
  10. package/dist/memory/tool-output-compressor.d.ts +1 -1
  11. package/dist/memory/tool-output-compressor.d.ts.map +1 -1
  12. package/dist/memory/tool-output-compressor.js +1 -32
  13. package/dist/relay/dispatcher.d.ts.map +1 -1
  14. package/dist/relay/dispatcher.js +7 -1
  15. package/dist/sdk/agent-core/types.d.ts +1 -1
  16. package/dist/sdk/ai/env-api-keys.d.ts.map +1 -1
  17. package/dist/sdk/ai/env-api-keys.js +0 -3
  18. package/dist/sdk/ai/models.generated.d.ts +0 -515
  19. package/dist/sdk/ai/models.generated.d.ts.map +1 -1
  20. package/dist/sdk/ai/models.generated.js +0 -361
  21. package/dist/sdk/ai/providers/anthropic.d.ts.map +1 -1
  22. package/dist/sdk/ai/providers/anthropic.js +2 -26
  23. package/dist/sdk/ai/providers/openai-completions.d.ts.map +1 -1
  24. package/dist/sdk/ai/providers/openai-completions.js +0 -9
  25. package/dist/sdk/ai/types.d.ts +1 -1
  26. package/dist/sdk/ai/types.d.ts.map +1 -1
  27. package/dist/sdk/ai/utils/oauth/index.d.ts +0 -2
  28. package/dist/sdk/ai/utils/oauth/index.d.ts.map +1 -1
  29. package/dist/sdk/ai/utils/oauth/index.js +0 -5
  30. package/dist/sdk/ai/utils/overflow.d.ts.map +1 -1
  31. package/dist/sdk/ai/utils/overflow.js +1 -2
  32. package/dist/sdk/coding-agent/config.d.ts.map +1 -1
  33. package/dist/sdk/coding-agent/config.js +2 -1
  34. package/dist/sdk/coding-agent/core/extensions/index.d.ts +2 -2
  35. package/dist/sdk/coding-agent/core/extensions/index.d.ts.map +1 -1
  36. package/dist/sdk/coding-agent/core/extensions/index.js +1 -1
  37. package/dist/sdk/coding-agent/core/extensions/types.d.ts +3 -13
  38. package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
  39. package/dist/sdk/coding-agent/core/extensions/types.js +0 -3
  40. package/dist/sdk/coding-agent/core/model-resolver.d.ts.map +1 -1
  41. package/dist/sdk/coding-agent/core/model-resolver.js +0 -1
  42. package/dist/sdk/coding-agent/core/sdk.d.ts +2 -2
  43. package/dist/sdk/coding-agent/core/sdk.d.ts.map +1 -1
  44. package/dist/sdk/coding-agent/core/sdk.js +2 -2
  45. package/dist/sdk/coding-agent/core/system-prompt.d.ts.map +1 -1
  46. package/dist/sdk/coding-agent/core/system-prompt.js +2 -4
  47. package/dist/sdk/coding-agent/core/tools/bash-blocklist.js +1 -1
  48. package/dist/sdk/coding-agent/core/tools/index.d.ts +1 -4
  49. package/dist/sdk/coding-agent/core/tools/index.d.ts.map +1 -1
  50. package/dist/sdk/coding-agent/core/tools/index.js +0 -11
  51. package/dist/sdk/coding-agent/index.d.ts +4 -4
  52. package/dist/sdk/coding-agent/index.d.ts.map +1 -1
  53. package/dist/sdk/coding-agent/index.js +3 -3
  54. package/dist/server/storage.d.ts +18 -0
  55. package/dist/server/storage.d.ts.map +1 -1
  56. package/dist/server/storage.js +47 -0
  57. package/dist/version.d.ts +4 -0
  58. package/dist/version.d.ts.map +1 -0
  59. package/dist/version.js +88 -0
  60. package/package.json +1 -1
  61. package/dist/sdk/ai/providers/github-copilot-headers.d.ts +0 -8
  62. package/dist/sdk/ai/providers/github-copilot-headers.d.ts.map +0 -1
  63. package/dist/sdk/ai/providers/github-copilot-headers.js +0 -28
  64. package/dist/sdk/ai/utils/oauth/github-copilot.d.ts +0 -30
  65. package/dist/sdk/ai/utils/oauth/github-copilot.d.ts.map +0 -1
  66. package/dist/sdk/ai/utils/oauth/github-copilot.js +0 -270
  67. package/dist/sdk/coding-agent/core/tools/find.d.ts +0 -35
  68. package/dist/sdk/coding-agent/core/tools/find.d.ts.map +0 -1
  69. package/dist/sdk/coding-agent/core/tools/find.js +0 -343
@@ -1,343 +0,0 @@
1
- import { createInterface } from "node:readline";
2
- import { spawn } from "child_process";
3
- import { existsSync } from "fs";
4
- import path from "path";
5
- import { Type } from "typebox";
6
- import { ensureTool } from "../../utils/tools-manager.js";
7
- import { resolveToCwd } from "./path-utils.js";
8
- import { getTextOutput, shortenPath, str } from "./render-utils.js";
9
- import { wrapToolDefinition } from "./tool-definition-wrapper.js";
10
- import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
11
- function toPosixPath(value) {
12
- return value.split(path.sep).join("/");
13
- }
14
- const findSchema = Type.Object({
15
- pattern: Type.String({
16
- description: "Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'",
17
- }),
18
- path: Type.Optional(Type.String({ description: "Directory to search in (default: current directory)" })),
19
- limit: Type.Optional(Type.Number({ description: "Maximum number of results (default: 1000)" })),
20
- });
21
- const DEFAULT_LIMIT = 1000;
22
- // Hard cap on how long a single fd invocation may run. Prevents the find tool
23
- // from hanging indefinitely when the search root contains large/irrelevant
24
- // trees (node_modules, .git, .next, build artifacts, project temp folders).
25
- const FD_TIMEOUT_MS = 20_000;
26
- // Directories and patterns excluded from fd searches regardless of .gitignore.
27
- // These are a safety net for trees that have no/incomplete .gitignore, and they
28
- // also catch project-specific temp folders the agent itself creates.
29
- const FD_EXCLUDE_PATTERNS = [
30
- "node_modules",
31
- ".git",
32
- ".next",
33
- "dist",
34
- "build",
35
- ".turbo",
36
- ".cache",
37
- ".tmp",
38
- "tmp",
39
- ".spectral",
40
- ".agent-cache",
41
- ".visual-agent-output",
42
- "coverage",
43
- ".deno-cache",
44
- "*.log",
45
- ];
46
- // Glob equivalents of FD_EXCLUDE_PATTERNS, used by the custom glob branch.
47
- const GLOB_IGNORE_PATTERNS = [
48
- "**/node_modules/**",
49
- "**/.git/**",
50
- "**/.next/**",
51
- "**/dist/**",
52
- "**/build/**",
53
- "**/.turbo/**",
54
- "**/.cache/**",
55
- "**/.tmp/**",
56
- "**/tmp/**",
57
- "**/.spectral/**",
58
- "**/.agent-cache/**",
59
- "**/.visual-agent-output/**",
60
- "**/coverage/**",
61
- "**/.deno-cache/**",
62
- "**/*.log",
63
- ];
64
- const defaultFindOperations = {
65
- exists: existsSync,
66
- // This is a placeholder. Actual fd execution happens in execute() when no custom glob is provided.
67
- glob: () => [],
68
- };
69
- function formatFindCall(args, _theme) {
70
- const pattern = str(args?.pattern);
71
- const rawPath = str(args?.path);
72
- const path = rawPath !== null ? shortenPath(rawPath || ".") : null;
73
- const limit = args?.limit;
74
- const invalidArg = "[invalid]";
75
- let text = `find ${pattern === null ? invalidArg : pattern || ""} in ${path === null ? invalidArg : path}`;
76
- if (limit !== undefined) {
77
- text += ` (limit ${limit})`;
78
- }
79
- return text;
80
- }
81
- function formatFindResult(result, options, _theme, showImages) {
82
- const output = getTextOutput(result, showImages).trim();
83
- let text = "";
84
- if (output) {
85
- const lines = output.split("\n");
86
- const maxLines = options.expanded ? lines.length : 20;
87
- const displayLines = lines.slice(0, maxLines);
88
- const remaining = lines.length - maxLines;
89
- text += `\n${displayLines.join("\n")}`;
90
- if (remaining > 0) {
91
- text += `\n... (${remaining} more lines)`;
92
- }
93
- }
94
- const resultLimit = result.details?.resultLimitReached;
95
- const truncation = result.details?.truncation;
96
- if (resultLimit || truncation?.truncated) {
97
- const warnings = [];
98
- if (resultLimit)
99
- warnings.push(`${resultLimit} results limit`);
100
- if (truncation?.truncated)
101
- warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
102
- text += `\n[Truncated: ${warnings.join(", ")}]`;
103
- }
104
- return text;
105
- }
106
- export function createFindToolDefinition(cwd, options) {
107
- const customOps = options?.operations;
108
- return {
109
- name: "find",
110
- label: "find",
111
- description: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,
112
- promptSnippet: "Find files by glob pattern (respects .gitignore)",
113
- parameters: findSchema,
114
- async execute(_toolCallId, { pattern, path: searchDir, limit }, signal, _onUpdate, _ctx) {
115
- return new Promise((resolve, reject) => {
116
- if (signal?.aborted) {
117
- reject(new Error("Operation aborted"));
118
- return;
119
- }
120
- let settled = false;
121
- let stopChild;
122
- const settle = (fn) => {
123
- if (settled)
124
- return;
125
- settled = true;
126
- signal?.removeEventListener("abort", onAbort);
127
- stopChild = undefined;
128
- fn();
129
- };
130
- const onAbort = () => {
131
- stopChild?.();
132
- settle(() => reject(new Error("Operation aborted")));
133
- };
134
- signal?.addEventListener("abort", onAbort, { once: true });
135
- (async () => {
136
- try {
137
- const searchPath = resolveToCwd(searchDir || ".", cwd);
138
- const effectiveLimit = limit ?? DEFAULT_LIMIT;
139
- const ops = customOps ?? defaultFindOperations;
140
- // If custom operations provide glob(), use that instead of fd.
141
- if (customOps?.glob) {
142
- if (!(await ops.exists(searchPath))) {
143
- settle(() => reject(new Error(`Path not found: ${searchPath}`)));
144
- return;
145
- }
146
- if (signal?.aborted) {
147
- settle(() => reject(new Error("Operation aborted")));
148
- return;
149
- }
150
- const results = await ops.glob(pattern, searchPath, {
151
- ignore: [...GLOB_IGNORE_PATTERNS],
152
- limit: effectiveLimit,
153
- });
154
- if (signal?.aborted) {
155
- settle(() => reject(new Error("Operation aborted")));
156
- return;
157
- }
158
- if (results.length === 0) {
159
- settle(() => resolve({
160
- content: [{ type: "text", text: "No files found matching pattern" }],
161
- details: undefined,
162
- }));
163
- return;
164
- }
165
- // Relativize paths against the search root for stable output.
166
- const relativized = results.map((p) => {
167
- if (p.startsWith(searchPath))
168
- return toPosixPath(p.slice(searchPath.length + 1));
169
- return toPosixPath(path.relative(searchPath, p));
170
- });
171
- const resultLimitReached = relativized.length >= effectiveLimit;
172
- const rawOutput = relativized.join("\n");
173
- const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
174
- let resultOutput = truncation.content;
175
- const details = {};
176
- const notices = [];
177
- if (resultLimitReached) {
178
- notices.push(`${effectiveLimit} results limit reached`);
179
- details.resultLimitReached = effectiveLimit;
180
- }
181
- if (truncation.truncated) {
182
- notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
183
- details.truncation = truncation;
184
- }
185
- if (notices.length > 0) {
186
- resultOutput += `\n\n[${notices.join(". ")}]`;
187
- }
188
- settle(() => resolve({
189
- content: [{ type: "text", text: resultOutput }],
190
- details: Object.keys(details).length > 0 ? details : undefined,
191
- }));
192
- return;
193
- }
194
- // Default implementation uses fd.
195
- const fdPath = await ensureTool("fd", true);
196
- if (signal?.aborted) {
197
- settle(() => reject(new Error("Operation aborted")));
198
- return;
199
- }
200
- if (!fdPath) {
201
- settle(() => reject(new Error("fd is not available and could not be downloaded")));
202
- return;
203
- }
204
- // Build fd arguments. --no-require-git makes fd apply hierarchical .gitignore
205
- // semantics whether or not the search path is inside a git repository, without
206
- // leaking sibling-directory rules the way --ignore-file (a global source) would.
207
- // --hidden is intentionally omitted: it caused fd to descend into .git/ and
208
- // .next/, which is the #1 cause of the find tool hanging on large trees.
209
- const args = [
210
- "--glob",
211
- "--color=never",
212
- "--no-require-git",
213
- "--max-results",
214
- String(effectiveLimit),
215
- ];
216
- // Safety net excludes independent of .gitignore (handles trees with no or
217
- // incomplete .gitignore). fd accepts repeated --exclude args.
218
- for (const pattern of FD_EXCLUDE_PATTERNS) {
219
- args.push("--exclude", pattern);
220
- }
221
- // fd --glob matches against the basename unless --full-path is set; in --full-path
222
- // mode it matches against the absolute candidate path, so a path-containing
223
- // pattern like 'src/**/*.spec.ts' needs a leading '**/' to match anything.
224
- let effectivePattern = pattern;
225
- if (pattern.includes("/")) {
226
- args.push("--full-path");
227
- if (!pattern.startsWith("/") && !pattern.startsWith("**/") && pattern !== "**") {
228
- effectivePattern = `**/${pattern}`;
229
- }
230
- }
231
- args.push("--", effectivePattern, searchPath);
232
- const child = spawn(fdPath, args, { stdio: ["ignore", "pipe", "pipe"] });
233
- const rl = createInterface({ input: child.stdout });
234
- let stderr = "";
235
- const lines = [];
236
- // Kill fd if it runs longer than FD_TIMEOUT_MS. Without this, a search
237
- // rooted at a large tree can hang the find tool indefinitely.
238
- let timedOut = false;
239
- const timeoutHandle = setTimeout(() => {
240
- timedOut = true;
241
- child.kill("SIGTERM");
242
- }, FD_TIMEOUT_MS);
243
- const clearTimer = () => clearTimeout(timeoutHandle);
244
- stopChild = () => {
245
- if (!child.killed) {
246
- child.kill();
247
- }
248
- };
249
- const cleanup = () => {
250
- clearTimer();
251
- rl.close();
252
- };
253
- child.stderr?.on("data", (chunk) => {
254
- stderr += chunk.toString();
255
- });
256
- rl.on("line", (line) => {
257
- lines.push(line);
258
- });
259
- child.on("error", (error) => {
260
- cleanup();
261
- settle(() => reject(new Error(`Failed to run fd: ${error.message}`)));
262
- });
263
- child.on("close", (code) => {
264
- cleanup();
265
- if (timedOut) {
266
- settle(() => reject(new Error(`Search timed out after ${FD_TIMEOUT_MS / 1000}s — the search scope was too large. Try narrowing the path or pattern.`)));
267
- return;
268
- }
269
- if (signal?.aborted) {
270
- settle(() => reject(new Error("Operation aborted")));
271
- return;
272
- }
273
- const output = lines.join("\n");
274
- if (code !== 0) {
275
- const errorMsg = stderr.trim() || `fd exited with code ${code}`;
276
- if (!output) {
277
- settle(() => reject(new Error(errorMsg)));
278
- return;
279
- }
280
- }
281
- if (!output) {
282
- settle(() => resolve({
283
- content: [{ type: "text", text: "No files found matching pattern" }],
284
- details: undefined,
285
- }));
286
- return;
287
- }
288
- const relativized = [];
289
- for (const rawLine of lines) {
290
- const line = rawLine.replace(/\r$/, "").trim();
291
- if (!line)
292
- continue;
293
- const hadTrailingSlash = line.endsWith("/") || line.endsWith("\\");
294
- let relativePath = line;
295
- if (line.startsWith(searchPath)) {
296
- relativePath = line.slice(searchPath.length + 1);
297
- }
298
- else {
299
- relativePath = path.relative(searchPath, line);
300
- }
301
- if (hadTrailingSlash && !relativePath.endsWith("/"))
302
- relativePath += "/";
303
- relativized.push(toPosixPath(relativePath));
304
- }
305
- const resultLimitReached = relativized.length >= effectiveLimit;
306
- const rawOutput = relativized.join("\n");
307
- const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
308
- let resultOutput = truncation.content;
309
- const details = {};
310
- const notices = [];
311
- if (resultLimitReached) {
312
- notices.push(`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`);
313
- details.resultLimitReached = effectiveLimit;
314
- }
315
- if (truncation.truncated) {
316
- notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
317
- details.truncation = truncation;
318
- }
319
- if (notices.length > 0) {
320
- resultOutput += `\n\n[${notices.join(". ")}]`;
321
- }
322
- settle(() => resolve({
323
- content: [{ type: "text", text: resultOutput }],
324
- details: Object.keys(details).length > 0 ? details : undefined,
325
- }));
326
- });
327
- }
328
- catch (e) {
329
- if (signal?.aborted) {
330
- settle(() => reject(new Error("Operation aborted")));
331
- return;
332
- }
333
- const error = e instanceof Error ? e : new Error(String(e));
334
- settle(() => reject(error));
335
- }
336
- })();
337
- });
338
- },
339
- };
340
- }
341
- export function createFindTool(cwd, options) {
342
- return wrapToolDefinition(createFindToolDefinition(cwd, options));
343
- }