@wrongstack/plugins 0.275.1 → 0.276.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.
- package/dist/auto-doc.d.ts +3 -2
- package/dist/auto-doc.js +6 -44
- package/dist/cost-tracker.js +1 -0
- package/dist/cron.js +1 -0
- package/dist/file-watcher.js +15 -14
- package/dist/git-autocommit.d.ts +6 -3
- package/dist/git-autocommit.js +7 -137
- package/dist/index.js +111 -844
- package/dist/json-path.d.ts +9 -6
- package/dist/json-path.js +3 -280
- package/dist/semver-bump.js +3 -3
- package/dist/shell-check.d.ts +5 -2
- package/dist/shell-check.js +42 -72
- package/dist/template-engine.js +25 -24
- package/dist/web-search.d.ts +14 -0
- package/dist/web-search.js +4 -274
- package/package.json +2 -2
package/dist/json-path.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Plugin } from '@wrongstack/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* json-path plugin —
|
|
4
|
+
* json-path plugin — RETIRED.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* The four tools this plugin previously registered (`jmespath_query`,
|
|
7
|
+
* `json_validate`, `json_transform`, `json_merge`) have been consolidated
|
|
8
|
+
* into the built-in `json` tool (packages/tools/src/json.ts) via its
|
|
9
|
+
* `action` parameter.
|
|
10
|
+
*
|
|
11
|
+
* This file remains as a no-op stub so existing config references
|
|
12
|
+
* (`"json-path": { "enabled": true }`) do not break. It registers no
|
|
13
|
+
* tools and logs a deprecation notice on load.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
declare const plugin: Plugin;
|
package/dist/json-path.js
CHANGED
|
@@ -1,290 +1,13 @@
|
|
|
1
|
-
import { expectDefined, deepMerge as deepMerge$1 } from '@wrongstack/core';
|
|
2
|
-
|
|
3
1
|
// src/json-path/index.ts
|
|
4
2
|
var API_VERSION = "^0.1.10";
|
|
5
|
-
function jmespathSearch(data, query) {
|
|
6
|
-
if (!query || query === "@") return data;
|
|
7
|
-
if (query === "$") return data;
|
|
8
|
-
const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\.(.+))?$/);
|
|
9
|
-
if (dotMatch) {
|
|
10
|
-
const key = expectDefined(dotMatch[1]);
|
|
11
|
-
const rest = dotMatch[2];
|
|
12
|
-
const val = data?.[key];
|
|
13
|
-
if (rest === void 0) return val;
|
|
14
|
-
return jmespathSearch(val, rest);
|
|
15
|
-
}
|
|
16
|
-
const arrMatch = query.match(/^\[(\d+)\](?:\.(.+))?$/);
|
|
17
|
-
if (arrMatch) {
|
|
18
|
-
const idx = Number.parseInt(expectDefined(arrMatch[1]), 10);
|
|
19
|
-
const rest = arrMatch[2];
|
|
20
|
-
const arr = data;
|
|
21
|
-
const val = arr?.[idx];
|
|
22
|
-
if (rest === void 0) return val;
|
|
23
|
-
return jmespathSearch(val, rest);
|
|
24
|
-
}
|
|
25
|
-
if (query === "[*]") {
|
|
26
|
-
if (Array.isArray(data)) {
|
|
27
|
-
return data;
|
|
28
|
-
}
|
|
29
|
-
return data;
|
|
30
|
-
}
|
|
31
|
-
const multiMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\[\*\](?:\.(.+))?$/);
|
|
32
|
-
if (multiMatch) {
|
|
33
|
-
const key = expectDefined(multiMatch[1]);
|
|
34
|
-
const rest = multiMatch[2];
|
|
35
|
-
const arr = data?.[key];
|
|
36
|
-
if (!Array.isArray(arr)) return [];
|
|
37
|
-
if (rest === void 0) return arr;
|
|
38
|
-
return arr.map((item) => jmespathSearch(item, rest));
|
|
39
|
-
}
|
|
40
|
-
const filterMatch = query.match(/^\[\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\](?:\.(.+))?$/);
|
|
41
|
-
if (filterMatch) {
|
|
42
|
-
const field = expectDefined(filterMatch[1]);
|
|
43
|
-
const op = expectDefined(filterMatch[2]);
|
|
44
|
-
const rawVal = expectDefined(filterMatch[3]);
|
|
45
|
-
const rest = filterMatch[4];
|
|
46
|
-
const cmpVal = JSON.parse(rawVal.slice(1, -1));
|
|
47
|
-
const arr = data;
|
|
48
|
-
if (!Array.isArray(arr)) return [];
|
|
49
|
-
const filtered = arr.filter((item) => {
|
|
50
|
-
const itemVal = item[field];
|
|
51
|
-
switch (op) {
|
|
52
|
-
case "==":
|
|
53
|
-
return itemVal === cmpVal;
|
|
54
|
-
case "!=":
|
|
55
|
-
return itemVal !== cmpVal;
|
|
56
|
-
case ">":
|
|
57
|
-
return Number(itemVal) > Number(cmpVal);
|
|
58
|
-
case "<":
|
|
59
|
-
return Number(itemVal) < Number(cmpVal);
|
|
60
|
-
case ">=":
|
|
61
|
-
return Number(itemVal) >= Number(cmpVal);
|
|
62
|
-
case "<=":
|
|
63
|
-
return Number(itemVal) <= Number(cmpVal);
|
|
64
|
-
/* v8 ignore next -- op is constrained to the six operators by the filter regex; default is unreachable. */
|
|
65
|
-
default:
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
if (rest === void 0) return filtered;
|
|
70
|
-
return filtered.map((item) => jmespathSearch(item, rest));
|
|
71
|
-
}
|
|
72
|
-
const fnMatch = query.match(/^(length|keys|values|type)\(@\)$/);
|
|
73
|
-
if (fnMatch) {
|
|
74
|
-
const fn = expectDefined(fnMatch[1]);
|
|
75
|
-
switch (fn) {
|
|
76
|
-
case "length":
|
|
77
|
-
if (Array.isArray(data)) return data.length;
|
|
78
|
-
if (typeof data === "string") return data.length;
|
|
79
|
-
if (typeof data === "object" && data !== null) return Object.keys(data).length;
|
|
80
|
-
return 0;
|
|
81
|
-
case "keys":
|
|
82
|
-
if (typeof data === "object" && data !== null && !Array.isArray(data)) return Object.keys(data);
|
|
83
|
-
return [];
|
|
84
|
-
case "values":
|
|
85
|
-
if (typeof data === "object" && data !== null && !Array.isArray(data)) return Object.values(data);
|
|
86
|
-
return [];
|
|
87
|
-
case "type":
|
|
88
|
-
if (data === null) return "null";
|
|
89
|
-
if (Array.isArray(data)) return "array";
|
|
90
|
-
return typeof data;
|
|
91
|
-
/* v8 ignore next 2 -- fn is constrained to the four names by the function regex; default is unreachable. */
|
|
92
|
-
default:
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
function validateJsonSchema(data, schema) {
|
|
99
|
-
const errors = [];
|
|
100
|
-
function check(value, s, path) {
|
|
101
|
-
if (s["type"]) {
|
|
102
|
-
const expectedType = s["type"];
|
|
103
|
-
const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
104
|
-
if (expectedType === "integer") {
|
|
105
|
-
if (!Number.isInteger(value)) errors.push(`${path}: expected integer, got ${actualType}`);
|
|
106
|
-
} else if (expectedType !== actualType) {
|
|
107
|
-
errors.push(`${path}: expected ${expectedType}, got ${actualType}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (typeof value === "string" && s["format"] === "uri" && value) {
|
|
111
|
-
try {
|
|
112
|
-
new URL(value);
|
|
113
|
-
} catch {
|
|
114
|
-
errors.push(`${path}: not a valid URI`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (typeof value === "string" && s["pattern"]) {
|
|
118
|
-
const re = new RegExp(s["pattern"]);
|
|
119
|
-
if (!re.test(value)) errors.push(`${path}: does not match pattern ${s["pattern"]}`);
|
|
120
|
-
}
|
|
121
|
-
if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
|
|
122
|
-
errors.push(`${path}: string too short (min ${s["minLength"]})`);
|
|
123
|
-
}
|
|
124
|
-
if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
|
|
125
|
-
errors.push(`${path}: string too long (max ${s["maxLength"]})`);
|
|
126
|
-
}
|
|
127
|
-
if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
|
|
128
|
-
errors.push(`${path}: below minimum ${s["minimum"]}`);
|
|
129
|
-
}
|
|
130
|
-
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
131
|
-
errors.push(`${path}: above maximum ${s["maximum"]}`);
|
|
132
|
-
}
|
|
133
|
-
if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
|
|
134
|
-
for (let i = 0; i < value.length; i++) {
|
|
135
|
-
check(value[i], s["items"], `${path}[${i}]`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
139
|
-
const props = s["properties"];
|
|
140
|
-
for (const [k, propSchema] of Object.entries(props)) {
|
|
141
|
-
check(value[k], propSchema, `${path}.${k}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
check(data, schema, "$");
|
|
146
|
-
return { valid: errors.length === 0, errors };
|
|
147
|
-
}
|
|
148
|
-
function deepMerge(base, patch, conflictResolution = "prefer-patch") {
|
|
149
|
-
return deepMerge$1(base, patch, { conflictResolution });
|
|
150
|
-
}
|
|
151
3
|
var plugin = {
|
|
152
4
|
name: "json-path",
|
|
153
|
-
version: "0.
|
|
154
|
-
description: "
|
|
5
|
+
version: "0.2.0",
|
|
6
|
+
description: "Retired \u2014 capabilities merged into the built-in json tool",
|
|
155
7
|
apiVersion: API_VERSION,
|
|
156
8
|
capabilities: { tools: true },
|
|
157
|
-
defaultConfig: {
|
|
158
|
-
strictValidation: false,
|
|
159
|
-
maxDepth: 50,
|
|
160
|
-
allowLargeFiles: false
|
|
161
|
-
},
|
|
162
|
-
configSchema: {
|
|
163
|
-
type: "object",
|
|
164
|
-
properties: {
|
|
165
|
-
strictValidation: { type: "boolean", default: false },
|
|
166
|
-
maxDepth: { type: "number", default: 50 },
|
|
167
|
-
allowLargeFiles: { type: "boolean", default: false }
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
9
|
setup(api) {
|
|
171
|
-
api.
|
|
172
|
-
name: "jmespath_query",
|
|
173
|
-
description: "Execute a JMESPath query on JSON or YAML data. Supports dot notation, array indexing, wildcards, filters, and functions.",
|
|
174
|
-
inputSchema: {
|
|
175
|
-
type: "object",
|
|
176
|
-
properties: {
|
|
177
|
-
data: { description: "JSON/YAML data to query (object or array)" },
|
|
178
|
-
query: { type: "string", description: "JMESPath query expression" }
|
|
179
|
-
},
|
|
180
|
-
required: ["data", "query"]
|
|
181
|
-
},
|
|
182
|
-
permission: "auto",
|
|
183
|
-
mutating: false,
|
|
184
|
-
async execute(input) {
|
|
185
|
-
const data = input["data"];
|
|
186
|
-
const query = input["query"];
|
|
187
|
-
try {
|
|
188
|
-
const result = jmespathSearch(data, query);
|
|
189
|
-
return {
|
|
190
|
-
ok: true,
|
|
191
|
-
query,
|
|
192
|
-
result,
|
|
193
|
-
resultType: result === null ? "null" : Array.isArray(result) ? "array" : typeof result
|
|
194
|
-
};
|
|
195
|
-
} catch (err) {
|
|
196
|
-
return { ok: false, error: String(err), query };
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
api.tools.register({
|
|
201
|
-
name: "json_validate",
|
|
202
|
-
description: "Validate JSON/YAML data against a JSON Schema. Reports all validation errors found.",
|
|
203
|
-
inputSchema: {
|
|
204
|
-
type: "object",
|
|
205
|
-
properties: {
|
|
206
|
-
data: { description: "JSON data to validate" },
|
|
207
|
-
schema: { description: "JSON Schema to validate against" }
|
|
208
|
-
},
|
|
209
|
-
required: ["data", "schema"]
|
|
210
|
-
},
|
|
211
|
-
permission: "auto",
|
|
212
|
-
mutating: false,
|
|
213
|
-
async execute(input) {
|
|
214
|
-
const data = input["data"];
|
|
215
|
-
const schema = input["schema"];
|
|
216
|
-
try {
|
|
217
|
-
const { valid, errors } = validateJsonSchema(data, schema);
|
|
218
|
-
return { ok: true, valid, errors, errorCount: errors.length };
|
|
219
|
-
} catch (err) {
|
|
220
|
-
return { ok: false, error: String(err) };
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
api.tools.register({
|
|
225
|
-
name: "json_transform",
|
|
226
|
-
description: "Apply a series of JMESPath transforms to data, passing the output of each as input to the next.",
|
|
227
|
-
inputSchema: {
|
|
228
|
-
type: "object",
|
|
229
|
-
properties: {
|
|
230
|
-
data: { description: "Initial JSON data" },
|
|
231
|
-
transforms: {
|
|
232
|
-
type: "array",
|
|
233
|
-
items: { type: "string" },
|
|
234
|
-
description: "Array of JMESPath query strings to apply in sequence"
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
required: ["data", "transforms"]
|
|
238
|
-
},
|
|
239
|
-
permission: "auto",
|
|
240
|
-
mutating: false,
|
|
241
|
-
async execute(input) {
|
|
242
|
-
const data = input["data"];
|
|
243
|
-
const transforms = input["transforms"];
|
|
244
|
-
try {
|
|
245
|
-
let current = data;
|
|
246
|
-
const steps = [];
|
|
247
|
-
for (const t of transforms) {
|
|
248
|
-
current = jmespathSearch(current, t);
|
|
249
|
-
steps.push({ transform: t, result: current });
|
|
250
|
-
}
|
|
251
|
-
return { ok: true, finalResult: current, steps };
|
|
252
|
-
} catch (err) {
|
|
253
|
-
return { ok: false, error: String(err) };
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
api.tools.register({
|
|
258
|
-
name: "json_merge",
|
|
259
|
-
description: "Deep merge two JSON objects. Use conflictResolution to decide which value wins on collision.",
|
|
260
|
-
inputSchema: {
|
|
261
|
-
type: "object",
|
|
262
|
-
properties: {
|
|
263
|
-
base: { description: "Base JSON object" },
|
|
264
|
-
patch: { description: "Patch JSON object to merge in" },
|
|
265
|
-
conflictResolution: {
|
|
266
|
-
type: "string",
|
|
267
|
-
enum: ["prefer-base", "prefer-patch"],
|
|
268
|
-
default: "prefer-patch"
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
required: ["base", "patch"]
|
|
272
|
-
},
|
|
273
|
-
permission: "auto",
|
|
274
|
-
mutating: false,
|
|
275
|
-
async execute(input) {
|
|
276
|
-
const base = input["base"];
|
|
277
|
-
const patch = input["patch"];
|
|
278
|
-
const conflictResolution = input["conflictResolution"] ?? "prefer-patch";
|
|
279
|
-
try {
|
|
280
|
-
const result = deepMerge(base, patch, conflictResolution);
|
|
281
|
-
return { ok: true, result };
|
|
282
|
-
} catch (err) {
|
|
283
|
-
return { ok: false, error: String(err) };
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
api.log.info("json-path plugin loaded", { version: "0.1.0" });
|
|
10
|
+
api.log.info("json-path plugin retired \u2014 use the built-in json tool with action: query|validate|transform|merge");
|
|
288
11
|
}
|
|
289
12
|
};
|
|
290
13
|
var json_path_default = plugin;
|
package/dist/semver-bump.js
CHANGED
|
@@ -209,7 +209,7 @@ var plugin = {
|
|
|
209
209
|
if (dryRun) {
|
|
210
210
|
return {
|
|
211
211
|
ok: true,
|
|
212
|
-
|
|
212
|
+
dry_run: true,
|
|
213
213
|
currentVersion,
|
|
214
214
|
suggestedBump: bumpPart,
|
|
215
215
|
newVersion,
|
|
@@ -279,7 +279,7 @@ var plugin = {
|
|
|
279
279
|
type: "object",
|
|
280
280
|
properties: {
|
|
281
281
|
cwd: { type: "string", description: "Working directory (defaults to project root)" },
|
|
282
|
-
|
|
282
|
+
dry_run: { type: "boolean", default: false },
|
|
283
283
|
part: { type: "string", enum: ["major", "minor", "patch", "auto"], default: defaultPart, description: "Version part to bump. Omitted \u2192 the configured default (/settings semver-part, factory default: patch). Use auto to infer from commits." }
|
|
284
284
|
}
|
|
285
285
|
},
|
|
@@ -287,7 +287,7 @@ var plugin = {
|
|
|
287
287
|
mutating: true,
|
|
288
288
|
async execute(input) {
|
|
289
289
|
const cwd = input["cwd"];
|
|
290
|
-
const dryRun = input["
|
|
290
|
+
const dryRun = input["dry_run"] ?? false;
|
|
291
291
|
const part = input["part"] ?? defaultPart;
|
|
292
292
|
return performBump(part, dryRun, cwd);
|
|
293
293
|
}
|
package/dist/shell-check.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ import { Plugin } from '@wrongstack/core';
|
|
|
4
4
|
* shell-check plugin — Runs shellcheck analysis on bash/shell scripts.
|
|
5
5
|
*
|
|
6
6
|
* Tools registered:
|
|
7
|
-
* - shellcheck: Run shellcheck on specific files
|
|
8
|
-
*
|
|
7
|
+
* - shellcheck: Run shellcheck on specific files OR recursively scan a directory.
|
|
8
|
+
*
|
|
9
|
+
* Note: The former `shellcheck (scan mode)` tool has been merged into `shellcheck`
|
|
10
|
+
* via the `directory` + `pattern` parameters. Pass `files` for specific
|
|
11
|
+
* files, or `directory` (optionally with `pattern`) for recursive scanning.
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
declare const plugin: Plugin;
|
package/dist/shell-check.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync, execFileSync } from 'child_process';
|
|
2
|
-
import {
|
|
2
|
+
import { readdirSync, existsSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
|
|
5
5
|
// src/shell-check/index.ts
|
|
@@ -72,7 +72,7 @@ function findShellFiles(dir, pattern) {
|
|
|
72
72
|
}
|
|
73
73
|
var plugin = {
|
|
74
74
|
name: "shell-check",
|
|
75
|
-
version: "0.
|
|
75
|
+
version: "0.2.0",
|
|
76
76
|
description: "Runs shellcheck analysis on bash/shell scripts and surfaces issues with severity levels",
|
|
77
77
|
apiVersion: API_VERSION,
|
|
78
78
|
capabilities: { tools: true, pipelines: ["toolCall"] },
|
|
@@ -94,14 +94,24 @@ var plugin = {
|
|
|
94
94
|
setup(api) {
|
|
95
95
|
api.tools.register({
|
|
96
96
|
name: "shellcheck",
|
|
97
|
-
description: "Run shellcheck analysis on shell script files. Returns issues with file, line, column, severity, code, and message.",
|
|
97
|
+
description: "Run shellcheck analysis on shell script files. Pass `files` for specific files, or `directory` (optionally with `pattern`) to recursively scan for .sh files. Returns issues with file, line, column, severity, code, and message.",
|
|
98
98
|
inputSchema: {
|
|
99
99
|
type: "object",
|
|
100
100
|
properties: {
|
|
101
101
|
files: {
|
|
102
102
|
type: "array",
|
|
103
103
|
items: { type: "string" },
|
|
104
|
-
description: "Shell script files to check"
|
|
104
|
+
description: "Shell script files to check. Mutually exclusive with `directory`."
|
|
105
|
+
},
|
|
106
|
+
directory: {
|
|
107
|
+
type: "string",
|
|
108
|
+
default: ".",
|
|
109
|
+
description: "Directory to recursively scan for .sh files. Used when `files` is omitted."
|
|
110
|
+
},
|
|
111
|
+
pattern: {
|
|
112
|
+
type: "string",
|
|
113
|
+
default: "",
|
|
114
|
+
description: "Filename pattern to match when scanning a directory (default: all .sh files)."
|
|
105
115
|
},
|
|
106
116
|
severity: {
|
|
107
117
|
type: "string",
|
|
@@ -114,20 +124,39 @@ var plugin = {
|
|
|
114
124
|
default: false,
|
|
115
125
|
description: "Apply safe automatic fixes where possible"
|
|
116
126
|
}
|
|
117
|
-
}
|
|
118
|
-
required: ["files"]
|
|
127
|
+
}
|
|
119
128
|
},
|
|
120
129
|
permission: "auto",
|
|
130
|
+
category: "Code Quality",
|
|
121
131
|
mutating: true,
|
|
122
132
|
async execute(input) {
|
|
123
133
|
const files = input["files"];
|
|
134
|
+
const directory = input["directory"] ?? ".";
|
|
135
|
+
const pattern = input["pattern"] ?? "";
|
|
124
136
|
const severity = input["severity"] ?? "warning";
|
|
137
|
+
let checkFiles;
|
|
138
|
+
let scannedDirectories = false;
|
|
139
|
+
if (files && files.length > 0) {
|
|
140
|
+
checkFiles = files;
|
|
141
|
+
} else {
|
|
142
|
+
checkFiles = findShellFiles(directory, pattern);
|
|
143
|
+
scannedDirectories = true;
|
|
144
|
+
}
|
|
145
|
+
if (checkFiles.length === 0) {
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
filesScanned: 0,
|
|
149
|
+
issues: [],
|
|
150
|
+
summary: { total: 0 },
|
|
151
|
+
mode: scannedDirectories ? "directory" : "files"
|
|
152
|
+
};
|
|
153
|
+
}
|
|
125
154
|
let issues;
|
|
126
155
|
try {
|
|
127
|
-
issues = runShellCheck(
|
|
156
|
+
issues = runShellCheck(checkFiles, severity);
|
|
128
157
|
} catch (err) {
|
|
129
158
|
const msg = err instanceof Error ? err.message : String(err);
|
|
130
|
-
return { ok: false, error: msg, issues: [] };
|
|
159
|
+
return { ok: false, error: msg, issues: [], filesScanned: 0 };
|
|
131
160
|
}
|
|
132
161
|
const byFile = {};
|
|
133
162
|
for (const issue of issues) {
|
|
@@ -141,10 +170,12 @@ var plugin = {
|
|
|
141
170
|
const infoCount = issues.filter((i) => i.level === "info").length;
|
|
142
171
|
const styleCount = issues.filter((i) => i.level === "style").length;
|
|
143
172
|
api.metrics.counter("issues_found", issues.length, { severity });
|
|
144
|
-
api.metrics.histogram("issues_per_file", issues.length / Math.max(
|
|
173
|
+
api.metrics.histogram("issues_per_file", issues.length / Math.max(checkFiles.length, 1));
|
|
145
174
|
return {
|
|
146
175
|
ok: true,
|
|
147
|
-
|
|
176
|
+
mode: scannedDirectories ? "directory" : "files",
|
|
177
|
+
filesScanned: checkFiles.length,
|
|
178
|
+
filesWithIssues: Object.keys(byFile).length,
|
|
148
179
|
issues,
|
|
149
180
|
summary: {
|
|
150
181
|
total: issues.length,
|
|
@@ -158,68 +189,7 @@ var plugin = {
|
|
|
158
189
|
};
|
|
159
190
|
}
|
|
160
191
|
});
|
|
161
|
-
api.
|
|
162
|
-
name: "shellcheck_scan",
|
|
163
|
-
description: "Recursively scan a directory for shell scripts and run shellcheck on all found files.",
|
|
164
|
-
inputSchema: {
|
|
165
|
-
type: "object",
|
|
166
|
-
properties: {
|
|
167
|
-
directory: {
|
|
168
|
-
type: "string",
|
|
169
|
-
default: ".",
|
|
170
|
-
description: "Directory to scan"
|
|
171
|
-
},
|
|
172
|
-
pattern: {
|
|
173
|
-
type: "string",
|
|
174
|
-
default: "",
|
|
175
|
-
description: "Filename pattern to match (default: all .sh files)"
|
|
176
|
-
},
|
|
177
|
-
severity: {
|
|
178
|
-
type: "string",
|
|
179
|
-
enum: ["error", "warning", "info", "style"],
|
|
180
|
-
default: "warning"
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
permission: "auto",
|
|
185
|
-
mutating: true,
|
|
186
|
-
async execute(input) {
|
|
187
|
-
const dir = input["directory"] ?? ".";
|
|
188
|
-
const pattern = input["pattern"] ?? "";
|
|
189
|
-
const severity = input["severity"] ?? "warning";
|
|
190
|
-
const files = findShellFiles(dir, pattern);
|
|
191
|
-
if (files.length === 0) {
|
|
192
|
-
return { ok: true, filesScanned: 0, issues: [], summary: { total: 0 } };
|
|
193
|
-
}
|
|
194
|
-
let issues;
|
|
195
|
-
try {
|
|
196
|
-
issues = runShellCheck(files, severity);
|
|
197
|
-
} catch (err) {
|
|
198
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
199
|
-
return { ok: false, error: msg, issues: [], filesScanned: 0 };
|
|
200
|
-
}
|
|
201
|
-
const byFile = {};
|
|
202
|
-
for (const issue of issues) {
|
|
203
|
-
if (byFile[issue.file] === void 0) {
|
|
204
|
-
byFile[issue.file] = [];
|
|
205
|
-
}
|
|
206
|
-
byFile[issue.file]?.push(issue);
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
ok: true,
|
|
210
|
-
filesScanned: files.length,
|
|
211
|
-
filesWithIssues: Object.keys(byFile).length,
|
|
212
|
-
issues,
|
|
213
|
-
summary: {
|
|
214
|
-
total: issues.length,
|
|
215
|
-
errors: issues.filter((i) => i.level === "error").length,
|
|
216
|
-
warnings: issues.filter((i) => i.level === "warning").length
|
|
217
|
-
},
|
|
218
|
-
byFile
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
api.log.info("shell-check plugin loaded", { version: "0.1.0" });
|
|
192
|
+
api.log.info("shell-check plugin loaded", { version: "0.2.0" });
|
|
223
193
|
}
|
|
224
194
|
};
|
|
225
195
|
var shell_check_default = plugin;
|
package/dist/template-engine.js
CHANGED
|
@@ -85,17 +85,18 @@ var plugin = {
|
|
|
85
85
|
description: "Variables to substitute into the template",
|
|
86
86
|
additionalProperties: { type: "string" }
|
|
87
87
|
},
|
|
88
|
-
|
|
88
|
+
output_path: { type: "string", description: "Optional path to write the expanded result" },
|
|
89
89
|
raw: { type: "boolean", default: false, description: "Disable HTML auto-escaping" }
|
|
90
90
|
},
|
|
91
91
|
required: ["template", "variables"]
|
|
92
92
|
},
|
|
93
93
|
permission: "auto",
|
|
94
|
+
category: "Project",
|
|
94
95
|
mutating: true,
|
|
95
96
|
async execute(input) {
|
|
96
97
|
const template = input["template"];
|
|
97
98
|
const variables = input["variables"];
|
|
98
|
-
const
|
|
99
|
+
const output_path = input["output_path"];
|
|
99
100
|
const raw = input["raw"] ?? false;
|
|
100
101
|
if (!template || typeof template !== "string") {
|
|
101
102
|
return { ok: false, error: "template is required and must be a string" };
|
|
@@ -109,17 +110,17 @@ var plugin = {
|
|
|
109
110
|
} catch (err) {
|
|
110
111
|
return { ok: false, error: String(err) };
|
|
111
112
|
}
|
|
112
|
-
if (
|
|
113
|
-
if (isAbsolute(
|
|
114
|
-
return { ok: false, error: '
|
|
113
|
+
if (output_path) {
|
|
114
|
+
if (isAbsolute(output_path) || output_path.includes("..")) {
|
|
115
|
+
return { ok: false, error: 'output_path must be a relative path without ".." components' };
|
|
115
116
|
}
|
|
116
117
|
const { writeFileSync } = await import('fs');
|
|
117
|
-
writeFileSync(
|
|
118
|
+
writeFileSync(output_path, result, "utf-8");
|
|
118
119
|
return {
|
|
119
120
|
ok: true,
|
|
120
|
-
|
|
121
|
+
output_path,
|
|
121
122
|
contentLength: result.length,
|
|
122
|
-
message: `Wrote ${result.length} characters to ${
|
|
123
|
+
message: `Wrote ${result.length} characters to ${output_path}`
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
126
|
return {
|
|
@@ -136,26 +137,26 @@ var plugin = {
|
|
|
136
137
|
inputSchema: {
|
|
137
138
|
type: "object",
|
|
138
139
|
properties: {
|
|
139
|
-
|
|
140
|
+
template_path: { type: "string", description: "Path to the template file" },
|
|
140
141
|
variables: {
|
|
141
142
|
type: "object",
|
|
142
143
|
description: "Variables to substitute",
|
|
143
144
|
additionalProperties: { type: "string" }
|
|
144
145
|
},
|
|
145
|
-
|
|
146
|
+
output_path: { type: "string", description: "Optional path to write the rendered result" },
|
|
146
147
|
raw: { type: "boolean", default: false }
|
|
147
148
|
},
|
|
148
|
-
required: ["
|
|
149
|
+
required: ["template_path", "variables"]
|
|
149
150
|
},
|
|
150
151
|
permission: "auto",
|
|
151
152
|
mutating: true,
|
|
152
153
|
async execute(input) {
|
|
153
|
-
const
|
|
154
|
+
const template_path = input["template_path"];
|
|
154
155
|
const variables = input["variables"];
|
|
155
|
-
const
|
|
156
|
+
const output_path = input["output_path"];
|
|
156
157
|
const raw = input["raw"] ?? false;
|
|
157
|
-
if (!
|
|
158
|
-
return { ok: false, error: "
|
|
158
|
+
if (!template_path || typeof template_path !== "string") {
|
|
159
|
+
return { ok: false, error: "template_path is required and must be a string" };
|
|
159
160
|
}
|
|
160
161
|
if (!variables || typeof variables !== "object") {
|
|
161
162
|
return { ok: false, error: "variables is required and must be an object" };
|
|
@@ -163,7 +164,7 @@ var plugin = {
|
|
|
163
164
|
let content;
|
|
164
165
|
try {
|
|
165
166
|
const { readFileSync } = await import('fs');
|
|
166
|
-
content = readFileSync(
|
|
167
|
+
content = readFileSync(template_path, "utf-8");
|
|
167
168
|
} catch (err) {
|
|
168
169
|
return { ok: false, error: `Could not read template file: ${err}` };
|
|
169
170
|
}
|
|
@@ -173,22 +174,22 @@ var plugin = {
|
|
|
173
174
|
} catch (err) {
|
|
174
175
|
return { ok: false, error: `Template rendering failed: ${err}` };
|
|
175
176
|
}
|
|
176
|
-
if (
|
|
177
|
-
if (isAbsolute(
|
|
178
|
-
return { ok: false, error: '
|
|
177
|
+
if (output_path) {
|
|
178
|
+
if (isAbsolute(output_path) || output_path.includes("..")) {
|
|
179
|
+
return { ok: false, error: 'output_path must be a relative path without ".." components' };
|
|
179
180
|
}
|
|
180
181
|
const { writeFileSync } = await import('fs');
|
|
181
|
-
writeFileSync(
|
|
182
|
+
writeFileSync(output_path, result, "utf-8");
|
|
182
183
|
return {
|
|
183
184
|
ok: true,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
message: `Rendered and wrote ${result.length} chars to ${
|
|
185
|
+
template_path,
|
|
186
|
+
output_path,
|
|
187
|
+
message: `Rendered and wrote ${result.length} chars to ${output_path}`
|
|
187
188
|
};
|
|
188
189
|
}
|
|
189
190
|
return {
|
|
190
191
|
ok: true,
|
|
191
|
-
|
|
192
|
+
template_path,
|
|
192
193
|
result,
|
|
193
194
|
contentLength: result.length
|
|
194
195
|
};
|
package/dist/web-search.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { Plugin } from '@wrongstack/core';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* web-search plugin — RETIRED.
|
|
5
|
+
*
|
|
6
|
+
* Both tools this plugin previously registered have been consolidated:
|
|
7
|
+
* - `web_search` → built-in `search` tool (packages/tools/src/search.ts)
|
|
8
|
+
* with native caching, dedup, ranking, and multiple search engines.
|
|
9
|
+
* - `web_fetch` → built-in `fetch` tool (packages/tools/src/fetch.ts)
|
|
10
|
+
* which is strictly superior (DNS-pinned SSRF, TurndownService markdown,
|
|
11
|
+
* streaming, binary-content rejection, structured errors).
|
|
12
|
+
*
|
|
13
|
+
* This file remains as a no-op stub so existing config references
|
|
14
|
+
* (`"web-search": { "enabled": true }`) do not break.
|
|
15
|
+
*/
|
|
16
|
+
|
|
3
17
|
declare const plugin: Plugin;
|
|
4
18
|
|
|
5
19
|
export { plugin as default };
|