@wrongstack/tools 1.0.7 → 1.0.9
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/_win32-resolve.d.ts +5 -0
- package/dist/audit.js +5 -5
- package/dist/bash.js +2 -2
- package/dist/browser/index.js +1 -1
- package/dist/builtin.js +41 -41
- package/dist/{chunk-N3OTTQNC.js → chunk-2OCAAFAT.js} +44 -25
- package/dist/{chunk-5MP76C72.js → chunk-2UVAIS5O.js} +24 -29
- package/dist/{chunk-SIIOHBNY.js → chunk-3RRK33YM.js} +2 -2
- package/dist/{chunk-M2W36JT7.js → chunk-4CE3RKEP.js} +6 -3
- package/dist/{chunk-QJARSK2G.js → chunk-4SUGLJLO.js} +11 -3
- package/dist/{chunk-AH7J5HWL.js → chunk-5RBUYFRV.js} +15 -7
- package/dist/{chunk-WKLUOXR4.js → chunk-7GOE2ZTZ.js} +2 -2
- package/dist/{chunk-O6AGFJBO.js → chunk-7V33PHT6.js} +49 -77
- package/dist/{chunk-CAF4L6KN.js → chunk-C3WP6ZOT.js} +36 -48
- package/dist/{chunk-KMXPP32M.js → chunk-C6ZOXNXV.js} +13 -3
- package/dist/{chunk-EGT5QLCB.js → chunk-D6RQZMZS.js} +123 -255
- package/dist/{chunk-S6CGSFLX.js → chunk-DBG7UQGK.js} +10 -3
- package/dist/{chunk-2W4XTULI.js → chunk-DLZCOEVG.js} +50 -8
- package/dist/{chunk-NL45OWEO.js → chunk-DOAHONOS.js} +7 -12
- package/dist/{chunk-3LQJXJDM.js → chunk-E7A4SLKR.js} +2 -2
- package/dist/{chunk-JB5JLY7V.js → chunk-ENE22I5W.js} +387 -394
- package/dist/{chunk-SEONDNLN.js → chunk-G7CYW5EP.js} +2 -2
- package/dist/{chunk-YPSIG23D.js → chunk-HV7RWDCL.js} +3 -3
- package/dist/{chunk-TU6UVATU.js → chunk-HYHE4VNA.js} +3 -3
- package/dist/{chunk-HIRVCXLP.js → chunk-IE4KDAOB.js} +3 -3
- package/dist/{chunk-YA2ZYCJY.js → chunk-JPK2HHBK.js} +1 -1
- package/dist/{chunk-7E55DAFW.js → chunk-KHUCKLOR.js} +12 -7
- package/dist/{chunk-R3HIZVFS.js → chunk-KPDCKSN5.js} +23 -3
- package/dist/{chunk-B3MGJBFI.js → chunk-KS2OEZWV.js} +23 -47
- package/dist/{chunk-UI3ZJIG3.js → chunk-LKLIQUCW.js} +14 -8
- package/dist/{chunk-62OAECEQ.js → chunk-LLSFOUZF.js} +8 -8
- package/dist/{chunk-YZQSUL5G.js → chunk-M4ZHHCCW.js} +14 -6
- package/dist/{chunk-IXIS7RSG.js → chunk-MRXWOOOR.js} +29 -47
- package/dist/{chunk-C4DSQBTT.js → chunk-NEYUPZL6.js} +3 -3
- package/dist/{chunk-6XYFYLN7.js → chunk-O2MHULBO.js} +13 -8
- package/dist/{chunk-B62LKMWQ.js → chunk-OKZJJDOG.js} +86 -188
- package/dist/{chunk-JKFIDWQG.js → chunk-ON6ET5ER.js} +52 -9
- package/dist/{chunk-KF7GMVNU.js → chunk-OUERRFEM.js} +32 -11
- package/dist/{chunk-4DK5WZGR.js → chunk-OXO773CW.js} +127 -196
- package/dist/{chunk-GF4JHLCO.js → chunk-PWZUHZP7.js} +2 -2
- package/dist/{chunk-CLJXKFVS.js → chunk-QA37PFYL.js} +29 -68
- package/dist/{chunk-A3LNNBYO.js → chunk-QAWI3RSK.js} +41 -83
- package/dist/{chunk-ZMCV3XOV.js → chunk-SPNXDTCJ.js} +29 -63
- package/dist/{chunk-H2VB7GCR.js → chunk-ULI2J6TX.js} +27 -14
- package/dist/{chunk-EMA2XENR.js → chunk-UVYRQKPZ.js} +4 -3
- package/dist/{chunk-2NTHMZV3.js → chunk-VMJY6FYJ.js} +693 -276
- package/dist/{chunk-KPR53VKZ.js → chunk-WEUEU53R.js} +2 -2
- package/dist/{chunk-ZOUG3KKS.js → chunk-XPVYZ2S6.js} +2 -2
- package/dist/{chunk-5U5ULQX2.js → chunk-XZLVJD56.js} +5 -1
- package/dist/{chunk-HCPSVK7J.js → chunk-YKSOSI2N.js} +47 -31
- package/dist/codebase-index/codebase-ast-replace-tool.d.ts +5 -6
- package/dist/codebase-index/codebase-context-tool.d.ts +4 -6
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-index-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-invariant-check-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-repo-map-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-search-tool.d.ts +1 -1
- package/dist/codebase-index/codebase-targeted-test-tool.d.ts +1 -2
- package/dist/codebase-index/index.js +8 -8
- package/dist/codebase-index/parser-worker-script.js +3 -3
- package/dist/codebase-index/project-server.js +5 -5
- package/dist/codebase-index/worker.js +4 -4
- package/dist/design.js +1 -1
- package/dist/diff.js +1 -1
- package/dist/edit.js +7 -7
- package/dist/exec.d.ts +7 -7
- package/dist/exec.js +2 -2
- package/dist/format.js +5 -5
- package/dist/git.js +1 -1
- package/dist/glob.js +1 -1
- package/dist/{go-parser-VDPRQEGM.js → go-parser-Z4H6SR3R.js} +6 -3
- package/dist/grep.js +1 -1
- package/dist/index.js +45 -45
- package/dist/install.js +5 -5
- package/dist/json.d.ts +0 -1
- package/dist/json.js +1 -1
- package/dist/kanban-presence.d.ts +6 -0
- package/dist/kanban-serializer.d.ts +9 -1
- package/dist/kanban-split-task-handler.d.ts +1 -1
- package/dist/kanban-tool-results.d.ts +57 -2
- package/dist/kanban-tool-types.d.ts +16 -5
- package/dist/kanban.d.ts +14 -0
- package/dist/kanban.js +9 -1
- package/dist/languages/index.js +3 -3
- package/dist/{legacy-bridge-4T4OTSQP.js → legacy-bridge-BPT2S2F4.js} +5 -5
- package/dist/lint.js +5 -5
- package/dist/logs.js +1 -1
- package/dist/mode.d.ts +3 -2
- package/dist/mode.js +1 -1
- package/dist/outdated.js +2 -2
- package/dist/pack.js +42 -42
- package/dist/{parser-dispatch-4E2SDQUO.js → parser-dispatch-WG4DNBHH.js} +4 -4
- package/dist/patch.js +7 -7
- package/dist/plan.d.ts +2 -1
- package/dist/plan.js +3 -3
- package/dist/{py-parser-MAW6DHFE.js → py-parser-4PFZYAJ7.js} +3 -3
- package/dist/read.js +7 -7
- package/dist/replace.js +7 -7
- package/dist/search.d.ts +0 -6
- package/dist/search.js +1 -1
- package/dist/security-ast-scan-tool.d.ts +1 -2
- package/dist/session-shell.js +2 -2
- package/dist/task.d.ts +2 -1
- package/dist/task.js +3 -3
- package/dist/test.d.ts +8 -1
- package/dist/test.js +5 -5
- package/dist/todo.js +2 -2
- package/dist/tool-search.d.ts +2 -0
- package/dist/tool-search.js +1 -1
- package/dist/tool-tier.js +43 -43
- package/dist/tool-use.d.ts +2 -2
- package/dist/tool-use.js +1 -1
- package/dist/tree.js +1 -1
- package/dist/typecheck.js +5 -5
- package/dist/wasm/bash/tree-sitter-bash.wasm +0 -0
- package/dist/wasm/c/tree-sitter-c.wasm +0 -0
- package/dist/wasm/c_sharp/tree-sitter-c_sharp.wasm +0 -0
- package/dist/wasm/checksums.json +16 -0
- package/dist/wasm/cpp/tree-sitter-cpp.wasm +0 -0
- package/dist/wasm/elixir/tree-sitter-elixir.wasm +0 -0
- package/dist/wasm/go/tree-sitter-go.wasm +0 -0
- package/dist/wasm/java/tree-sitter-java.wasm +0 -0
- package/dist/wasm/kotlin/tree-sitter-kotlin.wasm +0 -0
- package/dist/wasm/php/tree-sitter-php.wasm +0 -0
- package/dist/wasm/python/tree-sitter-python.wasm +0 -0
- package/dist/wasm/ruby/tree-sitter-ruby.wasm +0 -0
- package/dist/wasm/rust/tree-sitter-rust.wasm +0 -0
- package/dist/wasm/swift/tree-sitter-swift.wasm +0 -0
- package/dist/wasm/tree-sitter-runtime.wasm +0 -0
- package/dist/win32.d.ts +1 -1
- package/dist/win32.js +3 -1
- package/dist/write.js +7 -7
- package/package.json +10 -10
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
|
|
9
9
|
// src/json.ts
|
|
10
10
|
import * as fs from "node:fs/promises";
|
|
11
|
-
import { deepMerge as deepMergeCore } from "@wrongstack/core/utils";
|
|
11
|
+
import { deepMerge as deepMergeCore, toErrorMessage } from "@wrongstack/core/utils";
|
|
12
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
12
13
|
var MAX_JSON_FILE_BYTES = 16 * 1024 * 1024;
|
|
13
14
|
var MAX_JSON_FILE_BYTES_HUMAN = "16 MiB";
|
|
14
15
|
var JsonFileTooLargeError = class extends Error {
|
|
@@ -39,8 +40,8 @@ async function readJsonFileBounded(filePath, ctx) {
|
|
|
39
40
|
var jsonTool = {
|
|
40
41
|
name: "json",
|
|
41
42
|
category: "Data",
|
|
42
|
-
description: "Parse, pretty-print, query, validate, transform, and merge JSON
|
|
43
|
-
usageHint: 'VERY USEFUL FOR DATA INSPECTION:\n\n- `action: "parse"` (default): read/pretty-print
|
|
43
|
+
description: "Parse, pretty-print, query, validate, transform, and merge JSON (read-only \u2014 does not write files). Input must be strict JSON; results can be rendered as JSON, JSON5-style, or YAML via `format`. Use `action` to select the operation: parse (default), query, validate, transform, or merge.",
|
|
44
|
+
usageHint: 'VERY USEFUL FOR DATA INSPECTION:\n\n- `action: "parse"` (default): read/pretty-print JSON from `file` or `data` (output as JSON, JSON5-style, or YAML via `format`).\n- `action: "query"`: JMESPath-like query (`a.b[0].c`, `items[*].name`, filters, functions).\n- `action: "validate"`: validate data against a JSON Schema (`schema` param).\n- `action: "transform"`: chain multiple JMESPath transforms (`transforms` param).\n- `action: "merge"`: deep merge `base` and `patch` objects (`conflictResolution` param).\nPrefer this over raw `read` + manual parsing when dealing with configuration or data files.',
|
|
44
45
|
permission: "auto",
|
|
45
46
|
mutating: false,
|
|
46
47
|
maxOutputBytes: 262144,
|
|
@@ -55,10 +56,10 @@ var jsonTool = {
|
|
|
55
56
|
enum: ["parse", "query", "validate", "transform", "merge"],
|
|
56
57
|
description: "Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge."
|
|
57
58
|
},
|
|
58
|
-
file: { type: "string", description: "Path to JSON
|
|
59
|
+
file: { type: "string", description: "Path to a JSON file (parse/query/validate/transform)" },
|
|
59
60
|
data: {
|
|
60
61
|
type: "string",
|
|
61
|
-
description: "JSON
|
|
62
|
+
description: "JSON string (parse/query/validate/transform, alternative to file)"
|
|
62
63
|
},
|
|
63
64
|
format: {
|
|
64
65
|
type: "string",
|
|
@@ -103,13 +104,10 @@ var jsonTool = {
|
|
|
103
104
|
"merge"
|
|
104
105
|
]);
|
|
105
106
|
if (input.action !== void 0 && !ALLOWED_ACTIONS.has(input.action)) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
action: String(input.action),
|
|
111
|
-
error: `Unknown action "${input.action}". Allowed actions: parse, query, validate, transform, merge`
|
|
112
|
-
};
|
|
107
|
+
throw new ToolValidationError({
|
|
108
|
+
message: `json: unknown action "${input.action}". Allowed actions: parse, query, validate, transform, merge`,
|
|
109
|
+
field: "action"
|
|
110
|
+
});
|
|
113
111
|
}
|
|
114
112
|
switch (action) {
|
|
115
113
|
case "query":
|
|
@@ -125,54 +123,61 @@ var jsonTool = {
|
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
};
|
|
126
|
+
async function readSource(input, ctx, action) {
|
|
127
|
+
if (input.file) {
|
|
128
|
+
try {
|
|
129
|
+
return await readJsonFileBounded(input.file, ctx);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
throw new Error(`json: could not read file "${input.file}": ${toErrorMessage(error)}`, {
|
|
135
|
+
cause: error
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (input.data) return input.data;
|
|
140
|
+
throw new ToolValidationError({
|
|
141
|
+
message: `json: provide \`file\` or \`data\` for action: ${action}`,
|
|
142
|
+
field: "file"
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function parseSource(raw, input) {
|
|
146
|
+
try {
|
|
147
|
+
return JSON.parse(raw);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const message = `json: parse failed${input.file ? ` for "${input.file}"` : ""}: ${toErrorMessage(error)}`;
|
|
150
|
+
if (input.file) throw new Error(message, { cause: error });
|
|
151
|
+
throw new ToolValidationError({ message, field: "data", cause: error });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
128
154
|
async function executeParse(input, ctx) {
|
|
129
155
|
const format = input.format ?? "json";
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
156
|
+
const raw = await readSource(input, ctx, "parse");
|
|
157
|
+
if (input.validate) {
|
|
158
|
+
let checked;
|
|
133
159
|
try {
|
|
134
|
-
|
|
160
|
+
checked = JSON.parse(raw);
|
|
135
161
|
} catch (error) {
|
|
136
162
|
return {
|
|
137
163
|
data: null,
|
|
138
|
-
formatted: "",
|
|
164
|
+
formatted: "invalid",
|
|
139
165
|
type: "unknown",
|
|
140
166
|
action: "parse",
|
|
141
|
-
|
|
167
|
+
valid: false,
|
|
168
|
+
errors: [`Parse failed: ${toErrorMessage(error)}`]
|
|
142
169
|
};
|
|
143
170
|
}
|
|
144
|
-
} else if (input.data) {
|
|
145
|
-
raw = input.data;
|
|
146
|
-
} else {
|
|
147
171
|
return {
|
|
148
|
-
data:
|
|
149
|
-
formatted: "",
|
|
150
|
-
type: "unknown",
|
|
151
|
-
action: "parse",
|
|
152
|
-
error: "Provide file or data"
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
parsed = JSON.parse(raw);
|
|
157
|
-
} catch (e) {
|
|
158
|
-
return {
|
|
159
|
-
data: null,
|
|
160
|
-
formatted: "",
|
|
161
|
-
type: "unknown",
|
|
162
|
-
action: "parse",
|
|
163
|
-
/* v8 ignore next -- JSON.parse only throws SyntaxError (an Error); the String(e) side is defensive. */
|
|
164
|
-
error: `Parse failed: ${e instanceof Error ? e.message : String(e)}`
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (input.validate) {
|
|
168
|
-
return {
|
|
169
|
-
data: parsed,
|
|
172
|
+
data: checked,
|
|
170
173
|
formatted: "valid",
|
|
171
|
-
type: Array.isArray(
|
|
174
|
+
type: Array.isArray(checked) ? "array" : typeof checked,
|
|
172
175
|
action: "parse",
|
|
173
|
-
|
|
176
|
+
valid: true,
|
|
177
|
+
keys: typeof checked === "object" && checked !== null ? Object.keys(checked) : void 0
|
|
174
178
|
};
|
|
175
179
|
}
|
|
180
|
+
const parsed = parseSource(raw, input);
|
|
176
181
|
if (input.query) {
|
|
177
182
|
const queryResult = simpleQuery(parsed, input.query);
|
|
178
183
|
const formatted2 = formatOutput(queryResult, format);
|
|
@@ -196,239 +201,102 @@ async function executeParse(input, ctx) {
|
|
|
196
201
|
}
|
|
197
202
|
async function executeQuery(input, ctx) {
|
|
198
203
|
if (!input.query) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
action: "query",
|
|
204
|
-
error: "query is required for action: query"
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
let parsed;
|
|
208
|
-
if (input.file) {
|
|
209
|
-
try {
|
|
210
|
-
const raw = await readJsonFileBounded(input.file, ctx);
|
|
211
|
-
parsed = JSON.parse(raw);
|
|
212
|
-
} catch (error) {
|
|
213
|
-
return {
|
|
214
|
-
data: null,
|
|
215
|
-
formatted: "",
|
|
216
|
-
type: "unknown",
|
|
217
|
-
action: "query",
|
|
218
|
-
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
} else if (input.data) {
|
|
222
|
-
try {
|
|
223
|
-
parsed = JSON.parse(input.data);
|
|
224
|
-
} catch {
|
|
225
|
-
return {
|
|
226
|
-
data: null,
|
|
227
|
-
formatted: "",
|
|
228
|
-
type: "unknown",
|
|
229
|
-
action: "query",
|
|
230
|
-
error: "Could not parse data string"
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
} else {
|
|
234
|
-
return {
|
|
235
|
-
data: null,
|
|
236
|
-
formatted: "",
|
|
237
|
-
type: "unknown",
|
|
238
|
-
action: "query",
|
|
239
|
-
error: "Provide file or data"
|
|
240
|
-
};
|
|
204
|
+
throw new ToolValidationError({
|
|
205
|
+
message: "json: query is required for action: query",
|
|
206
|
+
field: "query"
|
|
207
|
+
});
|
|
241
208
|
}
|
|
209
|
+
const parsed = parseSource(await readSource(input, ctx, "query"), input);
|
|
210
|
+
let result;
|
|
242
211
|
try {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
data: parsed,
|
|
247
|
-
formatted: formatOutput(result, format),
|
|
248
|
-
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
249
|
-
action: "query",
|
|
250
|
-
query_result: result
|
|
251
|
-
};
|
|
252
|
-
} catch (e) {
|
|
253
|
-
return {
|
|
254
|
-
data: null,
|
|
255
|
-
formatted: "",
|
|
256
|
-
type: "unknown",
|
|
257
|
-
action: "query",
|
|
258
|
-
/* v8 ignore next -- defensive String(e) */
|
|
259
|
-
error: `Query failed: ${e instanceof Error ? e.message : String(e)}`
|
|
260
|
-
};
|
|
212
|
+
result = jmespathSearch(parsed, input.query);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw new Error(`json: query failed: ${toErrorMessage(error)}`, { cause: error });
|
|
261
215
|
}
|
|
216
|
+
const format = input.format ?? "json";
|
|
217
|
+
return {
|
|
218
|
+
data: parsed,
|
|
219
|
+
formatted: formatOutput(result, format),
|
|
220
|
+
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
221
|
+
action: "query",
|
|
222
|
+
query_result: result
|
|
223
|
+
};
|
|
262
224
|
}
|
|
263
225
|
async function executeValidate(input, ctx) {
|
|
264
226
|
if (!input.schema) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
action: "validate",
|
|
270
|
-
error: "schema is required for action: validate"
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
let parsed;
|
|
274
|
-
if (input.file) {
|
|
275
|
-
try {
|
|
276
|
-
const raw = await readJsonFileBounded(input.file, ctx);
|
|
277
|
-
parsed = JSON.parse(raw);
|
|
278
|
-
} catch (error) {
|
|
279
|
-
return {
|
|
280
|
-
data: null,
|
|
281
|
-
formatted: "",
|
|
282
|
-
type: "unknown",
|
|
283
|
-
action: "validate",
|
|
284
|
-
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
} else if (input.data) {
|
|
288
|
-
try {
|
|
289
|
-
parsed = JSON.parse(input.data);
|
|
290
|
-
} catch {
|
|
291
|
-
return {
|
|
292
|
-
data: null,
|
|
293
|
-
formatted: "",
|
|
294
|
-
type: "unknown",
|
|
295
|
-
action: "validate",
|
|
296
|
-
error: "Could not parse data string"
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
return {
|
|
301
|
-
data: null,
|
|
302
|
-
formatted: "",
|
|
303
|
-
type: "unknown",
|
|
304
|
-
action: "validate",
|
|
305
|
-
error: "Provide file or data"
|
|
306
|
-
};
|
|
227
|
+
throw new ToolValidationError({
|
|
228
|
+
message: "json: schema is required for action: validate",
|
|
229
|
+
field: "schema"
|
|
230
|
+
});
|
|
307
231
|
}
|
|
232
|
+
const parsed = parseSource(await readSource(input, ctx, "validate"), input);
|
|
233
|
+
let outcome;
|
|
308
234
|
try {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
action: "validate",
|
|
315
|
-
valid,
|
|
316
|
-
errors
|
|
317
|
-
};
|
|
318
|
-
} catch (e) {
|
|
319
|
-
return {
|
|
320
|
-
data: null,
|
|
321
|
-
formatted: "",
|
|
322
|
-
type: "unknown",
|
|
323
|
-
action: "validate",
|
|
324
|
-
/* v8 ignore next -- defensive String(e) */
|
|
325
|
-
error: `Validation failed: ${e instanceof Error ? e.message : String(e)}`
|
|
326
|
-
};
|
|
235
|
+
outcome = validateJsonSchema(parsed, input.schema);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
throw new Error(`json: schema validation failed to run: ${toErrorMessage(error)}`, {
|
|
238
|
+
cause: error
|
|
239
|
+
});
|
|
327
240
|
}
|
|
241
|
+
return {
|
|
242
|
+
data: parsed,
|
|
243
|
+
formatted: outcome.valid ? "valid" : "invalid",
|
|
244
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed,
|
|
245
|
+
action: "validate",
|
|
246
|
+
valid: outcome.valid,
|
|
247
|
+
errors: outcome.errors
|
|
248
|
+
};
|
|
328
249
|
}
|
|
329
250
|
async function executeTransform(input, ctx) {
|
|
330
251
|
if (!input.transforms || input.transforms.length === 0) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
action: "transform",
|
|
336
|
-
error: "transforms array is required for action: transform"
|
|
337
|
-
};
|
|
252
|
+
throw new ToolValidationError({
|
|
253
|
+
message: "json: transforms array is required for action: transform",
|
|
254
|
+
field: "transforms"
|
|
255
|
+
});
|
|
338
256
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
parsed = JSON.parse(raw);
|
|
344
|
-
} catch (error) {
|
|
345
|
-
return {
|
|
346
|
-
data: null,
|
|
347
|
-
formatted: "",
|
|
348
|
-
type: "unknown",
|
|
349
|
-
action: "transform",
|
|
350
|
-
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
} else if (input.data) {
|
|
257
|
+
const parsed = parseSource(await readSource(input, ctx, "transform"), input);
|
|
258
|
+
let current = parsed;
|
|
259
|
+
const steps = [];
|
|
260
|
+
for (const t of input.transforms) {
|
|
354
261
|
try {
|
|
355
|
-
parsed = JSON.parse(input.data);
|
|
356
|
-
} catch {
|
|
357
|
-
return {
|
|
358
|
-
data: null,
|
|
359
|
-
formatted: "",
|
|
360
|
-
type: "unknown",
|
|
361
|
-
action: "transform",
|
|
362
|
-
error: "Could not parse data string"
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
} else {
|
|
366
|
-
return {
|
|
367
|
-
data: null,
|
|
368
|
-
formatted: "",
|
|
369
|
-
type: "unknown",
|
|
370
|
-
action: "transform",
|
|
371
|
-
error: "Provide file or data"
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
try {
|
|
375
|
-
let current = parsed;
|
|
376
|
-
const steps = [];
|
|
377
|
-
for (const t of input.transforms) {
|
|
378
262
|
current = jmespathSearch(current, t);
|
|
379
|
-
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw new Error(`json: transform "${t}" failed: ${toErrorMessage(error)}`, { cause: error });
|
|
380
265
|
}
|
|
381
|
-
|
|
382
|
-
return {
|
|
383
|
-
data: parsed,
|
|
384
|
-
formatted: formatOutput(current, format),
|
|
385
|
-
type: current === null ? "null" : Array.isArray(current) ? "array" : typeof current,
|
|
386
|
-
action: "transform",
|
|
387
|
-
result: current,
|
|
388
|
-
steps
|
|
389
|
-
};
|
|
390
|
-
} catch (e) {
|
|
391
|
-
return {
|
|
392
|
-
data: null,
|
|
393
|
-
formatted: "",
|
|
394
|
-
type: "unknown",
|
|
395
|
-
action: "transform",
|
|
396
|
-
/* v8 ignore next -- defensive String(e) */
|
|
397
|
-
error: `Transform failed: ${e instanceof Error ? e.message : String(e)}`
|
|
398
|
-
};
|
|
266
|
+
steps.push({ transform: t, result: current });
|
|
399
267
|
}
|
|
268
|
+
const format = input.format ?? "json";
|
|
269
|
+
return {
|
|
270
|
+
data: parsed,
|
|
271
|
+
formatted: formatOutput(current, format),
|
|
272
|
+
type: current === null ? "null" : Array.isArray(current) ? "array" : typeof current,
|
|
273
|
+
action: "transform",
|
|
274
|
+
result: current,
|
|
275
|
+
steps
|
|
276
|
+
};
|
|
400
277
|
}
|
|
401
278
|
async function executeMerge(input) {
|
|
402
279
|
if (input.base === void 0 || input.patch === void 0) {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
action: "merge",
|
|
408
|
-
error: "base and patch are required for action: merge"
|
|
409
|
-
};
|
|
280
|
+
throw new ToolValidationError({
|
|
281
|
+
message: "json: base and patch are required for action: merge",
|
|
282
|
+
field: input.base === void 0 ? "base" : "patch"
|
|
283
|
+
});
|
|
410
284
|
}
|
|
411
285
|
const conflictResolution = input.conflictResolution ?? "prefer-patch";
|
|
286
|
+
let result;
|
|
412
287
|
try {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
data: result,
|
|
417
|
-
formatted: formatOutput(result, format),
|
|
418
|
-
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
419
|
-
action: "merge",
|
|
420
|
-
result
|
|
421
|
-
};
|
|
422
|
-
} catch (e) {
|
|
423
|
-
return {
|
|
424
|
-
data: null,
|
|
425
|
-
formatted: "",
|
|
426
|
-
type: "unknown",
|
|
427
|
-
action: "merge",
|
|
428
|
-
/* v8 ignore next -- defensive String(e) */
|
|
429
|
-
error: `Merge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
430
|
-
};
|
|
288
|
+
result = deepMergeCore(input.base, input.patch, { conflictResolution });
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw new Error(`json: merge failed: ${toErrorMessage(error)}`, { cause: error });
|
|
431
291
|
}
|
|
292
|
+
const format = input.format ?? "json";
|
|
293
|
+
return {
|
|
294
|
+
data: result,
|
|
295
|
+
formatted: formatOutput(result, format),
|
|
296
|
+
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
297
|
+
action: "merge",
|
|
298
|
+
result
|
|
299
|
+
};
|
|
432
300
|
}
|
|
433
301
|
function jmespathSearch(data, query) {
|
|
434
302
|
if (!query || query === "@") return data;
|
|
@@ -704,4 +572,4 @@ ${toYaml(v, indent + 1)}`;
|
|
|
704
572
|
export {
|
|
705
573
|
jsonTool
|
|
706
574
|
};
|
|
707
|
-
//# sourceMappingURL=chunk-
|
|
575
|
+
//# sourceMappingURL=chunk-D6RQZMZS.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
kanbanTool
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VMJY6FYJ.js";
|
|
4
4
|
import {
|
|
5
5
|
applyManagedKanbanBoardToTodos,
|
|
6
6
|
blockingTitles,
|
|
@@ -118,7 +118,14 @@ async function synchronizeManagedKanban(items, board, ctx, signal) {
|
|
|
118
118
|
const warnings = [];
|
|
119
119
|
const actor = ctx.agentId?.trim() || ctx.agentName?.trim() || "kanban-agent";
|
|
120
120
|
const execute = async (input) => {
|
|
121
|
-
|
|
121
|
+
let result;
|
|
122
|
+
try {
|
|
123
|
+
result = await kanbanTool.execute(input, ctx, { signal });
|
|
124
|
+
} catch (err) {
|
|
125
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
126
|
+
warnings.push(message);
|
|
127
|
+
return { ok: false, message };
|
|
128
|
+
}
|
|
122
129
|
if (!result.ok) warnings.push(result.message);
|
|
123
130
|
else {
|
|
124
131
|
synced++;
|
|
@@ -487,4 +494,4 @@ var todoTool = {
|
|
|
487
494
|
export {
|
|
488
495
|
todoTool
|
|
489
496
|
};
|
|
490
|
-
//# sourceMappingURL=chunk-
|
|
497
|
+
//# sourceMappingURL=chunk-DBG7UQGK.js.map
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import { spawn } from "node:child_process";
|
|
19
19
|
import * as fs from "node:fs/promises";
|
|
20
20
|
import * as path from "node:path";
|
|
21
|
+
import { StringDecoder } from "node:string_decoder";
|
|
21
22
|
import { ToolValidationError } from "@wrongstack/core/types";
|
|
22
23
|
import {
|
|
23
24
|
buildChildEnv,
|
|
@@ -31,6 +32,13 @@ var NATIVE_READ_CHUNK_BYTES = 64 * 1024;
|
|
|
31
32
|
var NATIVE_MAX_FILE_BYTES = 1e6;
|
|
32
33
|
var RG_MAX_QUEUE_CHUNKS = 128;
|
|
33
34
|
var RG_MAX_QUEUE_CHARS = 8 * 1024 * 1024;
|
|
35
|
+
function isInsideDefaultIgnoredDirectory(target, root) {
|
|
36
|
+
const relative2 = path.relative(root, target);
|
|
37
|
+
if (!relative2 || relative2 === ".." || relative2.startsWith(`..${path.sep}`) || path.isAbsolute(relative2)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return relative2.split(path.sep).some((segment) => DEFAULT_IGNORE.has(segment));
|
|
41
|
+
}
|
|
34
42
|
var grepTool = {
|
|
35
43
|
name: "grep",
|
|
36
44
|
category: "Search",
|
|
@@ -99,6 +107,14 @@ var grepTool = {
|
|
|
99
107
|
});
|
|
100
108
|
}
|
|
101
109
|
const base = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
|
|
110
|
+
if (input.path && !await fs.stat(base).catch(() => null)) {
|
|
111
|
+
throw new ToolValidationError({
|
|
112
|
+
message: `grep: path "${input.path}" does not exist`,
|
|
113
|
+
field: "path"
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const ignoreRoot = await fs.realpath(ctx.projectRoot ?? ctx.cwd).catch(() => path.resolve(ctx.projectRoot ?? ctx.cwd));
|
|
117
|
+
const ignoreTarget = await fs.realpath(base).catch(() => path.resolve(base));
|
|
102
118
|
const mode = input.output_mode ?? "content";
|
|
103
119
|
const rawLimit = typeof input.limit === "number" && Number.isFinite(input.limit) ? input.limit : 200;
|
|
104
120
|
const limit = Math.max(1, Math.min(Math.floor(rawLimit), 2e3));
|
|
@@ -112,6 +128,18 @@ var grepTool = {
|
|
|
112
128
|
const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
|
|
113
129
|
const relativize = makeRootRelativizer(ctx.cwd);
|
|
114
130
|
const rgAvailable = await detectRg();
|
|
131
|
+
if (isInsideDefaultIgnoredDirectory(ignoreTarget, ignoreRoot)) {
|
|
132
|
+
yield {
|
|
133
|
+
type: "final",
|
|
134
|
+
output: {
|
|
135
|
+
matches: [],
|
|
136
|
+
count: 0,
|
|
137
|
+
truncated: false,
|
|
138
|
+
used: rgAvailable ? "rg" : "native"
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
115
143
|
if (rgAvailable) {
|
|
116
144
|
try {
|
|
117
145
|
yield* runRgStream(input, base, mode, limit, signal, relativize);
|
|
@@ -132,7 +160,7 @@ function __setRgAvailableForTests(available) {
|
|
|
132
160
|
rgAvailabilityCache = available !== void 0 ? Promise.resolve(available) : void 0;
|
|
133
161
|
}
|
|
134
162
|
function detectRg() {
|
|
135
|
-
rgAvailabilityCache ??= new Promise((
|
|
163
|
+
rgAvailabilityCache ??= new Promise((resolve2) => {
|
|
136
164
|
try {
|
|
137
165
|
const p = spawn("rg", ["--version"], {
|
|
138
166
|
env: buildChildEnv(),
|
|
@@ -140,10 +168,10 @@ function detectRg() {
|
|
|
140
168
|
signal: AbortSignal.timeout(1e4),
|
|
141
169
|
windowsHide: true
|
|
142
170
|
});
|
|
143
|
-
p.on("error", () =>
|
|
144
|
-
p.on("close", (code) =>
|
|
171
|
+
p.on("error", () => resolve2(false));
|
|
172
|
+
p.on("close", (code) => resolve2(code === 0));
|
|
145
173
|
} catch {
|
|
146
|
-
|
|
174
|
+
resolve2(false);
|
|
147
175
|
}
|
|
148
176
|
});
|
|
149
177
|
return rgAvailabilityCache;
|
|
@@ -206,6 +234,7 @@ async function* runRgStream(input, base, mode, limit, signal, relativize) {
|
|
|
206
234
|
windowsHide: true
|
|
207
235
|
});
|
|
208
236
|
const queue = [];
|
|
237
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
209
238
|
let queuedChars = 0;
|
|
210
239
|
let waiter;
|
|
211
240
|
let paused = false;
|
|
@@ -227,7 +256,8 @@ async function* runRgStream(input, base, mode, limit, signal, relativize) {
|
|
|
227
256
|
child.stdout?.resume();
|
|
228
257
|
};
|
|
229
258
|
const onStdoutData = (c) => {
|
|
230
|
-
const data =
|
|
259
|
+
const data = stdoutDecoder.write(c);
|
|
260
|
+
if (data.length === 0) return;
|
|
231
261
|
queue.push({ kind: "out", data });
|
|
232
262
|
queuedChars += data.length;
|
|
233
263
|
wake();
|
|
@@ -237,7 +267,14 @@ async function* runRgStream(input, base, mode, limit, signal, relativize) {
|
|
|
237
267
|
queue.push({ kind: "error", data: e.message });
|
|
238
268
|
wake();
|
|
239
269
|
};
|
|
240
|
-
|
|
270
|
+
let rgExitCode = null;
|
|
271
|
+
const onClose = (code) => {
|
|
272
|
+
rgExitCode = code;
|
|
273
|
+
const tail = stdoutDecoder.end();
|
|
274
|
+
if (tail.length > 0) {
|
|
275
|
+
queue.push({ kind: "out", data: tail });
|
|
276
|
+
queuedChars += tail.length;
|
|
277
|
+
}
|
|
241
278
|
queue.push({ kind: "close", data: "" });
|
|
242
279
|
wake();
|
|
243
280
|
};
|
|
@@ -319,6 +356,9 @@ async function* runRgStream(input, base, mode, limit, signal, relativize) {
|
|
|
319
356
|
};
|
|
320
357
|
}
|
|
321
358
|
if (errored) throw new Error("rg: spawn error");
|
|
359
|
+
if (rgExitCode === 2 && totalLines === 0 && !bufOverflow) {
|
|
360
|
+
throw new Error("rg: exited with an error and produced no matches");
|
|
361
|
+
}
|
|
322
362
|
yield {
|
|
323
363
|
type: "final",
|
|
324
364
|
output: {
|
|
@@ -398,6 +438,7 @@ async function runNative(input, base, mode, limit, signal, relativize) {
|
|
|
398
438
|
let lineNumber = 0;
|
|
399
439
|
let fileHits = 0;
|
|
400
440
|
let leftover = "";
|
|
441
|
+
const decoder = new StringDecoder("utf8");
|
|
401
442
|
let binaryChecked = false;
|
|
402
443
|
const buffer = Buffer.allocUnsafe(Math.min(NATIVE_READ_CHUNK_BYTES, maxBytes));
|
|
403
444
|
while (!stopped && !signal.aborted && bytesReadTotal < maxBytes) {
|
|
@@ -415,7 +456,7 @@ async function runNative(input, base, mode, limit, signal, relativize) {
|
|
|
415
456
|
if (isBinaryBuffer(chunk)) return;
|
|
416
457
|
}
|
|
417
458
|
bytesReadTotal += bytesRead;
|
|
418
|
-
const text = leftover +
|
|
459
|
+
const text = leftover + decoder.write(chunk);
|
|
419
460
|
const lines = text.split(/\r?\n/);
|
|
420
461
|
leftover = lines.pop() ?? "";
|
|
421
462
|
for (const rawLine of lines) {
|
|
@@ -439,6 +480,7 @@ async function runNative(input, base, mode, limit, signal, relativize) {
|
|
|
439
480
|
}
|
|
440
481
|
if (mode === "files_with_matches" && fileHits > 0) break;
|
|
441
482
|
}
|
|
483
|
+
leftover += decoder.end();
|
|
442
484
|
if (!stopped && !signal.aborted && leftover.length > 0) {
|
|
443
485
|
lineNumber++;
|
|
444
486
|
const ln = leftover.length > 4096 ? capSubject(leftover) : leftover;
|
|
@@ -526,4 +568,4 @@ export {
|
|
|
526
568
|
__resetRgDetectionForTests,
|
|
527
569
|
__setRgAvailableForTests
|
|
528
570
|
};
|
|
529
|
-
//# sourceMappingURL=chunk-
|
|
571
|
+
//# sourceMappingURL=chunk-DLZCOEVG.js.map
|