@wrongstack/plugins 0.291.2 → 0.292.1
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/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +35 -18
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +65 -27
- package/dist/git-autocommit/index.d.ts.map +1 -1
- package/dist/git-autocommit.js +54 -42
- package/dist/index.js +529 -310
- package/dist/notify-hub/index.d.ts +0 -39
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub/webhook-channel.d.ts +56 -0
- package/dist/notify-hub/webhook-channel.d.ts.map +1 -0
- package/dist/notify-hub.js +241 -102
- package/dist/shell-check/index.d.ts.map +1 -1
- package/dist/shell-check.js +60 -36
- package/dist/spec-linker.js +529 -310
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +12 -23
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5033,8 +5033,8 @@ var plugin15 = {
|
|
|
5033
5033
|
var file_watcher_default = plugin15;
|
|
5034
5034
|
|
|
5035
5035
|
// src/format-on-save/index.ts
|
|
5036
|
-
import {
|
|
5037
|
-
import {
|
|
5036
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
5037
|
+
import { access, stat as stat2 } from "node:fs/promises";
|
|
5038
5038
|
var API_VERSION8 = "^0.1.10";
|
|
5039
5039
|
var state14 = {
|
|
5040
5040
|
invocationCount: 0,
|
|
@@ -5093,29 +5093,46 @@ function evictExpired(ttlMs) {
|
|
|
5093
5093
|
if (ts < cutoff) recentlyCovered.delete(path);
|
|
5094
5094
|
}
|
|
5095
5095
|
}
|
|
5096
|
-
function formatFile(filePath, timeoutMs) {
|
|
5096
|
+
async function formatFile(filePath, timeoutMs) {
|
|
5097
5097
|
if (!withinProject(filePath)) return null;
|
|
5098
|
-
|
|
5098
|
+
try {
|
|
5099
|
+
await access(filePath);
|
|
5100
|
+
} catch {
|
|
5101
|
+
return null;
|
|
5102
|
+
}
|
|
5099
5103
|
let bytesBefore;
|
|
5100
5104
|
try {
|
|
5101
|
-
bytesBefore =
|
|
5105
|
+
bytesBefore = (await stat2(filePath)).size;
|
|
5102
5106
|
} catch {
|
|
5103
5107
|
return null;
|
|
5104
5108
|
}
|
|
5105
5109
|
try {
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5110
|
+
await new Promise((resolve28, reject) => {
|
|
5111
|
+
execFile3(
|
|
5112
|
+
"npx",
|
|
5113
|
+
["biome", "format", "--write", filePath],
|
|
5114
|
+
{
|
|
5115
|
+
encoding: "utf-8",
|
|
5116
|
+
timeout: timeoutMs,
|
|
5117
|
+
cwd: process.cwd(),
|
|
5118
|
+
windowsHide: true,
|
|
5119
|
+
maxBuffer: 16 * 1024 * 1024
|
|
5120
|
+
},
|
|
5121
|
+
(err) => {
|
|
5122
|
+
if (err) {
|
|
5123
|
+
const e = err;
|
|
5124
|
+
if (e.killed) return reject(err);
|
|
5125
|
+
}
|
|
5126
|
+
resolve28();
|
|
5127
|
+
}
|
|
5128
|
+
);
|
|
5111
5129
|
});
|
|
5112
|
-
} catch
|
|
5113
|
-
|
|
5114
|
-
if (e.killed) return null;
|
|
5130
|
+
} catch {
|
|
5131
|
+
return null;
|
|
5115
5132
|
}
|
|
5116
5133
|
let bytesAfter;
|
|
5117
5134
|
try {
|
|
5118
|
-
bytesAfter =
|
|
5135
|
+
bytesAfter = (await stat2(filePath)).size;
|
|
5119
5136
|
} catch {
|
|
5120
5137
|
return null;
|
|
5121
5138
|
}
|
|
@@ -5123,11 +5140,22 @@ function formatFile(filePath, timeoutMs) {
|
|
|
5123
5140
|
return { changed: true, bytesBefore, bytesAfter };
|
|
5124
5141
|
}
|
|
5125
5142
|
try {
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5143
|
+
await new Promise((resolve28, reject) => {
|
|
5144
|
+
execFile3(
|
|
5145
|
+
"npx",
|
|
5146
|
+
["biome", "format", filePath],
|
|
5147
|
+
{
|
|
5148
|
+
encoding: "utf-8",
|
|
5149
|
+
timeout: timeoutMs,
|
|
5150
|
+
cwd: process.cwd(),
|
|
5151
|
+
windowsHide: true,
|
|
5152
|
+
maxBuffer: 16 * 1024 * 1024
|
|
5153
|
+
},
|
|
5154
|
+
(err) => {
|
|
5155
|
+
if (err) return reject(err);
|
|
5156
|
+
resolve28();
|
|
5157
|
+
}
|
|
5158
|
+
);
|
|
5131
5159
|
});
|
|
5132
5160
|
return { changed: false, bytesBefore, bytesAfter };
|
|
5133
5161
|
} catch {
|
|
@@ -5168,7 +5196,7 @@ var plugin16 = {
|
|
|
5168
5196
|
}
|
|
5169
5197
|
}
|
|
5170
5198
|
},
|
|
5171
|
-
setup(api) {
|
|
5199
|
+
async setup(api) {
|
|
5172
5200
|
clearRegistrations();
|
|
5173
5201
|
state14.invocationCount = 0;
|
|
5174
5202
|
state14.formattedCount = 0;
|
|
@@ -5180,11 +5208,21 @@ var plugin16 = {
|
|
|
5180
5208
|
const cfg = readConfig12(api.config.extensions?.["format-on-save"]);
|
|
5181
5209
|
let biomeAvailable = false;
|
|
5182
5210
|
try {
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5211
|
+
await new Promise((resolve28, reject) => {
|
|
5212
|
+
execFile3(
|
|
5213
|
+
"npx",
|
|
5214
|
+
["biome", "--version"],
|
|
5215
|
+
{
|
|
5216
|
+
encoding: "utf-8",
|
|
5217
|
+
timeout: 5e3,
|
|
5218
|
+
cwd: process.cwd(),
|
|
5219
|
+
windowsHide: true
|
|
5220
|
+
},
|
|
5221
|
+
(err) => {
|
|
5222
|
+
if (err) reject(err);
|
|
5223
|
+
else resolve28();
|
|
5224
|
+
}
|
|
5225
|
+
);
|
|
5188
5226
|
});
|
|
5189
5227
|
biomeAvailable = true;
|
|
5190
5228
|
api.log.info("format-on-save: biome detected");
|
|
@@ -5192,7 +5230,7 @@ var plugin16 = {
|
|
|
5192
5230
|
biomeAvailable = false;
|
|
5193
5231
|
api.log.warn("format-on-save: biome not found \u2014 hook will be a no-op");
|
|
5194
5232
|
}
|
|
5195
|
-
const hook = (input) => {
|
|
5233
|
+
const hook = async (input) => {
|
|
5196
5234
|
if (!cfg.enabled || !biomeAvailable) return;
|
|
5197
5235
|
if (input.toolResult?.isError) return;
|
|
5198
5236
|
const toolName = input.toolName ?? "";
|
|
@@ -5214,7 +5252,7 @@ var plugin16 = {
|
|
|
5214
5252
|
}
|
|
5215
5253
|
}
|
|
5216
5254
|
state14.invocationCount += 1;
|
|
5217
|
-
const result = formatFile(filePath, cfg.timeoutMs);
|
|
5255
|
+
const result = await formatFile(filePath, cfg.timeoutMs);
|
|
5218
5256
|
if (!result) {
|
|
5219
5257
|
state14.errorCount += 1;
|
|
5220
5258
|
return;
|
|
@@ -5320,56 +5358,68 @@ var plugin16 = {
|
|
|
5320
5358
|
var format_on_save_default = plugin16;
|
|
5321
5359
|
|
|
5322
5360
|
// src/git-autocommit/index.ts
|
|
5323
|
-
import {
|
|
5324
|
-
import { existsSync as
|
|
5361
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
5362
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
5325
5363
|
var API_VERSION9 = "^0.1.10";
|
|
5326
5364
|
var commitCount = { value: 0 };
|
|
5327
5365
|
var lastCommit = { hash: null, at: null };
|
|
5328
5366
|
var llmGenerated = { value: 0 };
|
|
5329
5367
|
var DEFAULT_GIT_TIMEOUT_MS = 3e4;
|
|
5330
5368
|
var GIT_COMMIT_TIMEOUT_MS = 5 * 6e4;
|
|
5331
|
-
function runGit2(args, cwd, timeoutMs = DEFAULT_GIT_TIMEOUT_MS) {
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5369
|
+
async function runGit2(args, cwd, timeoutMs = DEFAULT_GIT_TIMEOUT_MS) {
|
|
5370
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
5371
|
+
execFile4(
|
|
5372
|
+
"git",
|
|
5373
|
+
args,
|
|
5374
|
+
{
|
|
5375
|
+
encoding: "utf-8",
|
|
5376
|
+
cwd,
|
|
5377
|
+
windowsHide: true,
|
|
5378
|
+
timeout: timeoutMs,
|
|
5379
|
+
maxBuffer: 10 * 1024 * 1024
|
|
5380
|
+
},
|
|
5381
|
+
(err, stdout) => {
|
|
5382
|
+
if (err) {
|
|
5383
|
+
const e = err;
|
|
5384
|
+
rejectPromise(
|
|
5385
|
+
new Error(
|
|
5386
|
+
`git command failed: ${e.message ?? e.stderr ?? String(err)}`
|
|
5387
|
+
)
|
|
5388
|
+
);
|
|
5389
|
+
return;
|
|
5390
|
+
}
|
|
5391
|
+
resolvePromise(stdout.trim());
|
|
5392
|
+
}
|
|
5393
|
+
);
|
|
5394
|
+
});
|
|
5345
5395
|
}
|
|
5346
|
-
function getChangedFiles(cwd) {
|
|
5347
|
-
const output = runGit2(["status", "--porcelain"], cwd);
|
|
5396
|
+
async function getChangedFiles(cwd) {
|
|
5397
|
+
const output = await runGit2(["status", "--porcelain"], cwd);
|
|
5348
5398
|
if (!output) return [];
|
|
5349
5399
|
return output.split("\n").filter((l) => l.trim()).map((l) => l.slice(3).trim());
|
|
5350
5400
|
}
|
|
5351
|
-
function getStagedFiles(cwd) {
|
|
5352
|
-
const output = runGit2(["diff", "--cached", "--name-only"], cwd);
|
|
5401
|
+
async function getStagedFiles(cwd) {
|
|
5402
|
+
const output = await runGit2(["diff", "--cached", "--name-only"], cwd);
|
|
5353
5403
|
return output ? output.split("\n").filter(Boolean) : [];
|
|
5354
5404
|
}
|
|
5355
|
-
function stageFiles(files, cwd) {
|
|
5405
|
+
async function stageFiles(files, cwd) {
|
|
5356
5406
|
if (!files || !Array.isArray(files)) return;
|
|
5357
5407
|
const existing = files.filter((f) => {
|
|
5358
5408
|
try {
|
|
5359
|
-
return
|
|
5409
|
+
return existsSync2(f);
|
|
5360
5410
|
} catch {
|
|
5361
5411
|
return false;
|
|
5362
5412
|
}
|
|
5363
5413
|
});
|
|
5364
5414
|
if (existing.length === 0) throw new Error("No files exist to stage");
|
|
5365
|
-
runGit2(["add", ...existing], cwd);
|
|
5415
|
+
await runGit2(["add", ...existing], cwd);
|
|
5366
5416
|
}
|
|
5367
|
-
function commitWithMessage(message, cwd) {
|
|
5368
|
-
return runGit2(["commit", "-m", message], cwd, GIT_COMMIT_TIMEOUT_MS);
|
|
5417
|
+
async function commitWithMessage(message, cwd) {
|
|
5418
|
+
return await runGit2(["commit", "-m", message], cwd, GIT_COMMIT_TIMEOUT_MS);
|
|
5369
5419
|
}
|
|
5370
|
-
function getWorktrees(cwd) {
|
|
5420
|
+
async function getWorktrees(cwd) {
|
|
5371
5421
|
try {
|
|
5372
|
-
const out = runGit2(["worktree", "list", "--porcelain"], cwd);
|
|
5422
|
+
const out = await runGit2(["worktree", "list", "--porcelain"], cwd);
|
|
5373
5423
|
if (!out) return [];
|
|
5374
5424
|
const entries = [];
|
|
5375
5425
|
let current = {};
|
|
@@ -5389,28 +5439,28 @@ function getWorktrees(cwd) {
|
|
|
5389
5439
|
return [];
|
|
5390
5440
|
}
|
|
5391
5441
|
}
|
|
5392
|
-
function simultaneousEditWarning(cwd) {
|
|
5393
|
-
const worktrees = getWorktrees(cwd);
|
|
5442
|
+
async function simultaneousEditWarning(cwd) {
|
|
5443
|
+
const worktrees = await getWorktrees(cwd);
|
|
5394
5444
|
if (worktrees.length > 1) {
|
|
5395
5445
|
const otherBranches = worktrees.filter((wt) => wt.branch).map((wt) => wt.branch.replace("refs/heads/", ""));
|
|
5396
5446
|
return `\u26A0 Simultaneous edits detected: ${worktrees.length} active worktrees (${otherBranches.join(", ")}). Changes from other agents may mix into this commit. Consider using worktree isolation or verifying the diff below before committing.`;
|
|
5397
5447
|
}
|
|
5398
5448
|
return null;
|
|
5399
5449
|
}
|
|
5400
|
-
function getStagedDiff(cwd) {
|
|
5450
|
+
async function getStagedDiff(cwd) {
|
|
5401
5451
|
try {
|
|
5402
|
-
const
|
|
5403
|
-
const diff = runGit2(["diff", "--cached"], cwd);
|
|
5452
|
+
const stat5 = await runGit2(["diff", "--cached", "--stat"], cwd);
|
|
5453
|
+
const diff = await runGit2(["diff", "--cached"], cwd);
|
|
5404
5454
|
const MAX_DIFF = 2e4;
|
|
5405
5455
|
const truncated = diff.length > MAX_DIFF ? diff.slice(0, MAX_DIFF) + "\n\n... (diff truncated)" : diff;
|
|
5406
|
-
return { stat:
|
|
5456
|
+
return { stat: stat5 || "(no stat)", diff: truncated || "(clean)" };
|
|
5407
5457
|
} catch {
|
|
5408
5458
|
return { stat: "(unavailable)", diff: "(unavailable)" };
|
|
5409
5459
|
}
|
|
5410
5460
|
}
|
|
5411
|
-
function externalChangesSinceStage(cwd) {
|
|
5461
|
+
async function externalChangesSinceStage(cwd) {
|
|
5412
5462
|
try {
|
|
5413
|
-
const out = runGit2(["status", "--porcelain"], cwd);
|
|
5463
|
+
const out = await runGit2(["status", "--porcelain"], cwd);
|
|
5414
5464
|
if (!out) return null;
|
|
5415
5465
|
const unstaged = out.split("\n").filter((l) => l.trim()).filter((l) => {
|
|
5416
5466
|
const idx = l[0] ?? " ";
|
|
@@ -5441,14 +5491,14 @@ var VALID_TYPES = [
|
|
|
5441
5491
|
"build",
|
|
5442
5492
|
"revert"
|
|
5443
5493
|
];
|
|
5444
|
-
async function generateCommitFromDiff(api,
|
|
5494
|
+
async function generateCommitFromDiff(api, stat5, diff) {
|
|
5445
5495
|
if (!api.llm) return null;
|
|
5446
5496
|
try {
|
|
5447
5497
|
const result = await api.llm.complete(
|
|
5448
5498
|
`Write a Conventional Commits message for this staged git diff. Respond with ONLY a JSON object of the form {"type": string, "scope": string, "summary": string, "body": string}. type is one of: ${VALID_TYPES.join(", ")}. scope is a short area (empty string if unclear). summary is an imperative, lower-case, <=72-char subject with no trailing period. body is an optional short explanation (empty string if not needed). No prose outside the JSON.
|
|
5449
5499
|
|
|
5450
5500
|
Stat:
|
|
5451
|
-
${
|
|
5501
|
+
${stat5}
|
|
5452
5502
|
|
|
5453
5503
|
Diff:
|
|
5454
5504
|
${diff}`,
|
|
@@ -5585,7 +5635,7 @@ var plugin17 = {
|
|
|
5585
5635
|
}
|
|
5586
5636
|
if (files && files.length > 0) {
|
|
5587
5637
|
try {
|
|
5588
|
-
stageFiles(files);
|
|
5638
|
+
await stageFiles(files);
|
|
5589
5639
|
} catch (err) {
|
|
5590
5640
|
return {
|
|
5591
5641
|
ok: false,
|
|
@@ -5595,20 +5645,20 @@ var plugin17 = {
|
|
|
5595
5645
|
}
|
|
5596
5646
|
let staged = [];
|
|
5597
5647
|
try {
|
|
5598
|
-
staged = getStagedFiles();
|
|
5648
|
+
staged = await getStagedFiles();
|
|
5599
5649
|
} catch {
|
|
5600
5650
|
staged = [];
|
|
5601
5651
|
}
|
|
5602
5652
|
if (staged.length === 0) {
|
|
5603
5653
|
try {
|
|
5604
|
-
const changed = getChangedFiles();
|
|
5654
|
+
const changed = await getChangedFiles();
|
|
5605
5655
|
if (changed.length > 0) {
|
|
5606
5656
|
try {
|
|
5607
|
-
stageFiles(changed);
|
|
5657
|
+
await stageFiles(changed);
|
|
5608
5658
|
} catch {
|
|
5609
5659
|
}
|
|
5610
5660
|
try {
|
|
5611
|
-
staged = getStagedFiles();
|
|
5661
|
+
staged = await getStagedFiles();
|
|
5612
5662
|
} catch {
|
|
5613
5663
|
staged = [];
|
|
5614
5664
|
}
|
|
@@ -5616,10 +5666,10 @@ var plugin17 = {
|
|
|
5616
5666
|
} catch {
|
|
5617
5667
|
}
|
|
5618
5668
|
}
|
|
5619
|
-
const { stat:
|
|
5669
|
+
const { stat: stat5, diff: stagedDiff } = await getStagedDiff();
|
|
5620
5670
|
let generatedByLlm = false;
|
|
5621
5671
|
if (wantGenerate && staged.length > 0) {
|
|
5622
|
-
const g = await generateCommitFromDiff(api,
|
|
5672
|
+
const g = await generateCommitFromDiff(api, stat5, stagedDiff);
|
|
5623
5673
|
if (g) {
|
|
5624
5674
|
type = g.type;
|
|
5625
5675
|
if (g.scope) scope = g.scope;
|
|
@@ -5662,8 +5712,8 @@ var plugin17 = {
|
|
|
5662
5712
|
error: "Nothing staged. Add files with git add or provide files input."
|
|
5663
5713
|
};
|
|
5664
5714
|
}
|
|
5665
|
-
const worktreeWarn = simultaneousEditWarning();
|
|
5666
|
-
const externalChanges = externalChangesSinceStage();
|
|
5715
|
+
const worktreeWarn = await simultaneousEditWarning();
|
|
5716
|
+
const externalChanges = await externalChangesSinceStage();
|
|
5667
5717
|
let externalWarning = null;
|
|
5668
5718
|
if (externalChanges && externalChanges.length > 0) {
|
|
5669
5719
|
const preview = externalChanges.slice(0, 10).join(", ");
|
|
@@ -5680,7 +5730,7 @@ var plugin17 = {
|
|
|
5680
5730
|
stagedDiff: `
|
|
5681
5731
|
## Staged changes (dry run)
|
|
5682
5732
|
|
|
5683
|
-
${
|
|
5733
|
+
${stat5}
|
|
5684
5734
|
|
|
5685
5735
|
\`\`\`diff
|
|
5686
5736
|
${stagedDiff}
|
|
@@ -5688,15 +5738,15 @@ ${stagedDiff}
|
|
|
5688
5738
|
};
|
|
5689
5739
|
}
|
|
5690
5740
|
let preCommitDiff = stagedDiff;
|
|
5691
|
-
let preCommitStat =
|
|
5741
|
+
let preCommitStat = stat5;
|
|
5692
5742
|
if (staged.length === 0) {
|
|
5693
|
-
const fresh = getStagedDiff();
|
|
5743
|
+
const fresh = await getStagedDiff();
|
|
5694
5744
|
preCommitDiff = fresh.diff;
|
|
5695
5745
|
preCommitStat = fresh.stat;
|
|
5696
5746
|
}
|
|
5697
5747
|
let hash = "";
|
|
5698
5748
|
try {
|
|
5699
|
-
hash = commitWithMessage(msg);
|
|
5749
|
+
hash = await commitWithMessage(msg);
|
|
5700
5750
|
} catch (err) {
|
|
5701
5751
|
return {
|
|
5702
5752
|
ok: false,
|
|
@@ -5781,7 +5831,7 @@ var git_autocommit_default = plugin17;
|
|
|
5781
5831
|
|
|
5782
5832
|
// src/import-organizer/index.ts
|
|
5783
5833
|
import { spawn } from "node:child_process";
|
|
5784
|
-
import { existsSync as
|
|
5834
|
+
import { existsSync as existsSync3, statSync as statSync4 } from "node:fs";
|
|
5785
5835
|
import { basename as basename2, isAbsolute as isAbsolute7 } from "node:path";
|
|
5786
5836
|
var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
5787
5837
|
"npx",
|
|
@@ -5880,10 +5930,10 @@ function runCommand(command, args, timeoutMs, cwd) {
|
|
|
5880
5930
|
}
|
|
5881
5931
|
async function organizeImports(filePath, cfg, cwd) {
|
|
5882
5932
|
if (!withinProject(filePath)) return null;
|
|
5883
|
-
if (!
|
|
5933
|
+
if (!existsSync3(filePath)) return null;
|
|
5884
5934
|
let bytesBefore;
|
|
5885
5935
|
try {
|
|
5886
|
-
bytesBefore =
|
|
5936
|
+
bytesBefore = statSync4(filePath).size;
|
|
5887
5937
|
} catch {
|
|
5888
5938
|
return null;
|
|
5889
5939
|
}
|
|
@@ -5904,7 +5954,7 @@ async function organizeImports(filePath, cfg, cwd) {
|
|
|
5904
5954
|
if (result.code === 127) return null;
|
|
5905
5955
|
let bytesAfter;
|
|
5906
5956
|
try {
|
|
5907
|
-
bytesAfter =
|
|
5957
|
+
bytesAfter = statSync4(filePath).size;
|
|
5908
5958
|
} catch {
|
|
5909
5959
|
return null;
|
|
5910
5960
|
}
|
|
@@ -6629,7 +6679,7 @@ var plugin20 = {
|
|
|
6629
6679
|
var knowledge_graph_default = plugin20;
|
|
6630
6680
|
|
|
6631
6681
|
// src/lint-gate/index.ts
|
|
6632
|
-
import { execFile as
|
|
6682
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
6633
6683
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
6634
6684
|
import { mkdtemp, readFile as readFile2, rm, writeFile } from "node:fs/promises";
|
|
6635
6685
|
import { createRequire } from "node:module";
|
|
@@ -6699,7 +6749,7 @@ function resolveLocalLinter(name, cwd) {
|
|
|
6699
6749
|
function runCommand2(command, args, timeoutMs, cwd, signal) {
|
|
6700
6750
|
return new Promise((resolveResult) => {
|
|
6701
6751
|
try {
|
|
6702
|
-
|
|
6752
|
+
execFile5(
|
|
6703
6753
|
command,
|
|
6704
6754
|
args,
|
|
6705
6755
|
{
|
|
@@ -7342,7 +7392,7 @@ var plugin22 = {
|
|
|
7342
7392
|
var llm_cache_default = plugin22;
|
|
7343
7393
|
|
|
7344
7394
|
// src/loop-breaker/index.ts
|
|
7345
|
-
import { execFile as
|
|
7395
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
7346
7396
|
var state20 = {
|
|
7347
7397
|
lastFingerprint: null,
|
|
7348
7398
|
streak: 0,
|
|
@@ -7439,7 +7489,7 @@ function hashString2(value) {
|
|
|
7439
7489
|
async function gitDiffFingerprint(cwd, signal) {
|
|
7440
7490
|
try {
|
|
7441
7491
|
const diff = await new Promise((resolve28, reject) => {
|
|
7442
|
-
|
|
7492
|
+
execFile6(
|
|
7443
7493
|
"git",
|
|
7444
7494
|
["diff", "--no-ext-diff", "--"],
|
|
7445
7495
|
{
|
|
@@ -8007,15 +8057,134 @@ var plugin24 = {
|
|
|
8007
8057
|
var model_router_default = plugin24;
|
|
8008
8058
|
|
|
8009
8059
|
// src/notify-hub/index.ts
|
|
8060
|
+
import { lookup } from "node:dns/promises";
|
|
8061
|
+
|
|
8062
|
+
// src/notify-hub/webhook-channel.ts
|
|
8063
|
+
function freshCircuit() {
|
|
8064
|
+
return { open: false, consecutiveFailures: 0 };
|
|
8065
|
+
}
|
|
8066
|
+
var WebhookNotificationChannel = class {
|
|
8067
|
+
name = "webhook";
|
|
8068
|
+
type = "webhook";
|
|
8069
|
+
#url;
|
|
8070
|
+
#headers;
|
|
8071
|
+
#timeoutMs;
|
|
8072
|
+
#maxFailures;
|
|
8073
|
+
#circuit;
|
|
8074
|
+
/** Total deliveries attempted (across all resets). */
|
|
8075
|
+
#totalAttempted = 0;
|
|
8076
|
+
/** Total successful deliveries. */
|
|
8077
|
+
#totalDelivered = 0;
|
|
8078
|
+
/** Total failed deliveries. */
|
|
8079
|
+
#totalFailed = 0;
|
|
8080
|
+
/** Total suppressed by circuit breaker. */
|
|
8081
|
+
#totalSuppressed = 0;
|
|
8082
|
+
constructor(opts) {
|
|
8083
|
+
this.#url = opts.webhookUrl;
|
|
8084
|
+
this.#headers = opts.headers ?? {};
|
|
8085
|
+
this.#timeoutMs = opts.timeoutMs ?? 5e3;
|
|
8086
|
+
this.#maxFailures = opts.maxConsecutiveFailures ?? 5;
|
|
8087
|
+
this.#circuit = freshCircuit();
|
|
8088
|
+
}
|
|
8089
|
+
// -----------------------------------------------------------------------
|
|
8090
|
+
// NotificationChannel
|
|
8091
|
+
// -----------------------------------------------------------------------
|
|
8092
|
+
async deliver(msg) {
|
|
8093
|
+
const deliveredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8094
|
+
if (this.#circuit.open && this.#maxFailures > 0) {
|
|
8095
|
+
this.#totalSuppressed += 1;
|
|
8096
|
+
return {
|
|
8097
|
+
ok: false,
|
|
8098
|
+
channel: this.name,
|
|
8099
|
+
error: `circuit open after ${this.#circuit.consecutiveFailures} consecutive failures`,
|
|
8100
|
+
deliveredAt
|
|
8101
|
+
};
|
|
8102
|
+
}
|
|
8103
|
+
this.#totalAttempted += 1;
|
|
8104
|
+
const body = JSON.stringify({
|
|
8105
|
+
source: "wrongstack/notify-hub",
|
|
8106
|
+
event: msg.source,
|
|
8107
|
+
ts: deliveredAt,
|
|
8108
|
+
title: msg.title,
|
|
8109
|
+
message: msg.body,
|
|
8110
|
+
level: msg.level,
|
|
8111
|
+
...msg.metadata ?? {}
|
|
8112
|
+
});
|
|
8113
|
+
try {
|
|
8114
|
+
const controller = new AbortController();
|
|
8115
|
+
const timer = setTimeout(() => controller.abort(), this.#timeoutMs);
|
|
8116
|
+
try {
|
|
8117
|
+
const res = await fetch(this.#url, {
|
|
8118
|
+
method: "POST",
|
|
8119
|
+
headers: { "content-type": "application/json", ...this.#headers },
|
|
8120
|
+
body,
|
|
8121
|
+
signal: controller.signal
|
|
8122
|
+
});
|
|
8123
|
+
if (!res.ok) throw new Error(`webhook responded ${res.status}`);
|
|
8124
|
+
} finally {
|
|
8125
|
+
clearTimeout(timer);
|
|
8126
|
+
}
|
|
8127
|
+
this.#totalDelivered += 1;
|
|
8128
|
+
this.#circuit.consecutiveFailures = 0;
|
|
8129
|
+
this.#circuit.open = false;
|
|
8130
|
+
return { ok: true, channel: this.name, deliveredAt };
|
|
8131
|
+
} catch (err) {
|
|
8132
|
+
this.#totalFailed += 1;
|
|
8133
|
+
this.#circuit.consecutiveFailures += 1;
|
|
8134
|
+
if (this.#maxFailures > 0 && this.#circuit.consecutiveFailures >= this.#maxFailures) {
|
|
8135
|
+
this.#circuit.open = true;
|
|
8136
|
+
}
|
|
8137
|
+
return {
|
|
8138
|
+
ok: false,
|
|
8139
|
+
channel: this.name,
|
|
8140
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8141
|
+
deliveredAt
|
|
8142
|
+
};
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
async ping() {
|
|
8146
|
+
if (!this.#url) {
|
|
8147
|
+
return { ok: false, error: "no webhookUrl configured" };
|
|
8148
|
+
}
|
|
8149
|
+
if (this.#circuit.open) {
|
|
8150
|
+
return {
|
|
8151
|
+
ok: false,
|
|
8152
|
+
error: `circuit open after ${this.#circuit.consecutiveFailures} consecutive failures`
|
|
8153
|
+
};
|
|
8154
|
+
}
|
|
8155
|
+
return { ok: true };
|
|
8156
|
+
}
|
|
8157
|
+
// -----------------------------------------------------------------------
|
|
8158
|
+
// Diagnostics (not part of NotificationChannel)
|
|
8159
|
+
// -----------------------------------------------------------------------
|
|
8160
|
+
/** Reset the circuit breaker (e.g. after config update). */
|
|
8161
|
+
resetCircuit() {
|
|
8162
|
+
this.#circuit.open = false;
|
|
8163
|
+
this.#circuit.consecutiveFailures = 0;
|
|
8164
|
+
}
|
|
8165
|
+
/** Current circuit breaker state. */
|
|
8166
|
+
circuitStatus() {
|
|
8167
|
+
return { open: this.#circuit.open, consecutiveFailures: this.#circuit.consecutiveFailures };
|
|
8168
|
+
}
|
|
8169
|
+
/** Lifetime delivery counters (never reset). */
|
|
8170
|
+
counters() {
|
|
8171
|
+
return {
|
|
8172
|
+
attempted: this.#totalAttempted,
|
|
8173
|
+
delivered: this.#totalDelivered,
|
|
8174
|
+
failed: this.#totalFailed,
|
|
8175
|
+
suppressed: this.#totalSuppressed
|
|
8176
|
+
};
|
|
8177
|
+
}
|
|
8178
|
+
};
|
|
8179
|
+
|
|
8180
|
+
// src/notify-hub/index.ts
|
|
8181
|
+
var _pluginLog = null;
|
|
8010
8182
|
var state22 = {
|
|
8011
|
-
|
|
8012
|
-
failed: 0,
|
|
8013
|
-
suppressed: 0,
|
|
8014
|
-
consecutiveFailures: 0,
|
|
8015
|
-
circuitOpen: false,
|
|
8183
|
+
channel: null,
|
|
8016
8184
|
lastDelivery: null,
|
|
8017
8185
|
stopHookUnregister: null,
|
|
8018
|
-
eventUnsubscribers: []
|
|
8186
|
+
eventUnsubscribers: [],
|
|
8187
|
+
circuitWarned: false
|
|
8019
8188
|
};
|
|
8020
8189
|
var KNOWN_EVENTS = ["session.stop", "tool.error", "budget.threshold"];
|
|
8021
8190
|
var DEFAULTS19 = {
|
|
@@ -8038,6 +8207,21 @@ function isBlockedHostname(hostname) {
|
|
|
8038
8207
|
const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
8039
8208
|
return h === "localhost" || h.endsWith(".localhost") || h === "::1" || h === "0:0:0:0:0:0:0:1" || h.startsWith("fc") || h.startsWith("fd") || h.startsWith("fe80:") || isPrivateIPv4(h);
|
|
8040
8209
|
}
|
|
8210
|
+
async function hasPrivateResolvedIP(hostname) {
|
|
8211
|
+
try {
|
|
8212
|
+
const entries = await lookup(hostname, { all: true, verbatim: true });
|
|
8213
|
+
for (const { address } of entries) {
|
|
8214
|
+
if (isPrivateIPv4(address)) return true;
|
|
8215
|
+
const lower = address.toLowerCase();
|
|
8216
|
+
if (lower === "::1" || lower === "0:0:0:0:0:0:0:1" || lower.startsWith("fc") || lower.startsWith("fd") || lower.startsWith("fe80:")) {
|
|
8217
|
+
return true;
|
|
8218
|
+
}
|
|
8219
|
+
}
|
|
8220
|
+
return false;
|
|
8221
|
+
} catch {
|
|
8222
|
+
return false;
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8041
8225
|
function normalizeWebhookUrl(raw) {
|
|
8042
8226
|
if (typeof raw !== "string" || raw.trim().length === 0) return "";
|
|
8043
8227
|
try {
|
|
@@ -8069,49 +8253,37 @@ function readConfig20(raw) {
|
|
|
8069
8253
|
maxConsecutiveFailures: typeof r["maxConsecutiveFailures"] === "number" && r["maxConsecutiveFailures"] >= 1 ? r["maxConsecutiveFailures"] : DEFAULTS19.maxConsecutiveFailures
|
|
8070
8254
|
};
|
|
8071
8255
|
}
|
|
8072
|
-
async function deliver(
|
|
8073
|
-
|
|
8074
|
-
if (
|
|
8075
|
-
state22.suppressed += 1;
|
|
8256
|
+
async function deliver(event, payload) {
|
|
8257
|
+
const ch = state22.channel;
|
|
8258
|
+
if (!ch) {
|
|
8076
8259
|
return false;
|
|
8077
8260
|
}
|
|
8078
|
-
const
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8261
|
+
const result = await deliverViaChannel(ch, event, {
|
|
8262
|
+
title: typeof payload.title === "string" ? payload.title : event,
|
|
8263
|
+
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : JSON.stringify(payload),
|
|
8264
|
+
level: event === "tool.error" || event === "budget.threshold" ? "warning" : "info",
|
|
8265
|
+
source: event,
|
|
8266
|
+
metadata: payload
|
|
8083
8267
|
});
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
headers: { "content-type": "application/json", ...cfg.headers },
|
|
8091
|
-
body,
|
|
8092
|
-
signal: controller.signal
|
|
8093
|
-
});
|
|
8094
|
-
if (!res.ok) throw new Error(`webhook responded ${res.status}`);
|
|
8095
|
-
} finally {
|
|
8096
|
-
clearTimeout(timer);
|
|
8097
|
-
}
|
|
8098
|
-
state22.sent += 1;
|
|
8099
|
-
state22.consecutiveFailures = 0;
|
|
8268
|
+
return result.ok;
|
|
8269
|
+
}
|
|
8270
|
+
async function deliverViaChannel(ch, event, msg) {
|
|
8271
|
+
const result = await ch.deliver(msg);
|
|
8272
|
+
if (result.ok) {
|
|
8273
|
+
state22.circuitWarned = false;
|
|
8100
8274
|
state22.lastDelivery = { event, ok: true, when: (/* @__PURE__ */ new Date()).toISOString() };
|
|
8101
|
-
|
|
8102
|
-
} catch (err) {
|
|
8103
|
-
state22.failed += 1;
|
|
8104
|
-
state22.consecutiveFailures += 1;
|
|
8275
|
+
} else {
|
|
8105
8276
|
state22.lastDelivery = { event, ok: false, when: (/* @__PURE__ */ new Date()).toISOString() };
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
{
|
|
8277
|
+
const cs = ch.circuitStatus();
|
|
8278
|
+
if (cs.open && !state22.circuitWarned) {
|
|
8279
|
+
state22.circuitWarned = true;
|
|
8280
|
+
_pluginLog?.warn(
|
|
8281
|
+
`notify-hub: ${cs.consecutiveFailures} consecutive delivery failures \u2014 circuit opened, further notifications suppressed`,
|
|
8282
|
+
{ consecutiveFailures: cs.consecutiveFailures, event }
|
|
8111
8283
|
);
|
|
8112
8284
|
}
|
|
8113
|
-
return false;
|
|
8114
8285
|
}
|
|
8286
|
+
return result;
|
|
8115
8287
|
}
|
|
8116
8288
|
function truncateText(s, max) {
|
|
8117
8289
|
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
@@ -8158,12 +8330,10 @@ var plugin25 = {
|
|
|
8158
8330
|
}
|
|
8159
8331
|
}
|
|
8160
8332
|
},
|
|
8161
|
-
setup(api) {
|
|
8162
|
-
|
|
8163
|
-
state22.
|
|
8164
|
-
state22.
|
|
8165
|
-
state22.consecutiveFailures = 0;
|
|
8166
|
-
state22.circuitOpen = false;
|
|
8333
|
+
async setup(api) {
|
|
8334
|
+
_pluginLog = api.log;
|
|
8335
|
+
state22.circuitWarned = false;
|
|
8336
|
+
state22.channel = null;
|
|
8167
8337
|
state22.lastDelivery = null;
|
|
8168
8338
|
if (state22.stopHookUnregister) {
|
|
8169
8339
|
try {
|
|
@@ -8180,15 +8350,35 @@ var plugin25 = {
|
|
|
8180
8350
|
}
|
|
8181
8351
|
state22.eventUnsubscribers = [];
|
|
8182
8352
|
const cfg = readConfig20(api.config.extensions?.["notify-hub"]);
|
|
8183
|
-
|
|
8353
|
+
let active = cfg.enabled && cfg.webhookUrl.length > 0;
|
|
8354
|
+
if (active) {
|
|
8355
|
+
try {
|
|
8356
|
+
const url = new URL(cfg.webhookUrl);
|
|
8357
|
+
const hostnameBlocked = await hasPrivateResolvedIP(url.hostname);
|
|
8358
|
+
if (hostnameBlocked) {
|
|
8359
|
+
api.log.warn(
|
|
8360
|
+
`notify-hub: webhook URL resolves to a private/local IP (${url.hostname}) \u2014 disabling plugin`
|
|
8361
|
+
);
|
|
8362
|
+
active = false;
|
|
8363
|
+
}
|
|
8364
|
+
} catch {
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
if (active) {
|
|
8368
|
+
state22.channel = new WebhookNotificationChannel({
|
|
8369
|
+
webhookUrl: cfg.webhookUrl,
|
|
8370
|
+
headers: cfg.headers,
|
|
8371
|
+
timeoutMs: cfg.timeoutMs,
|
|
8372
|
+
maxConsecutiveFailures: cfg.maxConsecutiveFailures
|
|
8373
|
+
});
|
|
8374
|
+
api.notifier?.registerChannel(state22.channel);
|
|
8375
|
+
}
|
|
8184
8376
|
if (active && cfg.events.includes("session.stop")) {
|
|
8185
8377
|
const stopHook = (input) => {
|
|
8186
|
-
void deliver(
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
api.log
|
|
8191
|
-
);
|
|
8378
|
+
void deliver("session.stop", {
|
|
8379
|
+
sessionId: input.sessionId ?? null,
|
|
8380
|
+
cwd: input.cwd ?? null
|
|
8381
|
+
});
|
|
8192
8382
|
};
|
|
8193
8383
|
state22.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
|
|
8194
8384
|
}
|
|
@@ -8196,26 +8386,21 @@ var plugin25 = {
|
|
|
8196
8386
|
const off = api.onPattern("tool.*", (eventName, payload) => {
|
|
8197
8387
|
if (!/error|failed/.test(eventName)) return;
|
|
8198
8388
|
const p = payload;
|
|
8199
|
-
void deliver(
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
500
|
|
8208
|
-
)
|
|
8209
|
-
},
|
|
8210
|
-
api.log
|
|
8211
|
-
);
|
|
8389
|
+
void deliver("tool.error", {
|
|
8390
|
+
tool: p?.tool ?? p?.name ?? "unknown",
|
|
8391
|
+
busEvent: eventName,
|
|
8392
|
+
error: truncateText(
|
|
8393
|
+
p?.error instanceof Error ? p.error.message : String(p?.error ?? ""),
|
|
8394
|
+
500
|
|
8395
|
+
)
|
|
8396
|
+
});
|
|
8212
8397
|
});
|
|
8213
8398
|
state22.eventUnsubscribers.push(off);
|
|
8214
8399
|
}
|
|
8215
8400
|
if (active && cfg.events.includes("budget.threshold")) {
|
|
8216
8401
|
const off = api.onPattern("budget.*", (eventName, payload) => {
|
|
8217
8402
|
if (!eventName.includes("threshold")) return;
|
|
8218
|
-
void deliver(
|
|
8403
|
+
void deliver("budget.threshold", { busEvent: eventName, detail: payload });
|
|
8219
8404
|
});
|
|
8220
8405
|
state22.eventUnsubscribers.push(off);
|
|
8221
8406
|
}
|
|
@@ -8240,26 +8425,23 @@ var plugin25 = {
|
|
|
8240
8425
|
mutating: true,
|
|
8241
8426
|
async execute(input) {
|
|
8242
8427
|
if (!cfg.enabled) return { ok: false, error: "notify-hub is disabled" };
|
|
8243
|
-
|
|
8428
|
+
const ch = state22.channel;
|
|
8429
|
+
if (!ch) {
|
|
8244
8430
|
return {
|
|
8245
8431
|
ok: false,
|
|
8246
8432
|
error: 'no webhookUrl configured \u2014 set config.extensions["notify-hub"].webhookUrl to enable deliveries'
|
|
8247
8433
|
};
|
|
8248
8434
|
}
|
|
8249
|
-
const
|
|
8250
|
-
|
|
8251
|
-
"
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
level: input.level === "warning" || input.level === "critical" ? input.level : "info"
|
|
8256
|
-
},
|
|
8257
|
-
api.log
|
|
8258
|
-
);
|
|
8435
|
+
const result = await deliverViaChannel(ch, "manual", {
|
|
8436
|
+
title: truncateText(String(input.title ?? "WrongStack notification"), 200),
|
|
8437
|
+
body: truncateText(String(input.message ?? ""), 2e3),
|
|
8438
|
+
level: input.level === "warning" || input.level === "critical" ? input.level : "info",
|
|
8439
|
+
source: "manual"
|
|
8440
|
+
});
|
|
8259
8441
|
return {
|
|
8260
|
-
ok:
|
|
8261
|
-
circuitOpen:
|
|
8262
|
-
...
|
|
8442
|
+
ok: result.ok,
|
|
8443
|
+
circuitOpen: ch.circuitStatus().open,
|
|
8444
|
+
...result.ok ? {} : { error: result.error ?? "delivery failed" }
|
|
8263
8445
|
};
|
|
8264
8446
|
}
|
|
8265
8447
|
});
|
|
@@ -8271,18 +8453,26 @@ var plugin25 = {
|
|
|
8271
8453
|
category: "Diagnostics",
|
|
8272
8454
|
mutating: false,
|
|
8273
8455
|
async execute() {
|
|
8456
|
+
const ch = state22.channel;
|
|
8457
|
+
const counters = ch?.counters() ?? {
|
|
8458
|
+
attempted: 0,
|
|
8459
|
+
delivered: 0,
|
|
8460
|
+
failed: 0,
|
|
8461
|
+
suppressed: 0
|
|
8462
|
+
};
|
|
8274
8463
|
return {
|
|
8275
8464
|
ok: true,
|
|
8276
8465
|
enabled: cfg.enabled,
|
|
8277
8466
|
webhookConfigured: cfg.webhookUrl.length > 0,
|
|
8278
8467
|
events: cfg.events,
|
|
8279
8468
|
timeoutMs: cfg.timeoutMs,
|
|
8280
|
-
circuitOpen:
|
|
8469
|
+
circuitOpen: ch?.circuitStatus().open ?? false,
|
|
8281
8470
|
counters: {
|
|
8282
|
-
sent:
|
|
8283
|
-
failed:
|
|
8284
|
-
suppressed:
|
|
8285
|
-
consecutiveFailures:
|
|
8471
|
+
sent: counters.delivered,
|
|
8472
|
+
failed: counters.failed,
|
|
8473
|
+
suppressed: counters.suppressed,
|
|
8474
|
+
consecutiveFailures: ch?.circuitStatus().consecutiveFailures ?? 0,
|
|
8475
|
+
totalAttempted: counters.attempted
|
|
8286
8476
|
},
|
|
8287
8477
|
lastDelivery: state22.lastDelivery
|
|
8288
8478
|
};
|
|
@@ -8296,6 +8486,8 @@ var plugin25 = {
|
|
|
8296
8486
|
});
|
|
8297
8487
|
},
|
|
8298
8488
|
teardown(api) {
|
|
8489
|
+
_pluginLog = null;
|
|
8490
|
+
state22.circuitWarned = false;
|
|
8299
8491
|
if (state22.stopHookUnregister) {
|
|
8300
8492
|
try {
|
|
8301
8493
|
state22.stopHookUnregister();
|
|
@@ -8310,25 +8502,22 @@ var plugin25 = {
|
|
|
8310
8502
|
}
|
|
8311
8503
|
}
|
|
8312
8504
|
state22.eventUnsubscribers = [];
|
|
8313
|
-
const
|
|
8314
|
-
state22.
|
|
8315
|
-
state22.failed = 0;
|
|
8316
|
-
state22.suppressed = 0;
|
|
8317
|
-
state22.consecutiveFailures = 0;
|
|
8318
|
-
state22.circuitOpen = false;
|
|
8505
|
+
const channelCounters = state22.channel?.counters();
|
|
8506
|
+
state22.channel = null;
|
|
8319
8507
|
state22.lastDelivery = null;
|
|
8320
|
-
api.log.info("notify-hub: teardown complete", {
|
|
8508
|
+
api.log.info("notify-hub: teardown complete", { channelCounters });
|
|
8321
8509
|
},
|
|
8322
8510
|
async health() {
|
|
8511
|
+
const ch = state22.channel;
|
|
8512
|
+
const cs = ch?.circuitStatus();
|
|
8513
|
+
const channelCounters = ch?.counters();
|
|
8514
|
+
const sent = channelCounters?.delivered ?? 0;
|
|
8515
|
+
const failed = channelCounters?.failed ?? 0;
|
|
8516
|
+
const suppressed = channelCounters?.suppressed ?? 0;
|
|
8323
8517
|
return {
|
|
8324
|
-
ok: !
|
|
8325
|
-
message:
|
|
8326
|
-
counters: {
|
|
8327
|
-
sent: state22.sent,
|
|
8328
|
-
failed: state22.failed,
|
|
8329
|
-
suppressed: state22.suppressed,
|
|
8330
|
-
consecutiveFailures: state22.consecutiveFailures
|
|
8331
|
-
}
|
|
8518
|
+
ok: !cs?.open,
|
|
8519
|
+
message: cs?.open ? `notify-hub: circuit OPEN after ${cs.consecutiveFailures} consecutive failures \u2014 deliveries suppressed` : ch ? `notify-hub: ${sent} sent, ${failed} failed, ${suppressed} suppressed` : `notify-hub: idle \u2014 no webhook channel configured`,
|
|
8520
|
+
counters: { sent, failed, suppressed, consecutiveFailures: cs?.consecutiveFailures ?? 0 }
|
|
8332
8521
|
};
|
|
8333
8522
|
}
|
|
8334
8523
|
};
|
|
@@ -8859,7 +9048,7 @@ function readConfig23(raw) {
|
|
|
8859
9048
|
var plugin_stack_observer_default = PLUGIN;
|
|
8860
9049
|
|
|
8861
9050
|
// src/pr-drafter/index.ts
|
|
8862
|
-
import { execFileSync as
|
|
9051
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8863
9052
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8864
9053
|
import { dirname as dirname5, isAbsolute as isAbsolute10, relative as relative9, resolve as resolve9 } from "node:path";
|
|
8865
9054
|
var API_VERSION13 = "^0.1.10";
|
|
@@ -8908,7 +9097,7 @@ function resolveProjectPath6(rawPath, cwd = process.cwd()) {
|
|
|
8908
9097
|
}
|
|
8909
9098
|
function gitBranch() {
|
|
8910
9099
|
try {
|
|
8911
|
-
const out =
|
|
9100
|
+
const out = execFileSync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
8912
9101
|
encoding: "utf-8",
|
|
8913
9102
|
cwd: process.cwd(),
|
|
8914
9103
|
stdio: ["pipe", "pipe", "ignore"],
|
|
@@ -8921,7 +9110,7 @@ function gitBranch() {
|
|
|
8921
9110
|
}
|
|
8922
9111
|
function gitDiff() {
|
|
8923
9112
|
try {
|
|
8924
|
-
return
|
|
9113
|
+
return execFileSync2("git", ["diff", "--stat"], {
|
|
8925
9114
|
encoding: "utf-8",
|
|
8926
9115
|
cwd: process.cwd(),
|
|
8927
9116
|
stdio: ["pipe", "pipe", "ignore"],
|
|
@@ -9921,8 +10110,8 @@ var secret_scanner_default = plugin30;
|
|
|
9921
10110
|
// src/semver-bump/index.ts
|
|
9922
10111
|
import { expectDefined as expectDefined2 } from "@wrongstack/core";
|
|
9923
10112
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
9924
|
-
import { execFileSync as
|
|
9925
|
-
import { existsSync as
|
|
10113
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
10114
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
9926
10115
|
import { isAbsolute as isAbsolute11, join as join3, relative as relative10, resolve as resolve10 } from "node:path";
|
|
9927
10116
|
var API_VERSION14 = "^0.1.10";
|
|
9928
10117
|
function resolveProjectRoot(rawCwd, root = process.cwd()) {
|
|
@@ -9943,7 +10132,7 @@ var state29 = {
|
|
|
9943
10132
|
};
|
|
9944
10133
|
function runGit3(args, cwd) {
|
|
9945
10134
|
try {
|
|
9946
|
-
return
|
|
10135
|
+
return execFileSync3("git", args, {
|
|
9947
10136
|
encoding: "utf-8",
|
|
9948
10137
|
cwd,
|
|
9949
10138
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -9958,7 +10147,7 @@ function runGit3(args, cwd) {
|
|
|
9958
10147
|
}
|
|
9959
10148
|
function getPackageJson(cwd) {
|
|
9960
10149
|
const path = cwd ? `${cwd}/package.json` : "package.json";
|
|
9961
|
-
if (!
|
|
10150
|
+
if (!existsSync4(path)) return null;
|
|
9962
10151
|
try {
|
|
9963
10152
|
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
9964
10153
|
} catch {
|
|
@@ -9968,14 +10157,14 @@ function getPackageJson(cwd) {
|
|
|
9968
10157
|
function collectManifests(root) {
|
|
9969
10158
|
const paths = [];
|
|
9970
10159
|
const rootPkg = join3(root, "package.json");
|
|
9971
|
-
if (
|
|
10160
|
+
if (existsSync4(rootPkg)) paths.push(rootPkg);
|
|
9972
10161
|
for (const group of ["packages", "apps"]) {
|
|
9973
10162
|
const groupDir = join3(root, group);
|
|
9974
|
-
if (!
|
|
10163
|
+
if (!existsSync4(groupDir)) continue;
|
|
9975
10164
|
for (const entry of readdirSync2(groupDir, { withFileTypes: true })) {
|
|
9976
10165
|
if (!entry.isDirectory()) continue;
|
|
9977
10166
|
const candidate = join3(groupDir, entry.name, "package.json");
|
|
9978
|
-
if (
|
|
10167
|
+
if (existsSync4(candidate)) paths.push(candidate);
|
|
9979
10168
|
}
|
|
9980
10169
|
}
|
|
9981
10170
|
return paths;
|
|
@@ -10167,9 +10356,9 @@ var plugin31 = {
|
|
|
10167
10356
|
const root = cwd ?? process.cwd();
|
|
10168
10357
|
const bumpScript = join3(root, "scripts", "bump-version.mjs");
|
|
10169
10358
|
const changed = collectManifests(root);
|
|
10170
|
-
if (
|
|
10359
|
+
if (existsSync4(bumpScript)) {
|
|
10171
10360
|
try {
|
|
10172
|
-
|
|
10361
|
+
execFileSync3(process.execPath, [bumpScript, "set", newVersion], {
|
|
10173
10362
|
cwd: root,
|
|
10174
10363
|
stdio: ["pipe", "pipe", "pipe"],
|
|
10175
10364
|
timeout: 3e4,
|
|
@@ -10181,7 +10370,7 @@ var plugin31 = {
|
|
|
10181
10370
|
}
|
|
10182
10371
|
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
10183
10372
|
const p = join3(root, "website", rel);
|
|
10184
|
-
if (
|
|
10373
|
+
if (existsSync4(p)) changed.push(p);
|
|
10185
10374
|
}
|
|
10186
10375
|
} else {
|
|
10187
10376
|
for (const manifest of changed) {
|
|
@@ -10859,8 +11048,8 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
|
|
|
10859
11048
|
var session_recap_default = plugin32;
|
|
10860
11049
|
|
|
10861
11050
|
// src/shell-check/index.ts
|
|
10862
|
-
import {
|
|
10863
|
-
import {
|
|
11051
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
11052
|
+
import { readdir } from "node:fs/promises";
|
|
10864
11053
|
import { isAbsolute as isAbsolute12, join as join4, relative as relative11, resolve as resolve11 } from "node:path";
|
|
10865
11054
|
var API_VERSION15 = "^0.1.10";
|
|
10866
11055
|
function withinProject3(p) {
|
|
@@ -10881,15 +11070,23 @@ var state31 = {
|
|
|
10881
11070
|
/** Most recent run summary, surfaced by health(). */
|
|
10882
11071
|
lastRun: null
|
|
10883
11072
|
};
|
|
10884
|
-
function runShellCheck(files, severity, cwd) {
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
11073
|
+
async function runShellCheck(files, severity, cwd) {
|
|
11074
|
+
try {
|
|
11075
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
11076
|
+
execFile7(
|
|
11077
|
+
"shellcheck",
|
|
11078
|
+
["--version"],
|
|
11079
|
+
{ encoding: "utf-8", windowsHide: true },
|
|
11080
|
+
(err) => {
|
|
11081
|
+
if (err) rejectPromise(err);
|
|
11082
|
+
else resolvePromise();
|
|
11083
|
+
}
|
|
10891
11084
|
);
|
|
10892
|
-
}
|
|
11085
|
+
});
|
|
11086
|
+
} catch {
|
|
11087
|
+
throw new Error(
|
|
11088
|
+
"shellcheck is not installed. Install via: apt install shellcheck / brew install shellcheck"
|
|
11089
|
+
);
|
|
10893
11090
|
}
|
|
10894
11091
|
const levelMap = {
|
|
10895
11092
|
error: "error",
|
|
@@ -10901,20 +11098,34 @@ function runShellCheck(files, severity, cwd) {
|
|
|
10901
11098
|
const args = ["-f", "json", "-S", severityFlag, ...files];
|
|
10902
11099
|
let raw;
|
|
10903
11100
|
try {
|
|
10904
|
-
raw =
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
11101
|
+
raw = await new Promise((resolvePromise, rejectPromise) => {
|
|
11102
|
+
execFile7(
|
|
11103
|
+
"shellcheck",
|
|
11104
|
+
args,
|
|
11105
|
+
{
|
|
11106
|
+
encoding: "utf-8",
|
|
11107
|
+
cwd,
|
|
11108
|
+
windowsHide: true,
|
|
11109
|
+
timeout: 6e4,
|
|
11110
|
+
maxBuffer: 16 * 1024 * 1024
|
|
11111
|
+
},
|
|
11112
|
+
(err, stdout, stderr) => {
|
|
11113
|
+
if (err) {
|
|
11114
|
+
const e = err;
|
|
11115
|
+
const diagnostic = stdout || e.stdout?.toString() || stderr || e.stderr?.toString() || "";
|
|
11116
|
+
if (diagnostic.trim()) {
|
|
11117
|
+
resolvePromise(diagnostic);
|
|
11118
|
+
return;
|
|
11119
|
+
}
|
|
11120
|
+
rejectPromise(err);
|
|
11121
|
+
return;
|
|
11122
|
+
}
|
|
11123
|
+
resolvePromise(stdout);
|
|
11124
|
+
}
|
|
11125
|
+
);
|
|
10910
11126
|
});
|
|
10911
|
-
} catch
|
|
10912
|
-
|
|
10913
|
-
if (e.stderr && !e.stderr.includes("shellcheck")) {
|
|
10914
|
-
raw = e.stderr;
|
|
10915
|
-
} else {
|
|
10916
|
-
return [];
|
|
10917
|
-
}
|
|
11127
|
+
} catch {
|
|
11128
|
+
return [];
|
|
10918
11129
|
}
|
|
10919
11130
|
if (!raw.trim()) return [];
|
|
10920
11131
|
try {
|
|
@@ -10931,21 +11142,23 @@ function runShellCheck(files, severity, cwd) {
|
|
|
10931
11142
|
return [];
|
|
10932
11143
|
}
|
|
10933
11144
|
}
|
|
10934
|
-
function findShellFiles(dir, pattern) {
|
|
11145
|
+
async function findShellFiles(dir, pattern) {
|
|
10935
11146
|
const results = [];
|
|
11147
|
+
let entries;
|
|
10936
11148
|
try {
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
11149
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
11150
|
+
} catch {
|
|
11151
|
+
return results;
|
|
11152
|
+
}
|
|
11153
|
+
for (const entry of entries) {
|
|
11154
|
+
const full = join4(dir, entry.name);
|
|
11155
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
|
|
11156
|
+
results.push(...await findShellFiles(full, pattern));
|
|
11157
|
+
} else if (entry.isFile() && (entry.name.endsWith(".sh") || entry.name === "Dockerfile")) {
|
|
11158
|
+
if (!pattern || entry.name.includes(pattern)) {
|
|
11159
|
+
results.push(full);
|
|
10946
11160
|
}
|
|
10947
11161
|
}
|
|
10948
|
-
} catch {
|
|
10949
11162
|
}
|
|
10950
11163
|
return results;
|
|
10951
11164
|
}
|
|
@@ -11046,7 +11259,7 @@ var plugin33 = {
|
|
|
11046
11259
|
if (files && files.length > 0) {
|
|
11047
11260
|
checkFiles = files;
|
|
11048
11261
|
} else {
|
|
11049
|
-
checkFiles = findShellFiles(directory, pattern);
|
|
11262
|
+
checkFiles = await findShellFiles(directory, pattern);
|
|
11050
11263
|
scannedDirectories = true;
|
|
11051
11264
|
}
|
|
11052
11265
|
if (checkFiles.length === 0) {
|
|
@@ -11067,7 +11280,7 @@ var plugin33 = {
|
|
|
11067
11280
|
}
|
|
11068
11281
|
let issues;
|
|
11069
11282
|
try {
|
|
11070
|
-
issues = runShellCheck(checkFiles, severity);
|
|
11283
|
+
issues = await runShellCheck(checkFiles, severity);
|
|
11071
11284
|
} catch (err) {
|
|
11072
11285
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11073
11286
|
return { ok: false, error: msg, issues: [], filesScanned: 0 };
|
|
@@ -11709,8 +11922,8 @@ var plugin35 = {
|
|
|
11709
11922
|
var test_coverage_gate_default = plugin35;
|
|
11710
11923
|
|
|
11711
11924
|
// src/test-runner-gate/index.ts
|
|
11712
|
-
import { execFile as
|
|
11713
|
-
import { access } from "node:fs/promises";
|
|
11925
|
+
import { execFile as execFile8 } from "node:child_process";
|
|
11926
|
+
import { access as access2 } from "node:fs/promises";
|
|
11714
11927
|
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute15, join as join5 } from "node:path";
|
|
11715
11928
|
var API_VERSION18 = "^0.1.10";
|
|
11716
11929
|
var state33 = {
|
|
@@ -11813,7 +12026,7 @@ async function findTestFile(sourcePath, patterns) {
|
|
|
11813
12026
|
const candidates = resolveTestFiles(sourcePath, patterns);
|
|
11814
12027
|
for (const candidate of candidates) {
|
|
11815
12028
|
try {
|
|
11816
|
-
await
|
|
12029
|
+
await access2(candidate);
|
|
11817
12030
|
return candidate;
|
|
11818
12031
|
} catch {
|
|
11819
12032
|
}
|
|
@@ -11831,7 +12044,7 @@ async function detectRunner(requested) {
|
|
|
11831
12044
|
if (!match) return null;
|
|
11832
12045
|
try {
|
|
11833
12046
|
await new Promise((resolve28, reject) => {
|
|
11834
|
-
|
|
12047
|
+
execFile8("npx", [`${match.name}`, "--version"], {
|
|
11835
12048
|
encoding: "utf-8",
|
|
11836
12049
|
timeout: 5e3,
|
|
11837
12050
|
cwd: process.cwd()
|
|
@@ -11845,7 +12058,7 @@ async function detectRunner(requested) {
|
|
|
11845
12058
|
for (const candidate of candidates) {
|
|
11846
12059
|
try {
|
|
11847
12060
|
await new Promise((resolve28, reject) => {
|
|
11848
|
-
|
|
12061
|
+
execFile8("npx", [`${candidate.name}`, "--version"], {
|
|
11849
12062
|
encoding: "utf-8",
|
|
11850
12063
|
timeout: 5e3,
|
|
11851
12064
|
cwd: process.cwd()
|
|
@@ -11896,7 +12109,7 @@ async function runTests(testFile, runner, customCommand, timeoutMs) {
|
|
|
11896
12109
|
try {
|
|
11897
12110
|
const { stdout: out } = await new Promise(
|
|
11898
12111
|
(resolve28, reject) => {
|
|
11899
|
-
|
|
12112
|
+
execFile8(
|
|
11900
12113
|
cmd,
|
|
11901
12114
|
fullArgs,
|
|
11902
12115
|
{ encoding: "utf-8", timeout: timeoutMs, cwd: process.cwd() },
|
|
@@ -12198,8 +12411,7 @@ Fix the failing tests or revert the change if it broke something.`
|
|
|
12198
12411
|
var test_runner_gate_default = plugin36;
|
|
12199
12412
|
|
|
12200
12413
|
// src/type-gate/index.ts
|
|
12201
|
-
import {
|
|
12202
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
12414
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
12203
12415
|
var API_VERSION19 = "^0.1.10";
|
|
12204
12416
|
var state34 = {
|
|
12205
12417
|
invocationCount: 0,
|
|
@@ -12253,7 +12465,7 @@ function validateTsConfigPath(p) {
|
|
|
12253
12465
|
const sanitized = sanitizeRunnerPath(p);
|
|
12254
12466
|
return sanitized;
|
|
12255
12467
|
}
|
|
12256
|
-
function runTypeCheck(cfg) {
|
|
12468
|
+
async function runTypeCheck(cfg) {
|
|
12257
12469
|
const start = Date.now();
|
|
12258
12470
|
const rawTsConfig = cfg.tsConfigPath;
|
|
12259
12471
|
const validTsConfig = rawTsConfig && rawTsConfig !== "tsconfig.json" ? validateTsConfigPath(rawTsConfig) : null;
|
|
@@ -12267,32 +12479,22 @@ function runTypeCheck(cfg) {
|
|
|
12267
12479
|
if (!resolved) return null;
|
|
12268
12480
|
argv = [resolved.cmd, ...resolved.args];
|
|
12269
12481
|
} else {
|
|
12270
|
-
argv = ["npx", "tsc", "--noEmit"];
|
|
12482
|
+
argv = ["npx", "tsc", "--noEmit", "--incremental"];
|
|
12271
12483
|
if (tsConfig && tsConfig !== "tsconfig.json") {
|
|
12272
12484
|
argv = [...argv, "-p", tsConfig];
|
|
12273
12485
|
}
|
|
12274
12486
|
}
|
|
12275
|
-
if (!cfg.command && tsConfig && !
|
|
12487
|
+
if (!cfg.command && tsConfig && !existsSync5(tsConfig)) {
|
|
12276
12488
|
return null;
|
|
12277
12489
|
}
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
shell: false
|
|
12287
|
-
});
|
|
12288
|
-
stdout = out;
|
|
12289
|
-
} catch (err) {
|
|
12290
|
-
const e = err;
|
|
12291
|
-
if (e.killed) return null;
|
|
12292
|
-
stdout = e.stdout ?? "";
|
|
12293
|
-
stderr = e.stderr ?? "";
|
|
12294
|
-
}
|
|
12295
|
-
void runRunnerCommand;
|
|
12490
|
+
const result = await runRunnerCommand([argv[0], ...argv.slice(1)], {
|
|
12491
|
+
cwd: process.cwd(),
|
|
12492
|
+
timeoutMs: cfg.timeoutMs
|
|
12493
|
+
});
|
|
12494
|
+
if (result.timedOut) return null;
|
|
12495
|
+
if (result.spawnError) return null;
|
|
12496
|
+
const stdout = result.stdout;
|
|
12497
|
+
const stderr = result.stderr;
|
|
12296
12498
|
const combined = `${stdout}
|
|
12297
12499
|
${stderr}`.trim();
|
|
12298
12500
|
const durationMs = Date.now() - start;
|
|
@@ -12375,7 +12577,7 @@ var plugin37 = {
|
|
|
12375
12577
|
state34.lastResult = null;
|
|
12376
12578
|
state34.hookUnregister = null;
|
|
12377
12579
|
const cfg = readConfig30(api.config.extensions?.["type-gate"]);
|
|
12378
|
-
const hook = (input) => {
|
|
12580
|
+
const hook = async (input) => {
|
|
12379
12581
|
if (!cfg.enabled) return;
|
|
12380
12582
|
if (input.toolResult?.isError) return;
|
|
12381
12583
|
const inp = input.toolInput ?? {};
|
|
@@ -12388,7 +12590,7 @@ var plugin37 = {
|
|
|
12388
12590
|
return;
|
|
12389
12591
|
}
|
|
12390
12592
|
state34.invocationCount += 1;
|
|
12391
|
-
const result = runTypeCheck(cfg);
|
|
12593
|
+
const result = await runTypeCheck(cfg);
|
|
12392
12594
|
if (!result) {
|
|
12393
12595
|
state34.errorCount += 1;
|
|
12394
12596
|
return;
|
|
@@ -13968,8 +14170,8 @@ var plugin42 = {
|
|
|
13968
14170
|
var accessibility_auditor_default = plugin42;
|
|
13969
14171
|
|
|
13970
14172
|
// src/api-compatibility-gate/index.ts
|
|
13971
|
-
import { execFileSync as
|
|
13972
|
-
import { existsSync as
|
|
14173
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
14174
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10 } from "node:fs";
|
|
13973
14175
|
import { basename as basename4, dirname as dirname7, extname as extname2, isAbsolute as isAbsolute17, relative as relative14, resolve as resolve14 } from "node:path";
|
|
13974
14176
|
var API_VERSION22 = "^0.1.10";
|
|
13975
14177
|
var state40 = {
|
|
@@ -14050,7 +14252,7 @@ function isPackageEntryPoint(filePath) {
|
|
|
14050
14252
|
const resolved = resolveToProjectRoot(filePath);
|
|
14051
14253
|
const dir = dirname7(resolved);
|
|
14052
14254
|
const pkgPath = resolve14(dir, "package.json");
|
|
14053
|
-
if (!
|
|
14255
|
+
if (!existsSync6(pkgPath)) return false;
|
|
14054
14256
|
try {
|
|
14055
14257
|
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
14056
14258
|
const entries = [];
|
|
@@ -14125,7 +14327,7 @@ function readGitVersion(filePath) {
|
|
|
14125
14327
|
const resolved = resolveToProjectRoot(filePath);
|
|
14126
14328
|
const relPath = normalizePath2(relative14(process.cwd(), resolved));
|
|
14127
14329
|
try {
|
|
14128
|
-
const out =
|
|
14330
|
+
const out = execFileSync4("git", ["show", `HEAD:${relPath}`], {
|
|
14129
14331
|
encoding: "utf-8",
|
|
14130
14332
|
cwd: process.cwd(),
|
|
14131
14333
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -14930,7 +15132,7 @@ var plugin45 = {
|
|
|
14930
15132
|
var code_metrics_default = plugin45;
|
|
14931
15133
|
|
|
14932
15134
|
// src/dead-code-detector/index.ts
|
|
14933
|
-
import { readdirSync as
|
|
15135
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
|
|
14934
15136
|
import { extname as extname3, join as join6, relative as relative16, resolve as resolve16 } from "node:path";
|
|
14935
15137
|
var API_VERSION25 = "^0.1.10";
|
|
14936
15138
|
var state43 = {
|
|
@@ -14965,7 +15167,7 @@ function gatherFiles(root, depth, cfg) {
|
|
|
14965
15167
|
function walk(dir, remaining) {
|
|
14966
15168
|
let entries;
|
|
14967
15169
|
try {
|
|
14968
|
-
entries =
|
|
15170
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
14969
15171
|
} catch {
|
|
14970
15172
|
return;
|
|
14971
15173
|
}
|
|
@@ -15068,7 +15270,7 @@ function scan(root, depth, cfg) {
|
|
|
15068
15270
|
function resolveScanRoot(rawPath) {
|
|
15069
15271
|
const resolved = resolve16(process.cwd(), rawPath);
|
|
15070
15272
|
try {
|
|
15071
|
-
const stats =
|
|
15273
|
+
const stats = statSync5(resolved);
|
|
15072
15274
|
if (!stats.isDirectory()) {
|
|
15073
15275
|
return resolve16(resolved, "..");
|
|
15074
15276
|
}
|
|
@@ -15271,8 +15473,8 @@ Consider removing the export if it is not part of the public API.`;
|
|
|
15271
15473
|
var dead_code_detector_default = plugin46;
|
|
15272
15474
|
|
|
15273
15475
|
// src/dependency-vulnerability-gate/index.ts
|
|
15274
|
-
import { execFileSync as
|
|
15275
|
-
import { existsSync as
|
|
15476
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
15477
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
15276
15478
|
var API_VERSION26 = "^0.1.10";
|
|
15277
15479
|
var state44 = {
|
|
15278
15480
|
invocations: 0,
|
|
@@ -15385,14 +15587,14 @@ function isInstallCommand(input) {
|
|
|
15385
15587
|
return INSTALL_RE2.test(command);
|
|
15386
15588
|
}
|
|
15387
15589
|
function detectManager() {
|
|
15388
|
-
return
|
|
15590
|
+
return existsSync7("pnpm-lock.yaml") ? "pnpm" : "npm";
|
|
15389
15591
|
}
|
|
15390
15592
|
function runAudit(cfg) {
|
|
15391
15593
|
const manager = detectManager();
|
|
15392
15594
|
const start = Date.now();
|
|
15393
15595
|
let stdout = "";
|
|
15394
15596
|
try {
|
|
15395
|
-
stdout =
|
|
15597
|
+
stdout = execFileSync5(manager, ["audit", "--json"], {
|
|
15396
15598
|
encoding: "utf-8",
|
|
15397
15599
|
timeout: cfg.timeoutMs,
|
|
15398
15600
|
cwd: process.cwd(),
|
|
@@ -15788,7 +15990,7 @@ Consider mentioning these changes in the documentation.`;
|
|
|
15788
15990
|
var doc_sync_guard_default = plugin48;
|
|
15789
15991
|
|
|
15790
15992
|
// src/duplicate-code-detector/index.ts
|
|
15791
|
-
import { readFileSync as readFileSync14 } from "node:fs";
|
|
15993
|
+
import { readFileSync as readFileSync14, statSync as statSync6 } from "node:fs";
|
|
15792
15994
|
import { isAbsolute as isAbsolute19, relative as relative17, resolve as resolve17 } from "node:path";
|
|
15793
15995
|
var API_VERSION28 = "^0.1.10";
|
|
15794
15996
|
var state46 = {
|
|
@@ -15798,7 +16000,8 @@ var state46 = {
|
|
|
15798
16000
|
warningCount: 0,
|
|
15799
16001
|
errorCount: 0,
|
|
15800
16002
|
hookUnregister: null,
|
|
15801
|
-
lastHookWarning: /* @__PURE__ */ new Map()
|
|
16003
|
+
lastHookWarning: /* @__PURE__ */ new Map(),
|
|
16004
|
+
fileIndex: /* @__PURE__ */ new Map()
|
|
15802
16005
|
};
|
|
15803
16006
|
var DEFAULTS38 = {
|
|
15804
16007
|
enabled: false,
|
|
@@ -15946,6 +16149,7 @@ var plugin49 = {
|
|
|
15946
16149
|
state46.warningCount = 0;
|
|
15947
16150
|
state46.errorCount = 0;
|
|
15948
16151
|
state46.lastHookWarning.clear();
|
|
16152
|
+
state46.fileIndex.clear();
|
|
15949
16153
|
if (state46.hookUnregister) {
|
|
15950
16154
|
try {
|
|
15951
16155
|
state46.hookUnregister();
|
|
@@ -15954,6 +16158,27 @@ var plugin49 = {
|
|
|
15954
16158
|
state46.hookUnregister = null;
|
|
15955
16159
|
}
|
|
15956
16160
|
const cfg = readConfig41(api.config.extensions?.["duplicate-code-detector"]);
|
|
16161
|
+
function readCachedWindows(filePath, minLines) {
|
|
16162
|
+
let st;
|
|
16163
|
+
try {
|
|
16164
|
+
st = statSync6(filePath);
|
|
16165
|
+
} catch {
|
|
16166
|
+
return null;
|
|
16167
|
+
}
|
|
16168
|
+
const cached = state46.fileIndex.get(filePath);
|
|
16169
|
+
if (cached && cached.mtimeMs === st.mtimeMs && cached.size === st.size) {
|
|
16170
|
+
return cached.windows;
|
|
16171
|
+
}
|
|
16172
|
+
let content;
|
|
16173
|
+
try {
|
|
16174
|
+
content = readFileSync14(filePath, "utf-8");
|
|
16175
|
+
} catch {
|
|
16176
|
+
return null;
|
|
16177
|
+
}
|
|
16178
|
+
const windows = extractWindows(filePath, content, minLines);
|
|
16179
|
+
state46.fileIndex.set(filePath, { mtimeMs: st.mtimeMs, size: st.size, windows });
|
|
16180
|
+
return windows;
|
|
16181
|
+
}
|
|
15957
16182
|
const hook = (input) => {
|
|
15958
16183
|
if (!cfg.enabled) return;
|
|
15959
16184
|
if (input.toolResult?.isError) return;
|
|
@@ -15968,33 +16193,27 @@ var plugin49 = {
|
|
|
15968
16193
|
const lastWarning = state46.lastHookWarning.get(sourcePath);
|
|
15969
16194
|
if (lastWarning !== void 0 && now - lastWarning < 6e4) return;
|
|
15970
16195
|
const changedFile = resolve17(process.cwd(), sourcePath);
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
content = readFileSync14(changedFile, "utf-8");
|
|
15974
|
-
} catch {
|
|
16196
|
+
const changedWindows = readCachedWindows(changedFile, cfg.minLines);
|
|
16197
|
+
if (changedWindows === null) {
|
|
15975
16198
|
state46.errorCount += 1;
|
|
15976
16199
|
return;
|
|
15977
16200
|
}
|
|
15978
|
-
const changedWindows = extractWindows(changedFile, content, cfg.minLines);
|
|
15979
16201
|
if (changedWindows.length === 0) return;
|
|
15980
16202
|
const projectRoot = resolve17(process.cwd());
|
|
15981
|
-
let
|
|
16203
|
+
let otherFilePaths;
|
|
15982
16204
|
try {
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
otherFiles.set(p, readFileSync14(p, "utf-8"));
|
|
15988
|
-
} catch {
|
|
15989
|
-
}
|
|
15990
|
-
}
|
|
16205
|
+
otherFilePaths = collectSourceFiles(projectRoot, {
|
|
16206
|
+
extensions: cfg.extensions,
|
|
16207
|
+
excludeDirs: cfg.excludeDirs
|
|
16208
|
+
}).filter((p) => p !== changedFile);
|
|
15991
16209
|
} catch {
|
|
15992
16210
|
state46.errorCount += 1;
|
|
15993
16211
|
return;
|
|
15994
16212
|
}
|
|
15995
16213
|
const existingWindows = [];
|
|
15996
|
-
for (const
|
|
15997
|
-
|
|
16214
|
+
for (const p of otherFilePaths) {
|
|
16215
|
+
const w = readCachedWindows(p, cfg.minLines);
|
|
16216
|
+
if (w !== null) existingWindows.push(...w);
|
|
15998
16217
|
}
|
|
15999
16218
|
const hits = [];
|
|
16000
16219
|
for (const cw of changedWindows) {
|
|
@@ -16895,7 +17114,7 @@ Allowed licenses: ${cfg.allowedLicenses.join(", ")}
|
|
|
16895
17114
|
var license_audit_gate_default = plugin52;
|
|
16896
17115
|
|
|
16897
17116
|
// src/migration-planner/index.ts
|
|
16898
|
-
import { existsSync as
|
|
17117
|
+
import { existsSync as existsSync8, readFileSync as readFileSync18 } from "node:fs";
|
|
16899
17118
|
var API_VERSION32 = "^0.1.10";
|
|
16900
17119
|
var state50 = {
|
|
16901
17120
|
plansGenerated: 0,
|
|
@@ -16933,7 +17152,7 @@ function readChangelog(packageName, cfg) {
|
|
|
16933
17152
|
candidates.push(`node_modules/${packageName}/changelog.md`);
|
|
16934
17153
|
for (const candidate of candidates) {
|
|
16935
17154
|
if (!withinProject(candidate)) continue;
|
|
16936
|
-
if (
|
|
17155
|
+
if (existsSync8(candidate)) {
|
|
16937
17156
|
try {
|
|
16938
17157
|
const content = readFileSync18(candidate, "utf-8");
|
|
16939
17158
|
return { source: candidate, content: content.slice(0, cfg.maxChars) };
|
|
@@ -17357,7 +17576,7 @@ var plugin53 = {
|
|
|
17357
17576
|
var migration_planner_default = plugin53;
|
|
17358
17577
|
|
|
17359
17578
|
// src/performance-regression-gate/index.ts
|
|
17360
|
-
import { existsSync as
|
|
17579
|
+
import { existsSync as existsSync9, readFileSync as readFileSync19 } from "node:fs";
|
|
17361
17580
|
import { isAbsolute as isAbsolute22, relative as relative20, resolve as resolve21 } from "node:path";
|
|
17362
17581
|
var API_VERSION33 = "^0.1.10";
|
|
17363
17582
|
var state51 = {
|
|
@@ -17423,7 +17642,7 @@ function flattenResults(results) {
|
|
|
17423
17642
|
return flat;
|
|
17424
17643
|
}
|
|
17425
17644
|
function loadResults(path) {
|
|
17426
|
-
if (!path || !
|
|
17645
|
+
if (!path || !existsSync9(path)) return null;
|
|
17427
17646
|
try {
|
|
17428
17647
|
const raw = JSON.parse(readFileSync19(path, "utf-8"));
|
|
17429
17648
|
return raw;
|
|
@@ -18001,7 +18220,7 @@ var plugin55 = {
|
|
|
18001
18220
|
var refactor_suggester_default = plugin55;
|
|
18002
18221
|
|
|
18003
18222
|
// src/release-notes-generator/index.ts
|
|
18004
|
-
import { execFileSync as
|
|
18223
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
18005
18224
|
var API_VERSION35 = "^0.1.10";
|
|
18006
18225
|
var state53 = {
|
|
18007
18226
|
generateCount: 0,
|
|
@@ -18060,7 +18279,7 @@ function resolveFromRef(defaultFrom, inputFrom) {
|
|
|
18060
18279
|
if (inputFrom) return inputFrom;
|
|
18061
18280
|
if (defaultFrom === "latest-tag") {
|
|
18062
18281
|
try {
|
|
18063
|
-
return
|
|
18282
|
+
return execFileSync6("git", ["describe", "--tags", "--abbrev=0"], GIT_OPTIONS).trim();
|
|
18064
18283
|
} catch {
|
|
18065
18284
|
return "";
|
|
18066
18285
|
}
|
|
@@ -18068,7 +18287,7 @@ function resolveFromRef(defaultFrom, inputFrom) {
|
|
|
18068
18287
|
return defaultFrom;
|
|
18069
18288
|
}
|
|
18070
18289
|
function resolveCommit(ref) {
|
|
18071
|
-
const resolved =
|
|
18290
|
+
const resolved = execFileSync6(
|
|
18072
18291
|
"git",
|
|
18073
18292
|
["rev-parse", "--verify", "--end-of-options", `${ref}^{commit}`],
|
|
18074
18293
|
GIT_OPTIONS
|
|
@@ -18081,7 +18300,7 @@ function resolveCommit(ref) {
|
|
|
18081
18300
|
function getCommits(from, to) {
|
|
18082
18301
|
const toCommit = resolveCommit(to);
|
|
18083
18302
|
const range = from ? `${resolveCommit(from)}..${toCommit}` : toCommit;
|
|
18084
|
-
const output =
|
|
18303
|
+
const output = execFileSync6(
|
|
18085
18304
|
"git",
|
|
18086
18305
|
["log", "--pretty=format:%H%x09%s", "--end-of-options", range],
|
|
18087
18306
|
GIT_OPTIONS
|
|
@@ -18634,7 +18853,7 @@ ${body}${suffix}`;
|
|
|
18634
18853
|
var schema_evolution_guard_default = plugin57;
|
|
18635
18854
|
|
|
18636
18855
|
// src/security-hotspot-scanner/index.ts
|
|
18637
|
-
import { readdirSync as
|
|
18856
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync22, statSync as statSync7 } from "node:fs";
|
|
18638
18857
|
import { isAbsolute as isAbsolute24, relative as relative22, resolve as resolve23 } from "node:path";
|
|
18639
18858
|
var API_VERSION37 = "^0.1.10";
|
|
18640
18859
|
var state55 = {
|
|
@@ -18750,7 +18969,7 @@ function scanPath5(inputPath, cfg) {
|
|
|
18750
18969
|
const walk = (dir) => {
|
|
18751
18970
|
let entries;
|
|
18752
18971
|
try {
|
|
18753
|
-
entries =
|
|
18972
|
+
entries = readdirSync4(dir);
|
|
18754
18973
|
} catch {
|
|
18755
18974
|
return;
|
|
18756
18975
|
}
|
|
@@ -19699,7 +19918,7 @@ var plugin60 = {
|
|
|
19699
19918
|
var smart_rename_default = plugin60;
|
|
19700
19919
|
|
|
19701
19920
|
// src/test-flake-detector/index.ts
|
|
19702
|
-
import { execFileSync as
|
|
19921
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
19703
19922
|
import { readFileSync as readFileSync24 } from "node:fs";
|
|
19704
19923
|
import { createRequire as createRequire2 } from "node:module";
|
|
19705
19924
|
import { dirname as dirname8, isAbsolute as isAbsolute27, relative as relative25, resolve as resolve26 } from "node:path";
|
|
@@ -19845,7 +20064,7 @@ function resolveTestCommand(baseCommand, testPattern) {
|
|
|
19845
20064
|
}
|
|
19846
20065
|
function runOnce(command, timeoutMs) {
|
|
19847
20066
|
try {
|
|
19848
|
-
const output =
|
|
20067
|
+
const output = execFileSync7(command.cmd, command.args, {
|
|
19849
20068
|
encoding: "utf-8",
|
|
19850
20069
|
timeout: timeoutMs,
|
|
19851
20070
|
cwd: process.cwd(),
|
|
@@ -20679,8 +20898,8 @@ var plugin63 = {
|
|
|
20679
20898
|
state60.postInvocations += 1;
|
|
20680
20899
|
let content;
|
|
20681
20900
|
try {
|
|
20682
|
-
const
|
|
20683
|
-
if (!
|
|
20901
|
+
const stat5 = await fs3.stat(filePath);
|
|
20902
|
+
if (!stat5.isFile()) return;
|
|
20684
20903
|
content = await fs3.readFile(filePath, "utf-8");
|
|
20685
20904
|
} catch {
|
|
20686
20905
|
state60.readErrorCount += 1;
|