@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.
@@ -1,13 +1,16 @@
1
1
  import { Plugin } from '@wrongstack/core';
2
2
 
3
3
  /**
4
- * json-path plugin — JMESPath query, validate, and transform JSON/YAML.
4
+ * json-path plugin — RETIRED.
5
5
  *
6
- * Tools registered:
7
- * - jmespath_query: Execute JMESPath query on JSON/YAML data
8
- * - json_validate: Validate data against a JSON Schema
9
- * - json_transform: Apply JMESPath transforms to data
10
- * - json_merge: Deep merge two JSON objects
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.1.0",
154
- description: "JMESPath query, JSON Schema validation, transformation, and deep merge for JSON/YAML",
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.tools.register({
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;
@@ -209,7 +209,7 @@ var plugin = {
209
209
  if (dryRun) {
210
210
  return {
211
211
  ok: true,
212
- dryRun: true,
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
- dryRun: { type: "boolean", default: false },
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["dryRun"] ?? false;
290
+ const dryRun = input["dry_run"] ?? false;
291
291
  const part = input["part"] ?? defaultPart;
292
292
  return performBump(part, dryRun, cwd);
293
293
  }
@@ -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
- * - shellcheck_scan: Scan directory for shell script issues
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;
@@ -1,5 +1,5 @@
1
1
  import { execSync, execFileSync } from 'child_process';
2
- import { existsSync, readdirSync } from 'fs';
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.1.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(files, severity);
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(files.length, 1));
173
+ api.metrics.histogram("issues_per_file", issues.length / Math.max(checkFiles.length, 1));
145
174
  return {
146
175
  ok: true,
147
- filesScanned: files.length,
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.tools.register({
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;
@@ -85,17 +85,18 @@ var plugin = {
85
85
  description: "Variables to substitute into the template",
86
86
  additionalProperties: { type: "string" }
87
87
  },
88
- outputPath: { type: "string", description: "Optional path to write the expanded result" },
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 outputPath = input["outputPath"];
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 (outputPath) {
113
- if (isAbsolute(outputPath) || outputPath.includes("..")) {
114
- return { ok: false, error: 'outputPath must be a relative path without ".." components' };
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(outputPath, result, "utf-8");
118
+ writeFileSync(output_path, result, "utf-8");
118
119
  return {
119
120
  ok: true,
120
- outputPath,
121
+ output_path,
121
122
  contentLength: result.length,
122
- message: `Wrote ${result.length} characters to ${outputPath}`
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
- templatePath: { type: "string", description: "Path to the template file" },
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
- outputPath: { type: "string", description: "Optional path to write the rendered result" },
146
+ output_path: { type: "string", description: "Optional path to write the rendered result" },
146
147
  raw: { type: "boolean", default: false }
147
148
  },
148
- required: ["templatePath", "variables"]
149
+ required: ["template_path", "variables"]
149
150
  },
150
151
  permission: "auto",
151
152
  mutating: true,
152
153
  async execute(input) {
153
- const templatePath = input["templatePath"];
154
+ const template_path = input["template_path"];
154
155
  const variables = input["variables"];
155
- const outputPath = input["outputPath"];
156
+ const output_path = input["output_path"];
156
157
  const raw = input["raw"] ?? false;
157
- if (!templatePath || typeof templatePath !== "string") {
158
- return { ok: false, error: "templatePath is required and must be a string" };
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(templatePath, "utf-8");
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 (outputPath) {
177
- if (isAbsolute(outputPath) || outputPath.includes("..")) {
178
- return { ok: false, error: 'outputPath must be a relative path without ".." components' };
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(outputPath, result, "utf-8");
182
+ writeFileSync(output_path, result, "utf-8");
182
183
  return {
183
184
  ok: true,
184
- templatePath,
185
- outputPath,
186
- message: `Rendered and wrote ${result.length} chars to ${outputPath}`
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
- templatePath,
192
+ template_path,
192
193
  result,
193
194
  contentLength: result.length
194
195
  };
@@ -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 };