@wrongstack/plugins 0.317.0 → 0.317.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/accessibility-auditor.js +12 -10
- package/dist/agent-handoff.js +30 -10
- package/dist/auto-doc.js +22 -9
- package/dist/auto-escalate.js +17 -7
- package/dist/auto-i18n-extractor.js +19 -9
- package/dist/branch-guard.js +12 -9
- package/dist/changelog-writer/index.d.ts +3 -3
- package/dist/changelog-writer.js +59 -14
- package/dist/checkpoint.js +18 -7
- package/dist/code-metrics.js +17 -9
- package/dist/commit-validator.js +18 -11
- package/dist/config-validator.js +5 -3
- package/dist/context-pins.js +17 -6
- package/dist/cost-tracker.js +24 -16
- package/dist/cron.js +17 -13
- package/dist/dead-code-detector.js +5 -4
- package/dist/dep-guard.js +5 -4
- package/dist/dependency-vulnerability-gate.js +64 -24
- package/dist/diff-summary.js +6 -2
- package/dist/doc-sync-guard.js +12 -2
- package/dist/duplicate-code-detector.js +87 -15
- package/dist/error-lens.js +6 -5
- package/dist/feature-flag-tracker.js +43 -9
- package/dist/file-watcher.js +26 -3
- package/dist/format-on-save.js +9 -5
- package/dist/git-autocommit.js +20 -12
- package/dist/gitignore-guard.js +7 -4
- package/dist/import-organizer.js +9 -5
- package/dist/index.js +1675 -745
- package/dist/injection-shield/index.d.ts +1 -0
- package/dist/injection-shield.js +30 -5
- package/dist/interface-contract-guard.js +4 -2
- package/dist/knowledge-graph.js +40 -14
- package/dist/license-audit-gate.js +61 -8
- package/dist/lint-gate.js +13 -5
- package/dist/llm-cache.js +20 -6
- package/dist/loop-breaker.js +16 -8
- package/dist/migration-planner.js +80 -11
- package/dist/model-router.js +16 -9
- package/dist/notify-hub.js +14 -5
- package/dist/path-guard.js +7 -3
- package/dist/performance-regression-gate.js +12 -6
- package/dist/plugin-stack-observer.js +25 -3
- package/dist/pr-drafter.js +16 -7
- package/dist/process-guard.js +2 -1
- package/dist/prompt-firewall.js +9 -7
- package/dist/refactor-suggester.js +37 -8
- package/dist/release-notes-generator/index.d.ts +9 -0
- package/dist/release-notes-generator.js +50 -12
- package/dist/schema-evolution-guard.js +33 -6
- package/dist/secret-scanner.js +10 -7
- package/dist/security-hotspot-scanner.js +13 -8
- package/dist/semantic-search-indexer/index.d.ts +11 -0
- package/dist/semantic-search-indexer.js +67 -19
- package/dist/semver-bump/index.d.ts +3 -3
- package/dist/semver-bump.js +30 -15
- package/dist/session-recap/index.d.ts +16 -0
- package/dist/session-recap.js +18 -9
- package/dist/shell-check.js +27 -6
- package/dist/smart-rename.js +18 -9
- package/dist/spec-linker.js +70 -19
- package/dist/template-engine.js +24 -14
- package/dist/test-coverage-gate.js +1 -1
- package/dist/test-flake-detector.js +28 -5
- package/dist/test-generator/index.d.ts +10 -0
- package/dist/test-generator.js +35 -13
- package/dist/todo-listener.js +2 -2
- package/dist/todo-tracker.js +19 -11
- package/dist/token-budget.js +14 -9
- package/dist/token-throttle.js +8 -3
- package/dist/type-gate.js +9 -5
- package/package.json +5 -5
|
@@ -47,12 +47,15 @@ function readConfig(raw) {
|
|
|
47
47
|
return { ...DEFAULTS };
|
|
48
48
|
}
|
|
49
49
|
const r = raw;
|
|
50
|
-
const
|
|
50
|
+
const rawScan = r["scanOnChange"] ?? r["scan_on_change"] ?? r["extensions"] ?? r["file_extensions"];
|
|
51
|
+
const scanOnChange = Array.isArray(rawScan) ? rawScan.filter((x) => typeof x === "string") : DEFAULTS.scanOnChange;
|
|
51
52
|
scanOnChangeSet = new Set(scanOnChange);
|
|
53
|
+
const rawSev = typeof (r["severity"] ?? r["mode"] ?? r["action"]) === "string" ? String(r["severity"] ?? r["mode"] ?? r["action"]).trim().toLowerCase() : void 0;
|
|
54
|
+
const rawMax = r["maxFindings"] ?? r["max_findings"] ?? r["limit"];
|
|
52
55
|
return {
|
|
53
56
|
enabled: r["enabled"] === true,
|
|
54
|
-
severity:
|
|
55
|
-
maxFindings: typeof
|
|
57
|
+
severity: rawSev === "block" ? "block" : DEFAULTS.severity,
|
|
58
|
+
maxFindings: typeof rawMax === "number" && rawMax >= 1 && rawMax <= 100 ? rawMax : DEFAULTS.maxFindings,
|
|
56
59
|
scanOnChange
|
|
57
60
|
};
|
|
58
61
|
}
|
|
@@ -72,7 +75,7 @@ var PATTERNS = [
|
|
|
72
75
|
{
|
|
73
76
|
type: "hardcoded_http",
|
|
74
77
|
severity: "medium",
|
|
75
|
-
regex: /http:\/\/[a-zA-Z0-9][^\s'")\\]*/i
|
|
78
|
+
regex: /http:\/\/(?!(?:localhost|127\.0\.0\.1|0\.0\.0\.0|www\.w3\.org|schemas\.microsoft\.com)\b)[a-zA-Z0-9][^\s'")\\]*/i
|
|
76
79
|
},
|
|
77
80
|
{
|
|
78
81
|
type: "console_log_credentials",
|
|
@@ -250,7 +253,7 @@ var plugin = {
|
|
|
250
253
|
if (!cfg.enabled) return;
|
|
251
254
|
if (input.toolResult?.isError) return;
|
|
252
255
|
const inp = input.toolInput ?? {};
|
|
253
|
-
const rawPath = inp["path"] ?? inp["filePath"] ?? inp["file_path"];
|
|
256
|
+
const rawPath = inp["path"] ?? inp["TargetFile"] ?? inp["filePath"] ?? inp["targetFile"] ?? inp["file_path"] ?? inp["file"];
|
|
254
257
|
const sourcePath = typeof rawPath === "string" ? rawPath : void 0;
|
|
255
258
|
if (!sourcePath || !(0, runtime_exports.withinProject)(sourcePath)) return;
|
|
256
259
|
const ext = extname(sourcePath).toLowerCase();
|
|
@@ -315,12 +318,14 @@ Review or remove the risky pattern(s).`;
|
|
|
315
318
|
mutating: false,
|
|
316
319
|
async execute(input) {
|
|
317
320
|
if (!cfg.enabled) return { ok: false, error: "security-hotspot-scanner is disabled" };
|
|
318
|
-
const
|
|
321
|
+
const raw = input;
|
|
322
|
+
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) ?? ".";
|
|
323
|
+
const result = await scanPath(targetPath, cfg);
|
|
319
324
|
state.scanCount += 1;
|
|
320
325
|
state.fileScanCount += result.filesScanned;
|
|
321
326
|
state.findingCount += result.findings.length;
|
|
322
327
|
if (!result.scanned) {
|
|
323
|
-
return { ok: false, error: result.error, path:
|
|
328
|
+
return { ok: false, error: result.error, path: targetPath };
|
|
324
329
|
}
|
|
325
330
|
state.lastResult = {
|
|
326
331
|
path: result.path,
|
|
@@ -330,7 +335,7 @@ Review or remove the risky pattern(s).`;
|
|
|
330
335
|
};
|
|
331
336
|
return {
|
|
332
337
|
ok: true,
|
|
333
|
-
path:
|
|
338
|
+
path: targetPath,
|
|
334
339
|
filesScanned: result.filesScanned,
|
|
335
340
|
findings: result.findings,
|
|
336
341
|
findingCount: result.findings.length,
|
|
@@ -31,6 +31,17 @@
|
|
|
31
31
|
* @public
|
|
32
32
|
*/
|
|
33
33
|
import type { Plugin } from '@wrongstack/core/types';
|
|
34
|
+
interface SemanticSearchConfig {
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
includeExtensions: string[];
|
|
37
|
+
excludePatterns: string[];
|
|
38
|
+
maxFileBytes: number;
|
|
39
|
+
defaultLimit: number;
|
|
40
|
+
minTokenLength: number;
|
|
41
|
+
maxMatchesPerFile: number;
|
|
42
|
+
maxFiles: number;
|
|
43
|
+
}
|
|
44
|
+
export declare function readConfig(raw: unknown): SemanticSearchConfig;
|
|
34
45
|
declare const plugin: Plugin;
|
|
35
46
|
export default plugin;
|
|
36
47
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -14,6 +14,8 @@ var state = {
|
|
|
14
14
|
queryCount: 0,
|
|
15
15
|
reindexCount: 0,
|
|
16
16
|
buildPromise: null,
|
|
17
|
+
buildGeneration: 0,
|
|
18
|
+
publishedGeneration: 0,
|
|
17
19
|
hookUnregister: null
|
|
18
20
|
};
|
|
19
21
|
var DEFAULTS = {
|
|
@@ -61,18 +63,23 @@ var DEFAULTS = {
|
|
|
61
63
|
function readConfig(raw) {
|
|
62
64
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS, includeExtensions: [...DEFAULTS.includeExtensions], excludePatterns: [...DEFAULTS.excludePatterns] };
|
|
63
65
|
const r = raw;
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
+
const rawExts = r["includeExtensions"] ?? r["include_extensions"] ?? r["extensions"] ?? r["file_extensions"];
|
|
67
|
+
const includeExtensions = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : [...DEFAULTS.includeExtensions];
|
|
68
|
+
const rawExclude = r["excludePatterns"] ?? r["exclude_patterns"] ?? r["exclude"];
|
|
69
|
+
const excludePatterns = Array.isArray(rawExclude) ? rawExclude.filter((x) => typeof x === "string") : [...DEFAULTS.excludePatterns];
|
|
66
70
|
const clamp = (v, min, max, fallback) => typeof v === "number" && Number.isFinite(v) && v >= min && v <= max ? v : fallback;
|
|
71
|
+
const rawBytes = r["maxFileBytes"] ?? r["max_file_bytes"] ?? r["maxBytes"] ?? r["max_bytes"];
|
|
72
|
+
const rawLimit = r["defaultLimit"] ?? r["default_limit"] ?? r["limit"];
|
|
73
|
+
const rawMaxFiles = r["maxFiles"] ?? r["max_files"];
|
|
67
74
|
return {
|
|
68
75
|
enabled: r["enabled"] !== false,
|
|
69
76
|
includeExtensions,
|
|
70
77
|
excludePatterns,
|
|
71
|
-
maxFileBytes: clamp(
|
|
72
|
-
defaultLimit: clamp(
|
|
78
|
+
maxFileBytes: clamp(rawBytes, 1024, 5e7, DEFAULTS.maxFileBytes),
|
|
79
|
+
defaultLimit: clamp(rawLimit, 1, 1e3, DEFAULTS.defaultLimit),
|
|
73
80
|
minTokenLength: clamp(r["minTokenLength"], 1, 10, DEFAULTS.minTokenLength),
|
|
74
81
|
maxMatchesPerFile: clamp(r["maxMatchesPerFile"], 1, 100, DEFAULTS.maxMatchesPerFile),
|
|
75
|
-
maxFiles: clamp(
|
|
82
|
+
maxFiles: clamp(rawMaxFiles, 1, 5e4, DEFAULTS.maxFiles)
|
|
76
83
|
};
|
|
77
84
|
}
|
|
78
85
|
function normalizeSlashes(p) {
|
|
@@ -221,25 +228,30 @@ async function buildIndex(rootPath, cfg) {
|
|
|
221
228
|
if (rootStats.isFile()) {
|
|
222
229
|
const relPath = normalizeSlashes(relative(normalizeSlashes(process.cwd()), rootPath));
|
|
223
230
|
await indexFileFromStats(rootPath, relPath === "" ? "." : relPath, rootStats, cfg);
|
|
224
|
-
state.fileCount = state.index.files.size;
|
|
231
|
+
state.fileCount = state.index ? state.index.files.size : 0;
|
|
225
232
|
} else if (rootStats.isDirectory()) {
|
|
226
233
|
const fileBatch = [];
|
|
227
234
|
await walkDirectory(rootPath, cfg, excludes, fileBatch);
|
|
228
235
|
await flushFileBatch(fileBatch, cfg);
|
|
229
236
|
}
|
|
230
|
-
state.termCount = state.index.terms.size;
|
|
237
|
+
state.termCount = state.index ? state.index.terms.size : 0;
|
|
231
238
|
}
|
|
232
239
|
async function ensureIndex(rootPath, cfg) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
state.buildPromise = buildIndex(rootPath, cfg).finally(() => {
|
|
240
|
+
for (; ; ) {
|
|
241
|
+
if (state.index && state.cachedPath === rootPath && state.publishedGeneration === state.buildGeneration) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const gen = state.buildGeneration;
|
|
245
|
+
state.buildPromise ??= buildIndex(rootPath, cfg).finally(() => {
|
|
240
246
|
state.buildPromise = null;
|
|
241
247
|
});
|
|
242
248
|
await state.buildPromise;
|
|
249
|
+
if (gen === state.buildGeneration && state.index && state.cachedPath === rootPath) {
|
|
250
|
+
state.publishedGeneration = gen;
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
state.index = null;
|
|
254
|
+
state.cachedPath = null;
|
|
243
255
|
}
|
|
244
256
|
}
|
|
245
257
|
function compareRankedCandidates(a, b) {
|
|
@@ -379,6 +391,8 @@ var plugin = {
|
|
|
379
391
|
state.queryCount = 0;
|
|
380
392
|
state.reindexCount = 0;
|
|
381
393
|
state.buildPromise = null;
|
|
394
|
+
state.buildGeneration = 0;
|
|
395
|
+
state.publishedGeneration = 0;
|
|
382
396
|
if (state.hookUnregister) {
|
|
383
397
|
try {
|
|
384
398
|
state.hookUnregister();
|
|
@@ -397,6 +411,11 @@ var plugin = {
|
|
|
397
411
|
type: "string",
|
|
398
412
|
description: "Space-separated keywords to search for."
|
|
399
413
|
},
|
|
414
|
+
q: { type: "string", description: "Alias for `query`." },
|
|
415
|
+
text: { type: "string", description: "Alias for `query`." },
|
|
416
|
+
keyword: { type: "string", description: "Alias for `query`." },
|
|
417
|
+
keywords: { type: "string", description: "Alias for `query`." },
|
|
418
|
+
search: { type: "string", description: "Alias for `query`." },
|
|
400
419
|
limit: {
|
|
401
420
|
type: "number",
|
|
402
421
|
description: "Maximum number of results (defaults to configured defaultLimit)."
|
|
@@ -404,9 +423,23 @@ var plugin = {
|
|
|
404
423
|
path: {
|
|
405
424
|
type: "string",
|
|
406
425
|
description: "Directory or file to search under (defaults to project root)."
|
|
407
|
-
}
|
|
426
|
+
},
|
|
427
|
+
directory: { type: "string", description: "Alias for `path`." },
|
|
428
|
+
dir: { type: "string", description: "Alias for `path`." },
|
|
429
|
+
SearchDirectory: { type: "string", description: "Alias for `path`." },
|
|
430
|
+
SearchPath: { type: "string", description: "Alias for `path`." }
|
|
408
431
|
},
|
|
409
|
-
|
|
432
|
+
// Schema-validating hosts check this BEFORE execute() normalizes the
|
|
433
|
+
// aliases, so every query alternative must be declared or alias-only
|
|
434
|
+
// inputs are rejected as schema-invalid before they reach the tool.
|
|
435
|
+
anyOf: [
|
|
436
|
+
{ required: ["query"] },
|
|
437
|
+
{ required: ["q"] },
|
|
438
|
+
{ required: ["text"] },
|
|
439
|
+
{ required: ["keyword"] },
|
|
440
|
+
{ required: ["keywords"] },
|
|
441
|
+
{ required: ["search"] }
|
|
442
|
+
]
|
|
410
443
|
},
|
|
411
444
|
permission: "auto",
|
|
412
445
|
category: "Search",
|
|
@@ -417,12 +450,14 @@ var plugin = {
|
|
|
417
450
|
if (!cfg.enabled) {
|
|
418
451
|
return { ok: false, error: "semantic-search-indexer is disabled" };
|
|
419
452
|
}
|
|
420
|
-
const
|
|
453
|
+
const rawPath = input.path ?? input["directory"] ?? input["dir"] ?? input["SearchDirectory"] ?? input["SearchPath"] ?? input["TargetFile"] ?? input["targetFile"] ?? input["filePath"] ?? input["file"];
|
|
454
|
+
const resolved = resolveProjectPath(typeof rawPath === "string" ? rawPath : void 0);
|
|
421
455
|
if (!resolved) {
|
|
422
456
|
return { ok: false, error: "path outside project root" };
|
|
423
457
|
}
|
|
424
458
|
await ensureIndex(resolved, cfg);
|
|
425
|
-
const
|
|
459
|
+
const rawQuery = input.query ?? input["q"] ?? input["text"] ?? input["keyword"] ?? input["keywords"] ?? input["search"] ?? "";
|
|
460
|
+
const query = String(rawQuery);
|
|
426
461
|
const limit = typeof input.limit === "number" && input.limit >= 1 ? Math.floor(input.limit) : cfg.defaultLimit;
|
|
427
462
|
const results = runQuery(query, limit, cfg);
|
|
428
463
|
const queryTokens = [...new Set(tokenize(query, cfg.minTokenLength))];
|
|
@@ -464,6 +499,16 @@ var plugin = {
|
|
|
464
499
|
};
|
|
465
500
|
}
|
|
466
501
|
});
|
|
502
|
+
if (typeof api.registerHook === "function") {
|
|
503
|
+
state.hookUnregister = api.registerHook(
|
|
504
|
+
"PostToolUse",
|
|
505
|
+
"write|edit|write_to_file|replace_file_content",
|
|
506
|
+
(() => {
|
|
507
|
+
state.buildGeneration += 1;
|
|
508
|
+
}),
|
|
509
|
+
{ background: true }
|
|
510
|
+
);
|
|
511
|
+
}
|
|
467
512
|
api.log.info("semantic-search-indexer plugin loaded", {
|
|
468
513
|
version: "0.1.0",
|
|
469
514
|
defaultLimit: cfg.defaultLimit,
|
|
@@ -493,6 +538,8 @@ var plugin = {
|
|
|
493
538
|
state.queryCount = 0;
|
|
494
539
|
state.reindexCount = 0;
|
|
495
540
|
state.buildPromise = null;
|
|
541
|
+
state.buildGeneration = 0;
|
|
542
|
+
state.publishedGeneration = 0;
|
|
496
543
|
api.log.info("semantic-search-indexer: teardown complete", { final });
|
|
497
544
|
},
|
|
498
545
|
async health() {
|
|
@@ -511,5 +558,6 @@ var plugin = {
|
|
|
511
558
|
};
|
|
512
559
|
var semantic_search_indexer_default = plugin;
|
|
513
560
|
export {
|
|
514
|
-
semantic_search_indexer_default as default
|
|
561
|
+
semantic_search_indexer_default as default,
|
|
562
|
+
readConfig
|
|
515
563
|
};
|
|
@@ -15,9 +15,9 @@ interface ConventionalCommit {
|
|
|
15
15
|
message: string;
|
|
16
16
|
breaking: boolean;
|
|
17
17
|
}
|
|
18
|
-
/** Parse a conventional-commit subject line. Accepts the breaking `!` both
|
|
19
|
-
* before and after the scope (`feat!: x`, `feat(api)!: x`). */
|
|
20
|
-
export declare function parseConventional(subject: string): Omit<ConventionalCommit, 'hash'>;
|
|
18
|
+
/** Parse a conventional-commit subject line and optional body. Accepts the breaking `!` both
|
|
19
|
+
* before and after the scope (`feat!: x`, `feat(api)!: x`), and checks body for BREAKING CHANGE. */
|
|
20
|
+
export declare function parseConventional(subject: string, body?: string): Omit<ConventionalCommit, 'hash'>;
|
|
21
21
|
export declare function determineBump(commits: ConventionalCommit[]): BumpType;
|
|
22
22
|
declare const plugin: Plugin;
|
|
23
23
|
export default plugin;
|
package/dist/semver-bump.js
CHANGED
|
@@ -109,26 +109,43 @@ function bumpVersion(version, part) {
|
|
|
109
109
|
}
|
|
110
110
|
return `${major}.${minor}.${patch}`;
|
|
111
111
|
}
|
|
112
|
-
function parseConventional(subject) {
|
|
112
|
+
function parseConventional(subject, body = "") {
|
|
113
113
|
const m = subject.match(/^(\w+)(!)?(?:\(([^)]+)\))?(!)?:\s+(.+)/);
|
|
114
|
+
const hasBreakingInSubject = !!(m?.[2] ?? m?.[4]);
|
|
115
|
+
const hasBreakingInBody = /(?:^|\W)BREAKING[ -]CHANGES?(?!\w)/i.test(body);
|
|
114
116
|
return {
|
|
115
117
|
type: m?.[1] ?? "chore",
|
|
116
|
-
breaking:
|
|
118
|
+
breaking: hasBreakingInSubject || hasBreakingInBody,
|
|
117
119
|
scope: m?.[3],
|
|
118
120
|
message: m?.[5] ?? subject
|
|
119
121
|
};
|
|
120
122
|
}
|
|
121
|
-
|
|
122
|
-
const range = sinceTag ? `${sinceTag}..HEAD` : "-30";
|
|
123
|
-
const output = await runGit(["log", range, "--format=%H %s"], cwd);
|
|
123
|
+
function parseGitLogOutput(output) {
|
|
124
124
|
if (!output) return [];
|
|
125
|
-
|
|
125
|
+
if (output.includes("") || output.includes("")) {
|
|
126
|
+
return output.split("").map((block) => block.trim()).filter(Boolean).map((block) => {
|
|
127
|
+
const parts = block.split("");
|
|
128
|
+
const hash = parts[0] ?? "";
|
|
129
|
+
const subject = parts[1] ?? "";
|
|
130
|
+
const body = parts[2] ?? "";
|
|
131
|
+
return { hash, ...parseConventional(subject, body) };
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return output.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
126
135
|
const spaceIdx = line.indexOf(" ");
|
|
136
|
+
if (spaceIdx === -1) {
|
|
137
|
+
return { hash: line, ...parseConventional("") };
|
|
138
|
+
}
|
|
127
139
|
const hash = line.slice(0, spaceIdx);
|
|
128
140
|
const message = line.slice(spaceIdx + 1);
|
|
129
141
|
return { hash, ...parseConventional(message) };
|
|
130
142
|
});
|
|
131
143
|
}
|
|
144
|
+
async function getRecentCommits(sinceTag, cwd) {
|
|
145
|
+
const range = sinceTag ? `${sinceTag}..HEAD` : "-30";
|
|
146
|
+
const output = await runGit(["log", range, "--format=%H%x1f%s%x1f%b%x1e"], cwd);
|
|
147
|
+
return parseGitLogOutput(output);
|
|
148
|
+
}
|
|
132
149
|
function determineBump(commits) {
|
|
133
150
|
if (commits.some((c) => c.breaking)) return "major";
|
|
134
151
|
if (commits.some((c) => c.type === "feat")) return "minor";
|
|
@@ -264,6 +281,7 @@ var plugin = {
|
|
|
264
281
|
dry_run: true,
|
|
265
282
|
currentVersion,
|
|
266
283
|
suggestedBump: bumpPart,
|
|
284
|
+
bump: bumpPart,
|
|
267
285
|
newVersion,
|
|
268
286
|
commitCount: part === "auto" ? commits.length : void 0,
|
|
269
287
|
message: `Would bump ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
@@ -379,8 +397,10 @@ var plugin = {
|
|
|
379
397
|
state.invocationCount += 1;
|
|
380
398
|
state.perTool["semver_bump"] = (state.perTool["semver_bump"] ?? 0) + 1;
|
|
381
399
|
const cwd = input["cwd"];
|
|
382
|
-
const dryRun = input["dry_run"] ?? false;
|
|
383
|
-
const
|
|
400
|
+
const dryRun = input["dry_run"] ?? input["dryRun"] ?? input["dry"] ?? false;
|
|
401
|
+
const rawPart = input["part"] ?? input["bumpType"] ?? input["bump_type"] ?? input["type"] ?? input["releaseType"] ?? input["release_type"] ?? input["level"] ?? input["increment"] ?? input["bump"];
|
|
402
|
+
const normPart = typeof rawPart === "string" ? rawPart.trim().toLowerCase() : void 0;
|
|
403
|
+
const part = normPart === "major" || normPart === "minor" || normPart === "patch" || normPart === "auto" ? normPart : defaultPart;
|
|
384
404
|
return performBump(part, dryRun, cwd);
|
|
385
405
|
}
|
|
386
406
|
});
|
|
@@ -516,15 +536,10 @@ var plugin = {
|
|
|
516
536
|
let commits;
|
|
517
537
|
try {
|
|
518
538
|
const output = await runGit(
|
|
519
|
-
["log", range === to ? "-30" : range, "--format=%H
|
|
539
|
+
["log", range === to ? "-30" : range, "--format=%H%x1f%s%x1f%b%x1e"],
|
|
520
540
|
safeCwd
|
|
521
541
|
);
|
|
522
|
-
commits = output
|
|
523
|
-
const spaceIdx = line.indexOf(" ");
|
|
524
|
-
const hash = line.slice(0, spaceIdx);
|
|
525
|
-
const message = line.slice(spaceIdx + 1);
|
|
526
|
-
return { hash, ...parseConventional(message) };
|
|
527
|
-
});
|
|
542
|
+
commits = parseGitLogOutput(output);
|
|
528
543
|
} catch (err) {
|
|
529
544
|
return { ok: false, error: `Failed to get git log: ${err}` };
|
|
530
545
|
}
|
|
@@ -43,6 +43,22 @@
|
|
|
43
43
|
* @public
|
|
44
44
|
*/
|
|
45
45
|
import type { Plugin } from '@wrongstack/core/types';
|
|
46
|
+
interface SessionRecapConfig {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
/** Prepended to the broadcast `subject` (mailbox reads this in the inbox). */
|
|
49
|
+
subjectPrefix: string;
|
|
50
|
+
/** Number of last transcript events to include in the recap body. */
|
|
51
|
+
includeTranscriptTail: number;
|
|
52
|
+
/** Hard cap on the recap body size (chars). Default 8 KB. */
|
|
53
|
+
maxBodyChars: number;
|
|
54
|
+
/**
|
|
55
|
+
* When true and `api.llm` is wired, a natural-language summary of the
|
|
56
|
+
* session is written by the LLM and prepended to the recap body.
|
|
57
|
+
* Best-effort — a failure leaves the metrics-only recap intact.
|
|
58
|
+
*/
|
|
59
|
+
aiSummary: boolean;
|
|
60
|
+
}
|
|
61
|
+
export declare function readConfig(raw: unknown): SessionRecapConfig;
|
|
46
62
|
declare const plugin: Plugin;
|
|
47
63
|
export default plugin;
|
|
48
64
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/session-recap.js
CHANGED
|
@@ -45,12 +45,16 @@ var DEFAULTS = {
|
|
|
45
45
|
function readConfig(raw) {
|
|
46
46
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
47
47
|
const r = raw;
|
|
48
|
+
const rawPrefix = r["subjectPrefix"] ?? r["subject_prefix"] ?? r["prefix"];
|
|
49
|
+
const rawTail = r["includeTranscriptTail"] ?? r["include_transcript_tail"] ?? r["transcriptTail"] ?? r["transcript_tail"];
|
|
50
|
+
const rawBody = r["maxBodyChars"] ?? r["max_body_chars"] ?? r["maxChars"] ?? r["max_chars"];
|
|
51
|
+
const rawAi = r["aiSummary"] ?? r["ai_summary"] ?? r["useLlm"] ?? r["use_llm"];
|
|
48
52
|
return {
|
|
49
53
|
enabled: r["enabled"] !== false,
|
|
50
|
-
subjectPrefix: typeof
|
|
51
|
-
includeTranscriptTail: typeof
|
|
52
|
-
maxBodyChars: typeof
|
|
53
|
-
aiSummary:
|
|
54
|
+
subjectPrefix: typeof rawPrefix === "string" ? rawPrefix : DEFAULTS.subjectPrefix,
|
|
55
|
+
includeTranscriptTail: typeof rawTail === "number" && rawTail >= 0 ? rawTail : DEFAULTS.includeTranscriptTail,
|
|
56
|
+
maxBodyChars: typeof rawBody === "number" && rawBody > 0 ? rawBody : DEFAULTS.maxBodyChars,
|
|
57
|
+
aiSummary: rawAi === true
|
|
54
58
|
};
|
|
55
59
|
}
|
|
56
60
|
function touchActivity() {
|
|
@@ -223,8 +227,9 @@ var plugin = {
|
|
|
223
227
|
touchActivity();
|
|
224
228
|
const p = payload;
|
|
225
229
|
const model = p?.model ?? "unknown";
|
|
226
|
-
const
|
|
227
|
-
const
|
|
230
|
+
const u = p?.usage;
|
|
231
|
+
const input = typeof u?.["input"] === "number" ? u["input"] : typeof u?.["inputTokens"] === "number" ? u["inputTokens"] : typeof u?.["promptTokens"] === "number" ? u["promptTokens"] : typeof u?.["prompt_tokens"] === "number" ? u["prompt_tokens"] : 0;
|
|
232
|
+
const output = typeof u?.["output"] === "number" ? u["output"] : typeof u?.["outputTokens"] === "number" ? u["outputTokens"] : typeof u?.["completionTokens"] === "number" ? u["completionTokens"] : typeof u?.["completion_tokens"] === "number" ? u["completion_tokens"] : 0;
|
|
228
233
|
bumpModelUsage(model, input, output);
|
|
229
234
|
});
|
|
230
235
|
state.eventUnsubscribers.push(offUsage);
|
|
@@ -261,10 +266,13 @@ var plugin = {
|
|
|
261
266
|
const transcriptPath = api.session?.transcriptPath;
|
|
262
267
|
const tailEvents = await readTranscriptTail(transcriptPath, cfg.includeTranscriptTail);
|
|
263
268
|
const duration = formatDuration(state.startedAt, state.lastActivityAt);
|
|
269
|
+
const rawInput = input ?? {};
|
|
270
|
+
const sessionId = (typeof input.sessionId === "string" ? input.sessionId : void 0) ?? (typeof rawInput["session_id"] === "string" ? rawInput["session_id"] : void 0) ?? (typeof rawInput["id"] === "string" ? rawInput["id"] : void 0) ?? null;
|
|
271
|
+
const cwd = (typeof input.cwd === "string" ? input.cwd : void 0) ?? (typeof rawInput["workingDirectory"] === "string" ? rawInput["workingDirectory"] : void 0) ?? (typeof rawInput["dir"] === "string" ? rawInput["dir"] : void 0) ?? null;
|
|
264
272
|
const recap = {
|
|
265
273
|
session: {
|
|
266
|
-
id:
|
|
267
|
-
cwd
|
|
274
|
+
id: sessionId,
|
|
275
|
+
cwd,
|
|
268
276
|
startedAt: state.startedAt,
|
|
269
277
|
endedAt: state.lastActivityAt,
|
|
270
278
|
duration
|
|
@@ -476,5 +484,6 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
|
|
|
476
484
|
};
|
|
477
485
|
var session_recap_default = plugin;
|
|
478
486
|
export {
|
|
479
|
-
session_recap_default as default
|
|
487
|
+
session_recap_default as default,
|
|
488
|
+
readConfig
|
|
480
489
|
};
|
package/dist/shell-check.js
CHANGED
|
@@ -151,10 +151,16 @@ var plugin = {
|
|
|
151
151
|
type: "object",
|
|
152
152
|
properties: {
|
|
153
153
|
files: {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
description: "Shell script files to check \u2014 a single path string or an array of paths. Mutually exclusive with `directory`. Aliases: `file`, `filePath`, `TargetFile`, `targetFile`, `path`.",
|
|
155
|
+
// execute() normalizes the string form and the alias keys, but
|
|
156
|
+
// schema-validating hosts check this BEFORE execute — declare them.
|
|
157
|
+
anyOf: [{ type: "array", items: { type: "string" } }, { type: "string" }]
|
|
157
158
|
},
|
|
159
|
+
file: { type: "string", description: "Alias for `files` (single path)." },
|
|
160
|
+
filePath: { type: "string", description: "Alias for `files` (single path)." },
|
|
161
|
+
TargetFile: { type: "string", description: "Alias for `files` (single path)." },
|
|
162
|
+
targetFile: { type: "string", description: "Alias for `files` (single path)." },
|
|
163
|
+
path: { type: "string", description: "Alias for `files` (single path)." },
|
|
158
164
|
directory: {
|
|
159
165
|
type: "string",
|
|
160
166
|
default: ".",
|
|
@@ -183,8 +189,17 @@ var plugin = {
|
|
|
183
189
|
mutating: true,
|
|
184
190
|
async execute(input) {
|
|
185
191
|
const inp = input;
|
|
186
|
-
|
|
187
|
-
const
|
|
192
|
+
let files;
|
|
193
|
+
const rawFiles = inp.files ?? input["file"] ?? input["filePath"] ?? input["file_path"] ?? input["TargetFile"] ?? input["targetFile"] ?? input["path"];
|
|
194
|
+
if (rawFiles !== void 0) {
|
|
195
|
+
if (typeof rawFiles === "string" && rawFiles.trim().length > 0) {
|
|
196
|
+
files = [rawFiles.trim()];
|
|
197
|
+
} else if (Array.isArray(rawFiles)) {
|
|
198
|
+
files = rawFiles.filter((f) => typeof f === "string" && f.trim().length > 0);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const rawDirectory = inp.directory ?? input["dir"] ?? input["SearchDirectory"];
|
|
202
|
+
const directory = typeof rawDirectory === "string" && rawDirectory.length > 0 ? rawDirectory : ".";
|
|
188
203
|
const pattern = inp.pattern ?? "";
|
|
189
204
|
const severity = inp.severity ?? "warning";
|
|
190
205
|
state.invocationCount += 1;
|
|
@@ -236,7 +251,13 @@ var plugin = {
|
|
|
236
251
|
issues = await runShellCheck(checkFiles, severity);
|
|
237
252
|
} catch (err) {
|
|
238
253
|
const msg = err instanceof Error ? err.message : String(err);
|
|
239
|
-
return {
|
|
254
|
+
return {
|
|
255
|
+
ok: false,
|
|
256
|
+
error: msg,
|
|
257
|
+
issues: [],
|
|
258
|
+
filesScanned: 0,
|
|
259
|
+
mode: scannedDirectories ? "directory" : "files"
|
|
260
|
+
};
|
|
240
261
|
}
|
|
241
262
|
const byFile = {};
|
|
242
263
|
for (const issue of issues) {
|
package/dist/smart-rename.js
CHANGED
|
@@ -1,7 +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
|
-
var
|
|
4
|
+
var NEW_API_VERSION = "^0.1.10";
|
|
5
5
|
var state = {
|
|
6
6
|
renameCount: 0,
|
|
7
7
|
replacementCount: 0,
|
|
@@ -11,12 +11,17 @@ var DEFAULTS = {
|
|
|
11
11
|
enabled: true,
|
|
12
12
|
extensions: [".ts", ".tsx", ".js", ".jsx"]
|
|
13
13
|
};
|
|
14
|
+
function normalizeExtensions(exts) {
|
|
15
|
+
return exts.map((e) => e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`);
|
|
16
|
+
}
|
|
14
17
|
function readConfig(raw) {
|
|
15
|
-
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
18
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULTS, extensions: normalizeExtensions(DEFAULTS.extensions) };
|
|
16
19
|
const r = raw;
|
|
20
|
+
const rawExts = r["extensions"] ?? r["file_extensions"] ?? r["fileExtensions"];
|
|
21
|
+
const exts = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : DEFAULTS.extensions;
|
|
17
22
|
return {
|
|
18
23
|
enabled: r["enabled"] !== false,
|
|
19
|
-
extensions:
|
|
24
|
+
extensions: normalizeExtensions(exts)
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
27
|
function withinProject(p) {
|
|
@@ -58,7 +63,7 @@ var plugin = {
|
|
|
58
63
|
name: "smart-rename",
|
|
59
64
|
version: "0.1.0",
|
|
60
65
|
description: "Whole-word identifier rename inside a single source file",
|
|
61
|
-
apiVersion:
|
|
66
|
+
apiVersion: NEW_API_VERSION,
|
|
62
67
|
capabilities: { tools: true },
|
|
63
68
|
defaultConfig: { ...DEFAULTS },
|
|
64
69
|
configSchema: {
|
|
@@ -100,9 +105,10 @@ var plugin = {
|
|
|
100
105
|
capabilities: ["fs.write"],
|
|
101
106
|
async execute(input) {
|
|
102
107
|
if (!cfg.enabled) return { ok: false, error: "smart-rename is disabled" };
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
108
|
+
const inp = input ?? {};
|
|
109
|
+
const rawPath = inp["path"] ?? inp["filePath"] ?? inp["file_path"] ?? inp["TargetFile"] ?? inp["targetFile"] ?? inp["file"];
|
|
110
|
+
const oldName = inp["oldName"] ?? inp["old_name"] ?? inp["from"];
|
|
111
|
+
const newName = inp["newName"] ?? inp["new_name"] ?? inp["to"];
|
|
106
112
|
if (!rawPath || typeof rawPath !== "string") {
|
|
107
113
|
return { ok: false, error: "path is required" };
|
|
108
114
|
}
|
|
@@ -136,7 +142,10 @@ var plugin = {
|
|
|
136
142
|
const { preview, replacements } = renameInContent(content, oldName, newName);
|
|
137
143
|
state.renameCount += 1;
|
|
138
144
|
state.replacementCount += replacements;
|
|
139
|
-
|
|
145
|
+
const isDryRun = inp["dryRun"] === true || inp["dry_run"] === true || inp["dry"] === true || inp["previewOnly"] === true;
|
|
146
|
+
const rawApply = inp["apply"] ?? inp["write"] ?? inp["save"] ?? inp["persist"];
|
|
147
|
+
const shouldApply = Boolean(rawApply) && !isDryRun;
|
|
148
|
+
if (shouldApply) {
|
|
140
149
|
try {
|
|
141
150
|
writeFileSync(resolved, preview, "utf-8");
|
|
142
151
|
} catch (err) {
|
|
@@ -149,7 +158,7 @@ var plugin = {
|
|
|
149
158
|
path: relativePath(resolved),
|
|
150
159
|
replacements,
|
|
151
160
|
preview,
|
|
152
|
-
applied:
|
|
161
|
+
applied: shouldApply
|
|
153
162
|
};
|
|
154
163
|
}
|
|
155
164
|
});
|