@wrongstack/plugins 1.0.8 → 1.0.11
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/accessibility-auditor/index.d.ts +1 -1
- package/dist/accessibility-auditor.js +15 -3
- package/dist/agent-handoff.js +6 -6
- package/dist/auto-doc/index.d.ts +1 -1
- package/dist/auto-doc.js +31 -20
- package/dist/auto-i18n-extractor/index.d.ts +1 -1
- package/dist/auto-i18n-extractor.js +12 -8
- package/dist/branch-guard.js +3 -3
- package/dist/changelog-writer/index.d.ts +1 -1
- package/dist/changelog-writer.js +19 -10
- package/dist/checkpoint/index.d.ts +1 -1
- package/dist/checkpoint.js +38 -24
- package/dist/code-metrics/index.d.ts +1 -1
- package/dist/code-metrics.js +12 -4
- package/dist/commit-validator.js +5 -5
- package/dist/context-pins/index.d.ts +1 -1
- package/dist/context-pins.js +12 -9
- package/dist/cost-tracker.js +21 -9
- package/dist/cron/index.d.ts +1 -1
- package/dist/cron.js +18 -5
- package/dist/dead-code-detector/index.d.ts +1 -1
- package/dist/dead-code-detector.js +14 -12
- package/dist/duplicate-code-detector/index.d.ts +1 -1
- package/dist/duplicate-code-detector.js +11 -3
- package/dist/feature-flag-tracker/index.d.ts +1 -1
- package/dist/feature-flag-tracker.js +12 -4
- package/dist/file-watcher/index.d.ts +1 -1
- package/dist/file-watcher.js +37 -38
- package/dist/git-autocommit/index.d.ts +1 -1
- package/dist/git-autocommit.js +44 -39
- package/dist/gitignore-guard/index.d.ts +1 -1
- package/dist/gitignore-guard.js +12 -6
- package/dist/index.js +1553 -1086
- package/dist/interface-contract-guard/index.d.ts +1 -1
- package/dist/interface-contract-guard.js +12 -4
- package/dist/knowledge-graph/index.d.ts +1 -1
- package/dist/knowledge-graph.js +11 -9
- package/dist/loop-breaker.js +11 -4
- package/dist/migration-planner/index.d.ts +1 -1
- package/dist/migration-planner.js +6 -2
- package/dist/notify-hub/index.d.ts +1 -1
- package/dist/notify-hub.js +19 -12
- package/dist/performance-regression-gate/index.d.ts +1 -1
- package/dist/performance-regression-gate.js +33 -13
- package/dist/pr-drafter/index.d.ts +10 -1
- package/dist/pr-drafter.js +57 -26
- package/dist/refactor-suggester/index.d.ts +1 -1
- package/dist/refactor-suggester.js +17 -4
- package/dist/release-notes-generator.js +2 -2
- package/dist/secret-scanner/index.d.ts +1 -1
- package/dist/secret-scanner.js +11 -3
- package/dist/security-hotspot-scanner/index.d.ts +1 -1
- package/dist/security-hotspot-scanner.js +6 -2
- package/dist/semantic-search-indexer/index.d.ts +1 -1
- package/dist/semantic-search-indexer.js +19 -3
- package/dist/semver-bump/index.d.ts +1 -1
- package/dist/semver-bump.js +57 -37
- package/dist/session-recap.js +4 -2
- package/dist/shell-check/index.d.ts +1 -1
- package/dist/shell-check.js +30 -39
- package/dist/smart-rename/index.d.ts +1 -1
- package/dist/smart-rename.js +23 -10
- package/dist/template-engine/index.d.ts +1 -1
- package/dist/template-engine.js +51 -38
- package/dist/test-flake-detector/index.d.ts +1 -1
- package/dist/test-flake-detector.js +11 -5
- package/dist/test-generator/index.d.ts +1 -1
- package/dist/test-generator.js +12 -8
- package/dist/todo-tracker/index.d.ts +68 -1
- package/dist/todo-tracker.js +579 -395
- package/dist/token-budget.js +7 -4
- package/dist/token-throttle.js +6 -3
- package/package.json +7 -7
package/dist/secret-scanner.js
CHANGED
|
@@ -12,6 +12,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
12
12
|
};
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
|
+
// src/secret-scanner/index.ts
|
|
16
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
17
|
+
|
|
15
18
|
// src/runtime/credential-patterns.ts
|
|
16
19
|
import {
|
|
17
20
|
cloneCredentialPatterns,
|
|
@@ -447,9 +450,14 @@ var plugin = {
|
|
|
447
450
|
mutating: false,
|
|
448
451
|
async execute(input) {
|
|
449
452
|
activateRuntime(runtime);
|
|
450
|
-
const rawText = input["text"] ?? input["content"] ?? input["string"] ?? input["input"] ?? input["code"] ?? input["value"]
|
|
451
|
-
|
|
452
|
-
|
|
453
|
+
const rawText = input["text"] ?? input["content"] ?? input["string"] ?? input["input"] ?? input["code"] ?? input["value"];
|
|
454
|
+
if (typeof rawText !== "string") {
|
|
455
|
+
throw new ToolValidationError({
|
|
456
|
+
message: "text is required and must be a string",
|
|
457
|
+
field: "text"
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const matched = findMatches(rawText);
|
|
453
461
|
return {
|
|
454
462
|
ok: true,
|
|
455
463
|
matched,
|
|
@@ -15,6 +15,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
15
15
|
// src/security-hotspot-scanner/index.ts
|
|
16
16
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
17
17
|
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
18
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
18
19
|
|
|
19
20
|
// src/runtime/index.ts
|
|
20
21
|
var runtime_exports = {};
|
|
@@ -335,7 +336,7 @@ Review or remove the risky pattern(s).`;
|
|
|
335
336
|
category: "Security",
|
|
336
337
|
mutating: false,
|
|
337
338
|
async execute(input) {
|
|
338
|
-
if (!cfg.enabled)
|
|
339
|
+
if (!cfg.enabled) throw new Error("security-hotspot-scanner is disabled");
|
|
339
340
|
const raw = input;
|
|
340
341
|
const targetPath = (typeof input.path === "string" ? input.path : void 0) ?? (typeof raw["directory"] === "string" ? raw["directory"] : void 0) ?? (typeof raw["dir"] === "string" ? raw["dir"] : void 0) ?? (typeof raw["SearchDirectory"] === "string" ? raw["SearchDirectory"] : void 0) ?? (typeof raw["TargetFile"] === "string" ? raw["TargetFile"] : void 0) ?? (typeof raw["filePath"] === "string" ? raw["filePath"] : void 0) ?? (typeof raw["targetFile"] === "string" ? raw["targetFile"] : void 0) ?? ".";
|
|
341
342
|
const result = await scanPath(targetPath, cfg);
|
|
@@ -343,7 +344,10 @@ Review or remove the risky pattern(s).`;
|
|
|
343
344
|
state.fileScanCount += result.filesScanned;
|
|
344
345
|
state.findingCount += result.findings.length;
|
|
345
346
|
if (!result.scanned) {
|
|
346
|
-
|
|
347
|
+
throw new ToolValidationError({
|
|
348
|
+
message: `cannot scan ${targetPath}: ${result.error ?? "unknown error"}`,
|
|
349
|
+
field: "path"
|
|
350
|
+
});
|
|
347
351
|
}
|
|
348
352
|
state.lastResult = {
|
|
349
353
|
path: result.path,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/semantic-search-indexer/index.ts
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
4
5
|
import { DEFAULT_WALK_IGNORE_DIRS } from "@wrongstack/core/utils";
|
|
5
6
|
var API_VERSION = "^0.1.10";
|
|
6
7
|
var escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -510,16 +511,31 @@ var plugin = {
|
|
|
510
511
|
icon: "search",
|
|
511
512
|
async execute(input) {
|
|
512
513
|
if (!cfg.enabled) {
|
|
513
|
-
|
|
514
|
+
throw new Error("semantic-search-indexer is disabled");
|
|
514
515
|
}
|
|
515
516
|
const rawPath = input.path ?? input["directory"] ?? input["dir"] ?? input["SearchDirectory"] ?? input["SearchPath"] ?? input["TargetFile"] ?? input["targetFile"] ?? input["filePath"] ?? input["file"];
|
|
516
517
|
const resolved = resolveProjectPath(typeof rawPath === "string" ? rawPath : void 0);
|
|
517
518
|
if (!resolved) {
|
|
518
|
-
|
|
519
|
+
throw new ToolValidationError({ message: "path outside project root", field: "path" });
|
|
519
520
|
}
|
|
520
|
-
await ensureIndex(resolved, cfg);
|
|
521
521
|
const rawQuery = input.query ?? input["q"] ?? input["text"] ?? input["keyword"] ?? input["keywords"] ?? input["search"] ?? "";
|
|
522
522
|
const query = String(rawQuery);
|
|
523
|
+
if (tokenize(query, cfg.minTokenLength).length === 0) {
|
|
524
|
+
throw new ToolValidationError({
|
|
525
|
+
message: `query must contain at least one keyword of ${cfg.minTokenLength}+ characters`,
|
|
526
|
+
field: "query"
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
await fs.stat(resolved);
|
|
531
|
+
} catch (err) {
|
|
532
|
+
throw new ToolValidationError({
|
|
533
|
+
message: `path does not exist or cannot be read: ${typeof rawPath === "string" ? rawPath : resolved}`,
|
|
534
|
+
field: "path",
|
|
535
|
+
cause: err
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
await ensureIndex(resolved, cfg);
|
|
523
539
|
const limit = typeof input.limit === "number" && input.limit >= 1 ? Math.floor(input.limit) : cfg.defaultLimit;
|
|
524
540
|
const results = runQuery(query, limit, cfg);
|
|
525
541
|
const queryTokens = [...new Set(tokenize(query, cfg.minTokenLength))];
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - semver_current: Show the current version from package.json
|
|
7
7
|
* - semver_changelog: Generate a changelog between two versions
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
10
10
|
type BumpType = 'major' | 'minor' | 'patch' | 'auto';
|
|
11
11
|
interface ConventionalCommit {
|
|
12
12
|
hash: string;
|
package/dist/semver-bump.js
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
// src/semver-bump/index.ts
|
|
2
2
|
import { expectDefined } from "@wrongstack/core/utils";
|
|
3
3
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
4
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
4
5
|
import { execFile } from "node:child_process";
|
|
5
6
|
import { access, readFile, readdir, writeFile } from "node:fs/promises";
|
|
6
7
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
7
8
|
var API_VERSION = "^0.1.10";
|
|
9
|
+
function requireProjectRoot(rawCwd) {
|
|
10
|
+
const safeCwd = resolveProjectRoot(rawCwd);
|
|
11
|
+
if (!safeCwd) {
|
|
12
|
+
throw new ToolValidationError({
|
|
13
|
+
message: "cwd must stay within the current project directory",
|
|
14
|
+
field: "cwd"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return safeCwd;
|
|
18
|
+
}
|
|
19
|
+
function requireGitRef(field, ref) {
|
|
20
|
+
if (ref !== void 0 && (typeof ref !== "string" || ref.startsWith("-"))) {
|
|
21
|
+
throw new ToolValidationError({ message: `${field} is not a valid git ref`, field });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
function resolveProjectRoot(rawCwd, root = process.cwd()) {
|
|
9
25
|
if (typeof rawCwd !== "string" || rawCwd.length === 0) return root;
|
|
10
26
|
const base = resolve(root);
|
|
@@ -250,14 +266,10 @@ var plugin = {
|
|
|
250
266
|
defaultPart = readDefaultPart(next);
|
|
251
267
|
});
|
|
252
268
|
async function performBump(part, dryRun, cwd) {
|
|
253
|
-
|
|
254
|
-
if (!safeCwd) {
|
|
255
|
-
return { ok: false, error: "cwd must stay within the current project directory" };
|
|
256
|
-
}
|
|
257
|
-
cwd = safeCwd;
|
|
269
|
+
cwd = requireProjectRoot(cwd);
|
|
258
270
|
const pkg = await getPackageJson(cwd);
|
|
259
271
|
if (!pkg) {
|
|
260
|
-
|
|
272
|
+
throw new Error("No package.json found");
|
|
261
273
|
}
|
|
262
274
|
const currentVersion = pkg.version;
|
|
263
275
|
let bumpPart = part;
|
|
@@ -272,8 +284,7 @@ var plugin = {
|
|
|
272
284
|
try {
|
|
273
285
|
commits = await getRecentCommits(lastTag, cwd);
|
|
274
286
|
} catch (err) {
|
|
275
|
-
|
|
276
|
-
return { ok: false, error: `Git error: ${msg}`, bumpPart: "patch" };
|
|
287
|
+
throw new Error(`Git error: ${toErrorMessage(err)}`, { cause: err });
|
|
277
288
|
}
|
|
278
289
|
bumpPart = determineBump(commits);
|
|
279
290
|
} else {
|
|
@@ -305,8 +316,7 @@ var plugin = {
|
|
|
305
316
|
try {
|
|
306
317
|
await runCommand(process.execPath, [bumpScript, "set", newVersion], root);
|
|
307
318
|
} catch (err) {
|
|
308
|
-
|
|
309
|
-
return { ok: false, error: `bump script failed: ${msg}` };
|
|
319
|
+
throw new Error(`bump script failed: ${toErrorMessage(err)}`, { cause: err });
|
|
310
320
|
}
|
|
311
321
|
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
312
322
|
const p = join(root, "website", rel);
|
|
@@ -323,16 +333,15 @@ var plugin = {
|
|
|
323
333
|
try {
|
|
324
334
|
pkgData = JSON.parse(await readFile(manifest, "utf-8"));
|
|
325
335
|
} catch (err) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
336
|
+
throw new Error(
|
|
337
|
+
`cannot bump: ${manifest} is not readable as JSON (${toErrorMessage(err)}). No manifests were modified.`,
|
|
338
|
+
{ cause: err }
|
|
339
|
+
);
|
|
330
340
|
}
|
|
331
341
|
if (!pkgData || typeof pkgData !== "object") {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
};
|
|
342
|
+
throw new Error(
|
|
343
|
+
`cannot bump: ${manifest} does not contain a JSON object. No manifests were modified.`
|
|
344
|
+
);
|
|
336
345
|
}
|
|
337
346
|
pkgData.version = newVersion;
|
|
338
347
|
pending.push({ path: manifest, contents: `${JSON.stringify(pkgData, null, 2)}
|
|
@@ -342,16 +351,20 @@ var plugin = {
|
|
|
342
351
|
await writeFile(path, contents, "utf-8");
|
|
343
352
|
}
|
|
344
353
|
}
|
|
354
|
+
let commitError;
|
|
345
355
|
try {
|
|
346
356
|
await runGit(["add", "--", ...changed], cwd);
|
|
347
357
|
await runGit(["commit", "-m", `chore: bump version to ${newVersion}`], cwd);
|
|
348
|
-
} catch {
|
|
358
|
+
} catch (err) {
|
|
359
|
+
commitError = toErrorMessage(err);
|
|
349
360
|
}
|
|
361
|
+
let tagError;
|
|
350
362
|
if (autoTag) {
|
|
351
363
|
try {
|
|
352
364
|
const msg = tagMessage.replace("{{version}}", newVersion);
|
|
353
365
|
await runGit(["tag", "-a", `${tagPrefix}${newVersion}`, "-m", msg], cwd);
|
|
354
|
-
} catch {
|
|
366
|
+
} catch (err) {
|
|
367
|
+
tagError = toErrorMessage(err);
|
|
355
368
|
}
|
|
356
369
|
}
|
|
357
370
|
api.log.info("semver-bump: bumped", { from: currentVersion, to: newVersion, bump: bumpPart });
|
|
@@ -371,13 +384,22 @@ var plugin = {
|
|
|
371
384
|
commitCount: commits.length,
|
|
372
385
|
breakingCount: commits.filter((c) => c.breaking).length
|
|
373
386
|
};
|
|
387
|
+
const tagged = autoTag && tagError === void 0;
|
|
388
|
+
const warnings = [
|
|
389
|
+
...commitError ? [`commit failed: ${commitError}`] : [],
|
|
390
|
+
...tagError ? [`tag failed: ${tagError}`] : []
|
|
391
|
+
];
|
|
374
392
|
return {
|
|
375
393
|
ok: true,
|
|
376
394
|
currentVersion,
|
|
377
395
|
newVersion,
|
|
378
396
|
bump: bumpPart,
|
|
379
|
-
tag
|
|
380
|
-
|
|
397
|
+
// Only name the tag when it was actually created.
|
|
398
|
+
tag: tagged ? `${tagPrefix}${newVersion}` : null,
|
|
399
|
+
committed: commitError === void 0,
|
|
400
|
+
tagged,
|
|
401
|
+
...warnings.length > 0 ? { warnings } : {},
|
|
402
|
+
message: `Bumped ${currentVersion} \u2192 ${newVersion} (${bumpPart})` + (warnings.length > 0 ? ` \u2014 ${warnings.join("; ")}` : "")
|
|
381
403
|
};
|
|
382
404
|
}
|
|
383
405
|
api.tools.register({
|
|
@@ -463,8 +485,12 @@ var plugin = {
|
|
|
463
485
|
if (!safeCwd) {
|
|
464
486
|
return { message: "cwd must stay within the current project directory" };
|
|
465
487
|
}
|
|
466
|
-
|
|
467
|
-
|
|
488
|
+
try {
|
|
489
|
+
const result = await performBump(mode, dry, safeCwd);
|
|
490
|
+
return { message: String(result["message"] ?? JSON.stringify(result)) };
|
|
491
|
+
} catch (err) {
|
|
492
|
+
return { message: toErrorMessage(err) };
|
|
493
|
+
}
|
|
468
494
|
}
|
|
469
495
|
});
|
|
470
496
|
api.tools.register({
|
|
@@ -481,11 +507,7 @@ var plugin = {
|
|
|
481
507
|
async execute(input) {
|
|
482
508
|
state.invocationCount += 1;
|
|
483
509
|
state.perTool["semver_current"] = (state.perTool["semver_current"] ?? 0) + 1;
|
|
484
|
-
const
|
|
485
|
-
const safeCwd = resolveProjectRoot(cwdInput);
|
|
486
|
-
if (!safeCwd) {
|
|
487
|
-
return { ok: false, error: "cwd must stay within the current project directory" };
|
|
488
|
-
}
|
|
510
|
+
const safeCwd = requireProjectRoot(input["cwd"]);
|
|
489
511
|
const pkg = await getPackageJson(safeCwd);
|
|
490
512
|
const currentVersion = pkg?.version ?? "unknown";
|
|
491
513
|
let latestTag = null;
|
|
@@ -531,22 +553,20 @@ var plugin = {
|
|
|
531
553
|
state.perTool["semver_changelog"] = (state.perTool["semver_changelog"] ?? 0) + 1;
|
|
532
554
|
const from = input["from"];
|
|
533
555
|
const to = input["to"] ?? "HEAD";
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return { ok: false, error: "cwd must stay within the current project directory" };
|
|
538
|
-
}
|
|
556
|
+
requireGitRef("from", from);
|
|
557
|
+
requireGitRef("to", to);
|
|
558
|
+
const safeCwd = requireProjectRoot(input["cwd"]);
|
|
539
559
|
const format = input["format"] ?? "markdown";
|
|
540
|
-
const
|
|
560
|
+
const rangeArgs = from ? [`${from}..${to}`] : ["-30", to];
|
|
541
561
|
let commits;
|
|
542
562
|
try {
|
|
543
563
|
const output = await runGit(
|
|
544
|
-
["log",
|
|
564
|
+
["log", ...rangeArgs, "--format=%H%x1f%s%x1f%b%x1e"],
|
|
545
565
|
safeCwd
|
|
546
566
|
);
|
|
547
567
|
commits = parseGitLogOutput(output);
|
|
548
568
|
} catch (err) {
|
|
549
|
-
|
|
569
|
+
throw new Error(`Failed to get git log: ${toErrorMessage(err)}`, { cause: err });
|
|
550
570
|
}
|
|
551
571
|
if (format === "json") {
|
|
552
572
|
return {
|
package/dist/session-recap.js
CHANGED
|
@@ -238,8 +238,10 @@ var plugin = {
|
|
|
238
238
|
const offTool = api.onPattern("tool.*", (eventName, payload) => {
|
|
239
239
|
touchActivity();
|
|
240
240
|
const p = payload;
|
|
241
|
-
const
|
|
242
|
-
|
|
241
|
+
const rawTool = p?.tool;
|
|
242
|
+
const nameOf = (v) => typeof v === "string" ? v : v && typeof v === "object" && typeof v.name === "string" ? v.name : void 0;
|
|
243
|
+
const toolName = nameOf(rawTool) ?? nameOf(p?.name) ?? eventName;
|
|
244
|
+
bumpToolCount(toolName);
|
|
243
245
|
if (toolName === "git_autocommit" || toolName.startsWith("git ")) {
|
|
244
246
|
}
|
|
245
247
|
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* via the `directory` + `pattern` parameters. Pass `files` for specific
|
|
9
9
|
* files, or `directory` (optionally with `pattern`) for recursive scanning.
|
|
10
10
|
*/
|
|
11
|
-
import type
|
|
11
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
12
12
|
declare const plugin: Plugin;
|
|
13
13
|
export default plugin;
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/shell-check.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/shell-check/index.ts
|
|
2
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
2
3
|
import { execFile } from "node:child_process";
|
|
3
4
|
import { readdir } from "node:fs/promises";
|
|
4
5
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -72,8 +73,11 @@ async function runShellCheck(files, severity, cwd) {
|
|
|
72
73
|
}
|
|
73
74
|
);
|
|
74
75
|
});
|
|
75
|
-
} catch {
|
|
76
|
-
|
|
76
|
+
} catch (err) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`shellcheck failed without output: ${err instanceof Error ? err.message : String(err)}`,
|
|
79
|
+
{ cause: err }
|
|
80
|
+
);
|
|
77
81
|
}
|
|
78
82
|
if (!raw.trim()) return [];
|
|
79
83
|
try {
|
|
@@ -86,22 +90,31 @@ async function runShellCheck(files, severity, cwd) {
|
|
|
86
90
|
code: item.code,
|
|
87
91
|
message: item.message
|
|
88
92
|
}));
|
|
89
|
-
} catch {
|
|
90
|
-
|
|
93
|
+
} catch (err) {
|
|
94
|
+
throw new Error(`shellcheck returned unparseable output: ${raw.trim().slice(0, 500)}`, {
|
|
95
|
+
cause: err
|
|
96
|
+
});
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
|
-
async function findShellFiles(dir, pattern) {
|
|
99
|
+
async function findShellFiles(dir, pattern, isRoot = true) {
|
|
94
100
|
const results = [];
|
|
95
101
|
let entries;
|
|
96
102
|
try {
|
|
97
103
|
entries = await readdir(dir, { withFileTypes: true });
|
|
98
|
-
} catch {
|
|
104
|
+
} catch (err) {
|
|
105
|
+
if (isRoot) {
|
|
106
|
+
throw new ToolValidationError({
|
|
107
|
+
message: `directory does not exist or cannot be read: ${dir}`,
|
|
108
|
+
field: "directory",
|
|
109
|
+
cause: err
|
|
110
|
+
});
|
|
111
|
+
}
|
|
99
112
|
return results;
|
|
100
113
|
}
|
|
101
114
|
for (const entry of entries) {
|
|
102
115
|
const full = join(dir, entry.name);
|
|
103
116
|
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
|
|
104
|
-
results.push(...await findShellFiles(full, pattern));
|
|
117
|
+
results.push(...await findShellFiles(full, pattern, false));
|
|
105
118
|
} else if (entry.isFile() && (entry.name.endsWith(".sh") || entry.name.endsWith(".bash") || entry.name.endsWith(".zsh") || entry.name === "Dockerfile" || entry.name === ".bashrc" || entry.name === ".zshrc")) {
|
|
106
119
|
if (!pattern || entry.name.includes(pattern)) {
|
|
107
120
|
results.push(full);
|
|
@@ -171,12 +184,8 @@ var plugin = {
|
|
|
171
184
|
enum: ["error", "warning", "info", "style"],
|
|
172
185
|
default: "warning",
|
|
173
186
|
description: "Minimum severity level to report"
|
|
174
|
-
},
|
|
175
|
-
fix: {
|
|
176
|
-
type: "boolean",
|
|
177
|
-
default: false,
|
|
178
|
-
description: "Apply safe automatic fixes where possible"
|
|
179
187
|
}
|
|
188
|
+
// `fix` was declared ("apply safe automatic fixes") but never implemented.
|
|
180
189
|
}
|
|
181
190
|
},
|
|
182
191
|
permission: "auto",
|
|
@@ -202,22 +211,16 @@ var plugin = {
|
|
|
202
211
|
state.invocationCount += 1;
|
|
203
212
|
const pathIsSafe = (p) => typeof p === "string" && p.length > 0 && p.length <= MAX_PATH_LEN && withinProject(p);
|
|
204
213
|
if (!pathIsSafe(directory)) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
filesScanned: 0,
|
|
210
|
-
rejectedOutsideProject: true
|
|
211
|
-
};
|
|
214
|
+
throw new ToolValidationError({
|
|
215
|
+
message: `directory path is outside the project root: ${directory}`,
|
|
216
|
+
field: "directory"
|
|
217
|
+
});
|
|
212
218
|
}
|
|
213
219
|
if (files?.some((f) => !pathIsSafe(f))) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
filesScanned: 0,
|
|
219
|
-
rejectedOutsideProject: true
|
|
220
|
-
};
|
|
220
|
+
throw new ToolValidationError({
|
|
221
|
+
message: "one or more file paths are outside the project root",
|
|
222
|
+
field: "files"
|
|
223
|
+
});
|
|
221
224
|
}
|
|
222
225
|
let checkFiles;
|
|
223
226
|
let scannedDirectories = false;
|
|
@@ -243,19 +246,7 @@ var plugin = {
|
|
|
243
246
|
mode: scannedDirectories ? "directory" : "files"
|
|
244
247
|
};
|
|
245
248
|
}
|
|
246
|
-
|
|
247
|
-
try {
|
|
248
|
-
issues = await runShellCheck(checkFiles, severity);
|
|
249
|
-
} catch (err) {
|
|
250
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
251
|
-
return {
|
|
252
|
-
ok: false,
|
|
253
|
-
error: msg,
|
|
254
|
-
issues: [],
|
|
255
|
-
filesScanned: 0,
|
|
256
|
-
mode: scannedDirectories ? "directory" : "files"
|
|
257
|
-
};
|
|
258
|
-
}
|
|
249
|
+
const issues = await runShellCheck(checkFiles, severity);
|
|
259
250
|
const byFile = {};
|
|
260
251
|
for (const issue of issues) {
|
|
261
252
|
if (byFile[issue.file] === void 0) {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* @public
|
|
20
20
|
*/
|
|
21
|
-
import type
|
|
21
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
22
22
|
/** True when `name` is something this tool may safely substitute. */
|
|
23
23
|
export declare function isIdentifier(name: string): boolean;
|
|
24
24
|
declare const plugin: Plugin;
|
package/dist/smart-rename.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/smart-rename/index.ts
|
|
2
2
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
4
5
|
var NEW_API_VERSION = "^0.1.10";
|
|
5
6
|
var state = {
|
|
6
7
|
renameCount: 0,
|
|
@@ -106,32 +107,44 @@ var plugin = {
|
|
|
106
107
|
mutating: true,
|
|
107
108
|
capabilities: ["fs.write"],
|
|
108
109
|
async execute(input) {
|
|
109
|
-
if (!cfg.enabled)
|
|
110
|
+
if (!cfg.enabled) throw new Error("smart-rename is disabled");
|
|
110
111
|
const inp = input ?? {};
|
|
111
112
|
const rawPath = inp["path"] ?? inp["filePath"] ?? inp["file_path"] ?? inp["TargetFile"] ?? inp["targetFile"] ?? inp["file"];
|
|
112
113
|
const oldName = inp["oldName"] ?? inp["old_name"] ?? inp["from"];
|
|
113
114
|
const newName = inp["newName"] ?? inp["new_name"] ?? inp["to"];
|
|
114
115
|
if (!rawPath || typeof rawPath !== "string") {
|
|
115
|
-
|
|
116
|
+
throw new ToolValidationError({ message: "path is required", field: "path" });
|
|
116
117
|
}
|
|
117
118
|
if (!oldName || typeof oldName !== "string" || oldName.length === 0) {
|
|
118
|
-
|
|
119
|
+
throw new ToolValidationError({ message: "oldName is required", field: "oldName" });
|
|
119
120
|
}
|
|
120
121
|
if (!newName || typeof newName !== "string" || newName.length === 0) {
|
|
121
|
-
|
|
122
|
+
throw new ToolValidationError({ message: "newName is required", field: "newName" });
|
|
122
123
|
}
|
|
123
124
|
if (!isIdentifier(oldName)) {
|
|
124
|
-
|
|
125
|
+
throw new ToolValidationError({
|
|
126
|
+
message: `oldName "${oldName}" is not a valid identifier`,
|
|
127
|
+
field: "oldName"
|
|
128
|
+
});
|
|
125
129
|
}
|
|
126
130
|
if (!isIdentifier(newName)) {
|
|
127
|
-
|
|
131
|
+
throw new ToolValidationError({
|
|
132
|
+
message: `newName "${newName}" is not a valid identifier`,
|
|
133
|
+
field: "newName"
|
|
134
|
+
});
|
|
128
135
|
}
|
|
129
136
|
if (!withinProject(rawPath)) {
|
|
130
|
-
|
|
137
|
+
throw new ToolValidationError({
|
|
138
|
+
message: "path is outside the project root",
|
|
139
|
+
field: "path"
|
|
140
|
+
});
|
|
131
141
|
}
|
|
132
142
|
const ext = extname(rawPath).toLowerCase();
|
|
133
143
|
if (!cfg.extensions.includes(ext)) {
|
|
134
|
-
|
|
144
|
+
throw new ToolValidationError({
|
|
145
|
+
message: `extension ${ext} is not allowed for rename`,
|
|
146
|
+
field: "path"
|
|
147
|
+
});
|
|
135
148
|
}
|
|
136
149
|
const resolved = resolve(process.cwd(), rawPath);
|
|
137
150
|
let content;
|
|
@@ -139,7 +152,7 @@ var plugin = {
|
|
|
139
152
|
content = readFileSync(resolved, "utf-8");
|
|
140
153
|
} catch (err) {
|
|
141
154
|
state.errorCount += 1;
|
|
142
|
-
|
|
155
|
+
throw new Error(`Could not read ${rawPath}: ${String(err)}`, { cause: err });
|
|
143
156
|
}
|
|
144
157
|
const { preview, replacements } = renameInContent(content, oldName, newName);
|
|
145
158
|
state.renameCount += 1;
|
|
@@ -152,7 +165,7 @@ var plugin = {
|
|
|
152
165
|
writeFileSync(resolved, preview, "utf-8");
|
|
153
166
|
} catch (err) {
|
|
154
167
|
state.errorCount += 1;
|
|
155
|
-
|
|
168
|
+
throw new Error(`Could not write ${rawPath}: ${String(err)}`, { cause: err });
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
return {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - template_create: Save a named template to the plugin store
|
|
8
8
|
* - template_list: List all saved templates
|
|
9
9
|
*/
|
|
10
|
-
import type
|
|
10
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
11
11
|
declare const plugin: Plugin;
|
|
12
12
|
export default plugin;
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|