@aexol/spectral 0.9.159 → 0.9.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +29 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/memory/tool-output-compressor.d.ts +8 -2
- package/dist/memory/tool-output-compressor.d.ts.map +1 -1
- package/dist/memory/tool-output-compressor.js +8 -83
- package/dist/sdk/coding-agent/core/compaction/policy.js +6 -6
- package/dist/sdk/coding-agent/core/extensions/index.d.ts +2 -2
- package/dist/sdk/coding-agent/core/extensions/index.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/index.js +1 -1
- package/dist/sdk/coding-agent/core/extensions/types.d.ts +3 -44
- package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/types.js +0 -12
- package/dist/sdk/coding-agent/core/package-manager.d.ts +0 -15
- package/dist/sdk/coding-agent/core/package-manager.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/package-manager.js +0 -80
- package/dist/sdk/coding-agent/core/sdk.d.ts +2 -2
- package/dist/sdk/coding-agent/core/sdk.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/sdk.js +3 -3
- package/dist/sdk/coding-agent/core/tools/bash-blocklist.js +1 -1
- package/dist/sdk/coding-agent/core/tools/index.d.ts +1 -13
- package/dist/sdk/coding-agent/core/tools/index.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/index.js +0 -44
- package/dist/sdk/coding-agent/index.d.ts +4 -4
- package/dist/sdk/coding-agent/index.d.ts.map +1 -1
- package/dist/sdk/coding-agent/index.js +3 -3
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +1 -0
- package/package.json +1 -1
- package/dist/sdk/coding-agent/core/tools/edit.d.ts +0 -45
- package/dist/sdk/coding-agent/core/tools/edit.d.ts.map +0 -1
- package/dist/sdk/coding-agent/core/tools/edit.js +0 -216
- package/dist/sdk/coding-agent/core/tools/grep.d.ts +0 -37
- package/dist/sdk/coding-agent/core/tools/grep.d.ts.map +0 -1
- package/dist/sdk/coding-agent/core/tools/grep.js +0 -288
- package/dist/sdk/coding-agent/core/tools/ls.d.ts +0 -37
- package/dist/sdk/coding-agent/core/tools/ls.d.ts.map +0 -1
- package/dist/sdk/coding-agent/core/tools/ls.js +0 -156
- package/dist/sdk/coding-agent/core/tools/write.d.ts +0 -23
- package/dist/sdk/coding-agent/core/tools/write.d.ts.map +0 -1
- package/dist/sdk/coding-agent/core/tools/write.js +0 -134
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from "fs";
|
|
2
|
-
import nodePath from "path";
|
|
3
|
-
import { Type } from "typebox";
|
|
4
|
-
import { resolveToCwd } from "./path-utils.js";
|
|
5
|
-
import { getTextOutput, shortenPath, str } from "./render-utils.js";
|
|
6
|
-
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
7
|
-
import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
|
|
8
|
-
const lsSchema = Type.Object({
|
|
9
|
-
path: Type.Optional(Type.String({ description: "Directory to list (default: current directory)" })),
|
|
10
|
-
limit: Type.Optional(Type.Number({ description: "Maximum number of entries to return (default: 500)" })),
|
|
11
|
-
});
|
|
12
|
-
const DEFAULT_LIMIT = 500;
|
|
13
|
-
const defaultLsOperations = {
|
|
14
|
-
exists: existsSync,
|
|
15
|
-
stat: statSync,
|
|
16
|
-
readdir: readdirSync,
|
|
17
|
-
};
|
|
18
|
-
function formatLsCall(args, _theme) {
|
|
19
|
-
const rawPath = str(args?.path);
|
|
20
|
-
const path = rawPath !== null ? shortenPath(rawPath || ".") : null;
|
|
21
|
-
const limit = args?.limit;
|
|
22
|
-
const invalidArg = "[invalid]";
|
|
23
|
-
let text = `ls ${path === null ? invalidArg : path}`;
|
|
24
|
-
if (limit !== undefined) {
|
|
25
|
-
text += ` (limit ${limit})`;
|
|
26
|
-
}
|
|
27
|
-
return text;
|
|
28
|
-
}
|
|
29
|
-
function formatLsResult(result, options, _theme, showImages) {
|
|
30
|
-
const output = getTextOutput(result, showImages).trim();
|
|
31
|
-
let text = "";
|
|
32
|
-
if (output) {
|
|
33
|
-
const lines = output.split("\n");
|
|
34
|
-
const maxLines = options.expanded ? lines.length : 20;
|
|
35
|
-
const displayLines = lines.slice(0, maxLines);
|
|
36
|
-
const remaining = lines.length - maxLines;
|
|
37
|
-
text += `\n${displayLines.join("\n")}`;
|
|
38
|
-
if (remaining > 0) {
|
|
39
|
-
text += `\n... (${remaining} more lines)`;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const entryLimit = result.details?.entryLimitReached;
|
|
43
|
-
const truncation = result.details?.truncation;
|
|
44
|
-
if (entryLimit || truncation?.truncated) {
|
|
45
|
-
const warnings = [];
|
|
46
|
-
if (entryLimit)
|
|
47
|
-
warnings.push(`${entryLimit} entries limit`);
|
|
48
|
-
if (truncation?.truncated)
|
|
49
|
-
warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
|
|
50
|
-
text += `\n[Truncated: ${warnings.join(", ")}]`;
|
|
51
|
-
}
|
|
52
|
-
return text;
|
|
53
|
-
}
|
|
54
|
-
export function createLsToolDefinition(cwd, options) {
|
|
55
|
-
const ops = options?.operations ?? defaultLsOperations;
|
|
56
|
-
return {
|
|
57
|
-
name: "ls",
|
|
58
|
-
label: "ls",
|
|
59
|
-
description: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,
|
|
60
|
-
promptSnippet: "List directory contents",
|
|
61
|
-
parameters: lsSchema,
|
|
62
|
-
async execute(_toolCallId, { path, limit }, signal, _onUpdate, _ctx) {
|
|
63
|
-
return new Promise((resolve, reject) => {
|
|
64
|
-
if (signal?.aborted) {
|
|
65
|
-
reject(new Error("Operation aborted"));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const onAbort = () => reject(new Error("Operation aborted"));
|
|
69
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
70
|
-
(async () => {
|
|
71
|
-
try {
|
|
72
|
-
const dirPath = resolveToCwd(path || ".", cwd);
|
|
73
|
-
const effectiveLimit = limit ?? DEFAULT_LIMIT;
|
|
74
|
-
// Check if path exists.
|
|
75
|
-
if (!(await ops.exists(dirPath))) {
|
|
76
|
-
reject(new Error(`Path not found: ${dirPath}`));
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// Check if path is a directory.
|
|
80
|
-
const stat = await ops.stat(dirPath);
|
|
81
|
-
if (!stat.isDirectory()) {
|
|
82
|
-
reject(new Error(`Not a directory: ${dirPath}`));
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
// Read directory entries.
|
|
86
|
-
let entries;
|
|
87
|
-
try {
|
|
88
|
-
entries = await ops.readdir(dirPath);
|
|
89
|
-
}
|
|
90
|
-
catch (e) {
|
|
91
|
-
reject(new Error(`Cannot read directory: ${e.message}`));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
// Sort alphabetically, case-insensitive.
|
|
95
|
-
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
96
|
-
// Format entries with directory indicators.
|
|
97
|
-
const results = [];
|
|
98
|
-
let entryLimitReached = false;
|
|
99
|
-
for (const entry of entries) {
|
|
100
|
-
if (results.length >= effectiveLimit) {
|
|
101
|
-
entryLimitReached = true;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
const fullPath = nodePath.join(dirPath, entry);
|
|
105
|
-
let suffix = "";
|
|
106
|
-
try {
|
|
107
|
-
const entryStat = await ops.stat(fullPath);
|
|
108
|
-
if (entryStat.isDirectory())
|
|
109
|
-
suffix = "/";
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
// Skip entries we cannot stat.
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
results.push(entry + suffix);
|
|
116
|
-
}
|
|
117
|
-
signal?.removeEventListener("abort", onAbort);
|
|
118
|
-
if (results.length === 0) {
|
|
119
|
-
resolve({ content: [{ type: "text", text: "(empty directory)" }], details: undefined });
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const rawOutput = results.join("\n");
|
|
123
|
-
// Apply byte truncation. There is no separate line limit because entry count is already capped.
|
|
124
|
-
const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
125
|
-
let output = truncation.content;
|
|
126
|
-
const details = {};
|
|
127
|
-
// Build actionable notices for truncation and entry limits.
|
|
128
|
-
const notices = [];
|
|
129
|
-
if (entryLimitReached) {
|
|
130
|
-
notices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);
|
|
131
|
-
details.entryLimitReached = effectiveLimit;
|
|
132
|
-
}
|
|
133
|
-
if (truncation.truncated) {
|
|
134
|
-
notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
|
|
135
|
-
details.truncation = truncation;
|
|
136
|
-
}
|
|
137
|
-
if (notices.length > 0) {
|
|
138
|
-
output += `\n\n[${notices.join(". ")}]`;
|
|
139
|
-
}
|
|
140
|
-
resolve({
|
|
141
|
-
content: [{ type: "text", text: output }],
|
|
142
|
-
details: Object.keys(details).length > 0 ? details : undefined,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
catch (e) {
|
|
146
|
-
signal?.removeEventListener("abort", onAbort);
|
|
147
|
-
reject(e);
|
|
148
|
-
}
|
|
149
|
-
})();
|
|
150
|
-
});
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
export function createLsTool(cwd, options) {
|
|
155
|
-
return wrapToolDefinition(createLsToolDefinition(cwd, options));
|
|
156
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { AgentTool } from "../../../agent-core/index.js";
|
|
2
|
-
import { type Static, Type } from "typebox";
|
|
3
|
-
import type { ToolDefinition } from "../extensions/types.js";
|
|
4
|
-
declare const writeSchema: Type.TObject<{
|
|
5
|
-
path: Type.TString;
|
|
6
|
-
content: Type.TString;
|
|
7
|
-
}>;
|
|
8
|
-
export type WriteToolInput = Static<typeof writeSchema>;
|
|
9
|
-
export interface WriteOperations {
|
|
10
|
-
/**
|
|
11
|
-
* Optional atomic write override (temp file + rename). When omitted,
|
|
12
|
-
* the default {@link atomicWriteFile} helper is used.
|
|
13
|
-
*/
|
|
14
|
-
atomicWrite?: (absolutePath: string, content: string) => Promise<void>;
|
|
15
|
-
mkdir: (dir: string) => Promise<void>;
|
|
16
|
-
}
|
|
17
|
-
export interface WriteToolOptions {
|
|
18
|
-
operations?: WriteOperations;
|
|
19
|
-
}
|
|
20
|
-
export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition<typeof writeSchema, undefined>;
|
|
21
|
-
export declare function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema>;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=write.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAG9D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAe7D,QAAA,MAAM,WAAW;;;EAKf,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AACxD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAID,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AA+DD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACzB,cAAc,CAAC,OAAO,WAAW,EAAE,SAAS,CAAC,CA+E/C;AACD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACzB,SAAS,CAAC,OAAO,WAAW,CAAC,CAE/B"}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { mkdir as fsMkdir } from "fs/promises";
|
|
2
|
-
import { dirname } from "path";
|
|
3
|
-
import { Type } from "typebox";
|
|
4
|
-
import { getLanguageFromPath, highlightCode } from "../theme.js";
|
|
5
|
-
import { atomicWriteFile, defaultAtomicWriteOperations, } from "./atomic-write.js";
|
|
6
|
-
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
7
|
-
import { resolveToCwd } from "./path-utils.js";
|
|
8
|
-
import { normalizeDisplayText, replaceTabs, shortenPath, str, } from "./render-utils.js";
|
|
9
|
-
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
10
|
-
const writeSchema = Type.Object({
|
|
11
|
-
path: Type.String({
|
|
12
|
-
description: "Path to the file to write (relative or absolute)",
|
|
13
|
-
}),
|
|
14
|
-
content: Type.String({ description: "Content to write to the file" }),
|
|
15
|
-
});
|
|
16
|
-
const defaultWriteOperations = {
|
|
17
|
-
mkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => { }),
|
|
18
|
-
};
|
|
19
|
-
function trimTrailingEmptyLines(lines) {
|
|
20
|
-
let end = lines.length;
|
|
21
|
-
while (end > 0 && lines[end - 1] === "") {
|
|
22
|
-
end--;
|
|
23
|
-
}
|
|
24
|
-
return lines.slice(0, end);
|
|
25
|
-
}
|
|
26
|
-
function formatWriteCall(args, options, _theme) {
|
|
27
|
-
const rawPath = str(args?.file_path ?? args?.path);
|
|
28
|
-
const fileContent = str(args?.content);
|
|
29
|
-
const path = rawPath !== null ? shortenPath(rawPath) : null;
|
|
30
|
-
const pathDisplay = path === null ? "[invalid]" : path || "...";
|
|
31
|
-
let text = `write ${pathDisplay}`;
|
|
32
|
-
if (fileContent === null) {
|
|
33
|
-
text += `\n\n[invalid content arg - expected string]`;
|
|
34
|
-
}
|
|
35
|
-
else if (fileContent) {
|
|
36
|
-
const lines = trimTrailingEmptyLines(normalizeDisplayText(fileContent).split("\n"));
|
|
37
|
-
const totalLines = lines.length;
|
|
38
|
-
const maxLines = options.expanded ? totalLines : 10;
|
|
39
|
-
const preview = lines.slice(0, maxLines);
|
|
40
|
-
const lang = rawPath ? getLanguageFromPath(rawPath) : undefined;
|
|
41
|
-
const displayLines = lang
|
|
42
|
-
? highlightCode(replaceTabs(preview.join("\n")), lang)
|
|
43
|
-
: preview;
|
|
44
|
-
const remaining = totalLines - maxLines;
|
|
45
|
-
text += `\n\n${displayLines.join("\n")}`;
|
|
46
|
-
if (remaining > 0) {
|
|
47
|
-
text += `\n... (${remaining} more lines, ${totalLines} total)`;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return text;
|
|
51
|
-
}
|
|
52
|
-
function formatWriteResult(result, _theme) {
|
|
53
|
-
if (!result.isError) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
const output = result.content
|
|
57
|
-
.filter((c) => c.type === "text")
|
|
58
|
-
.map((c) => c.text || "")
|
|
59
|
-
.join("\n");
|
|
60
|
-
if (!output) {
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
return `\n${output}`;
|
|
64
|
-
}
|
|
65
|
-
export function createWriteToolDefinition(cwd, options) {
|
|
66
|
-
const ops = options?.operations ?? defaultWriteOperations;
|
|
67
|
-
const atomicOps = defaultAtomicWriteOperations;
|
|
68
|
-
return {
|
|
69
|
-
name: "write",
|
|
70
|
-
label: "write",
|
|
71
|
-
description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
|
72
|
-
promptSnippet: "Create or overwrite files",
|
|
73
|
-
promptGuidelines: ["Use write only for new files or complete rewrites."],
|
|
74
|
-
parameters: writeSchema,
|
|
75
|
-
async execute(_toolCallId, { path, content }, signal, _onUpdate, _ctx) {
|
|
76
|
-
const absolutePath = resolveToCwd(path, cwd);
|
|
77
|
-
const dir = dirname(absolutePath);
|
|
78
|
-
return withFileMutationQueue(absolutePath, () => new Promise((resolve, reject) => {
|
|
79
|
-
// Abort BEFORE the write begins -> reject immediately.
|
|
80
|
-
if (signal?.aborted) {
|
|
81
|
-
reject(new Error("Operation aborted"));
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
let aborted = false;
|
|
85
|
-
let writeStarted = false;
|
|
86
|
-
const onAbort = () => {
|
|
87
|
-
aborted = true;
|
|
88
|
-
// W2: only reject when aborted BEFORE the write begins. An abort
|
|
89
|
-
// that fires during/after the write must not swallow the
|
|
90
|
-
// successful resolve once the write completes.
|
|
91
|
-
if (!writeStarted) {
|
|
92
|
-
reject(new Error("Operation aborted"));
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
96
|
-
(async () => {
|
|
97
|
-
try {
|
|
98
|
-
await ops.mkdir(dir);
|
|
99
|
-
// Reject if aborted before the write begins.
|
|
100
|
-
if (aborted)
|
|
101
|
-
return;
|
|
102
|
-
writeStarted = true;
|
|
103
|
-
// W1 + W5: atomic write (temp + rename). On failure the
|
|
104
|
-
// temp is cleaned up and the target is left untouched.
|
|
105
|
-
const writeFn = ops.atomicWrite ??
|
|
106
|
-
((p, c) => atomicWriteFile(p, c, "utf-8", atomicOps));
|
|
107
|
-
await writeFn(absolutePath, content);
|
|
108
|
-
// W2: once the write has completed successfully, resolve
|
|
109
|
-
// with the success content even if the abort signal
|
|
110
|
-
// fired mid-write. Do NOT swallow the resolve.
|
|
111
|
-
signal?.removeEventListener("abort", onAbort);
|
|
112
|
-
resolve({
|
|
113
|
-
content: [
|
|
114
|
-
{
|
|
115
|
-
type: "text",
|
|
116
|
-
text: `Successfully wrote ${Buffer.byteLength(content, "utf-8")} bytes to ${path}`,
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
details: undefined,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
signal?.removeEventListener("abort", onAbort);
|
|
124
|
-
if (!aborted)
|
|
125
|
-
reject(error);
|
|
126
|
-
}
|
|
127
|
-
})();
|
|
128
|
-
}));
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
export function createWriteTool(cwd, options) {
|
|
133
|
-
return wrapToolDefinition(createWriteToolDefinition(cwd, options));
|
|
134
|
-
}
|