@wrongstack/plugins 0.291.1 → 0.292.0
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/spec-linker.js
CHANGED
|
@@ -5036,8 +5036,8 @@ var plugin15 = {
|
|
|
5036
5036
|
var file_watcher_default = plugin15;
|
|
5037
5037
|
|
|
5038
5038
|
// src/format-on-save/index.ts
|
|
5039
|
-
import {
|
|
5040
|
-
import {
|
|
5039
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
5040
|
+
import { access, stat as stat2 } from "node:fs/promises";
|
|
5041
5041
|
var API_VERSION8 = "^0.1.10";
|
|
5042
5042
|
var state14 = {
|
|
5043
5043
|
invocationCount: 0,
|
|
@@ -5096,29 +5096,46 @@ function evictExpired(ttlMs) {
|
|
|
5096
5096
|
if (ts < cutoff) recentlyCovered.delete(path);
|
|
5097
5097
|
}
|
|
5098
5098
|
}
|
|
5099
|
-
function formatFile(filePath, timeoutMs) {
|
|
5099
|
+
async function formatFile(filePath, timeoutMs) {
|
|
5100
5100
|
if (!withinProject(filePath)) return null;
|
|
5101
|
-
|
|
5101
|
+
try {
|
|
5102
|
+
await access(filePath);
|
|
5103
|
+
} catch {
|
|
5104
|
+
return null;
|
|
5105
|
+
}
|
|
5102
5106
|
let bytesBefore;
|
|
5103
5107
|
try {
|
|
5104
|
-
bytesBefore =
|
|
5108
|
+
bytesBefore = (await stat2(filePath)).size;
|
|
5105
5109
|
} catch {
|
|
5106
5110
|
return null;
|
|
5107
5111
|
}
|
|
5108
5112
|
try {
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5113
|
+
await new Promise((resolve28, reject) => {
|
|
5114
|
+
execFile3(
|
|
5115
|
+
"npx",
|
|
5116
|
+
["biome", "format", "--write", filePath],
|
|
5117
|
+
{
|
|
5118
|
+
encoding: "utf-8",
|
|
5119
|
+
timeout: timeoutMs,
|
|
5120
|
+
cwd: process.cwd(),
|
|
5121
|
+
windowsHide: true,
|
|
5122
|
+
maxBuffer: 16 * 1024 * 1024
|
|
5123
|
+
},
|
|
5124
|
+
(err) => {
|
|
5125
|
+
if (err) {
|
|
5126
|
+
const e = err;
|
|
5127
|
+
if (e.killed) return reject(err);
|
|
5128
|
+
}
|
|
5129
|
+
resolve28();
|
|
5130
|
+
}
|
|
5131
|
+
);
|
|
5114
5132
|
});
|
|
5115
|
-
} catch
|
|
5116
|
-
|
|
5117
|
-
if (e.killed) return null;
|
|
5133
|
+
} catch {
|
|
5134
|
+
return null;
|
|
5118
5135
|
}
|
|
5119
5136
|
let bytesAfter;
|
|
5120
5137
|
try {
|
|
5121
|
-
bytesAfter =
|
|
5138
|
+
bytesAfter = (await stat2(filePath)).size;
|
|
5122
5139
|
} catch {
|
|
5123
5140
|
return null;
|
|
5124
5141
|
}
|
|
@@ -5126,11 +5143,22 @@ function formatFile(filePath, timeoutMs) {
|
|
|
5126
5143
|
return { changed: true, bytesBefore, bytesAfter };
|
|
5127
5144
|
}
|
|
5128
5145
|
try {
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5146
|
+
await new Promise((resolve28, reject) => {
|
|
5147
|
+
execFile3(
|
|
5148
|
+
"npx",
|
|
5149
|
+
["biome", "format", filePath],
|
|
5150
|
+
{
|
|
5151
|
+
encoding: "utf-8",
|
|
5152
|
+
timeout: timeoutMs,
|
|
5153
|
+
cwd: process.cwd(),
|
|
5154
|
+
windowsHide: true,
|
|
5155
|
+
maxBuffer: 16 * 1024 * 1024
|
|
5156
|
+
},
|
|
5157
|
+
(err) => {
|
|
5158
|
+
if (err) return reject(err);
|
|
5159
|
+
resolve28();
|
|
5160
|
+
}
|
|
5161
|
+
);
|
|
5134
5162
|
});
|
|
5135
5163
|
return { changed: false, bytesBefore, bytesAfter };
|
|
5136
5164
|
} catch {
|
|
@@ -5171,7 +5199,7 @@ var plugin16 = {
|
|
|
5171
5199
|
}
|
|
5172
5200
|
}
|
|
5173
5201
|
},
|
|
5174
|
-
setup(api) {
|
|
5202
|
+
async setup(api) {
|
|
5175
5203
|
clearRegistrations();
|
|
5176
5204
|
state14.invocationCount = 0;
|
|
5177
5205
|
state14.formattedCount = 0;
|
|
@@ -5183,11 +5211,21 @@ var plugin16 = {
|
|
|
5183
5211
|
const cfg = readConfig12(api.config.extensions?.["format-on-save"]);
|
|
5184
5212
|
let biomeAvailable = false;
|
|
5185
5213
|
try {
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5214
|
+
await new Promise((resolve28, reject) => {
|
|
5215
|
+
execFile3(
|
|
5216
|
+
"npx",
|
|
5217
|
+
["biome", "--version"],
|
|
5218
|
+
{
|
|
5219
|
+
encoding: "utf-8",
|
|
5220
|
+
timeout: 5e3,
|
|
5221
|
+
cwd: process.cwd(),
|
|
5222
|
+
windowsHide: true
|
|
5223
|
+
},
|
|
5224
|
+
(err) => {
|
|
5225
|
+
if (err) reject(err);
|
|
5226
|
+
else resolve28();
|
|
5227
|
+
}
|
|
5228
|
+
);
|
|
5191
5229
|
});
|
|
5192
5230
|
biomeAvailable = true;
|
|
5193
5231
|
api.log.info("format-on-save: biome detected");
|
|
@@ -5195,7 +5233,7 @@ var plugin16 = {
|
|
|
5195
5233
|
biomeAvailable = false;
|
|
5196
5234
|
api.log.warn("format-on-save: biome not found \u2014 hook will be a no-op");
|
|
5197
5235
|
}
|
|
5198
|
-
const hook = (input) => {
|
|
5236
|
+
const hook = async (input) => {
|
|
5199
5237
|
if (!cfg.enabled || !biomeAvailable) return;
|
|
5200
5238
|
if (input.toolResult?.isError) return;
|
|
5201
5239
|
const toolName = input.toolName ?? "";
|
|
@@ -5217,7 +5255,7 @@ var plugin16 = {
|
|
|
5217
5255
|
}
|
|
5218
5256
|
}
|
|
5219
5257
|
state14.invocationCount += 1;
|
|
5220
|
-
const result = formatFile(filePath, cfg.timeoutMs);
|
|
5258
|
+
const result = await formatFile(filePath, cfg.timeoutMs);
|
|
5221
5259
|
if (!result) {
|
|
5222
5260
|
state14.errorCount += 1;
|
|
5223
5261
|
return;
|
|
@@ -5323,56 +5361,68 @@ var plugin16 = {
|
|
|
5323
5361
|
var format_on_save_default = plugin16;
|
|
5324
5362
|
|
|
5325
5363
|
// src/git-autocommit/index.ts
|
|
5326
|
-
import {
|
|
5327
|
-
import { existsSync as
|
|
5364
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
5365
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
5328
5366
|
var API_VERSION9 = "^0.1.10";
|
|
5329
5367
|
var commitCount = { value: 0 };
|
|
5330
5368
|
var lastCommit = { hash: null, at: null };
|
|
5331
5369
|
var llmGenerated = { value: 0 };
|
|
5332
5370
|
var DEFAULT_GIT_TIMEOUT_MS = 3e4;
|
|
5333
5371
|
var GIT_COMMIT_TIMEOUT_MS = 5 * 6e4;
|
|
5334
|
-
function runGit2(args, cwd, timeoutMs = DEFAULT_GIT_TIMEOUT_MS) {
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5372
|
+
async function runGit2(args, cwd, timeoutMs = DEFAULT_GIT_TIMEOUT_MS) {
|
|
5373
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
5374
|
+
execFile4(
|
|
5375
|
+
"git",
|
|
5376
|
+
args,
|
|
5377
|
+
{
|
|
5378
|
+
encoding: "utf-8",
|
|
5379
|
+
cwd,
|
|
5380
|
+
windowsHide: true,
|
|
5381
|
+
timeout: timeoutMs,
|
|
5382
|
+
maxBuffer: 10 * 1024 * 1024
|
|
5383
|
+
},
|
|
5384
|
+
(err, stdout) => {
|
|
5385
|
+
if (err) {
|
|
5386
|
+
const e = err;
|
|
5387
|
+
rejectPromise(
|
|
5388
|
+
new Error(
|
|
5389
|
+
`git command failed: ${e.message ?? e.stderr ?? String(err)}`
|
|
5390
|
+
)
|
|
5391
|
+
);
|
|
5392
|
+
return;
|
|
5393
|
+
}
|
|
5394
|
+
resolvePromise(stdout.trim());
|
|
5395
|
+
}
|
|
5396
|
+
);
|
|
5397
|
+
});
|
|
5348
5398
|
}
|
|
5349
|
-
function getChangedFiles(cwd) {
|
|
5350
|
-
const output = runGit2(["status", "--porcelain"], cwd);
|
|
5399
|
+
async function getChangedFiles(cwd) {
|
|
5400
|
+
const output = await runGit2(["status", "--porcelain"], cwd);
|
|
5351
5401
|
if (!output) return [];
|
|
5352
5402
|
return output.split("\n").filter((l) => l.trim()).map((l) => l.slice(3).trim());
|
|
5353
5403
|
}
|
|
5354
|
-
function getStagedFiles(cwd) {
|
|
5355
|
-
const output = runGit2(["diff", "--cached", "--name-only"], cwd);
|
|
5404
|
+
async function getStagedFiles(cwd) {
|
|
5405
|
+
const output = await runGit2(["diff", "--cached", "--name-only"], cwd);
|
|
5356
5406
|
return output ? output.split("\n").filter(Boolean) : [];
|
|
5357
5407
|
}
|
|
5358
|
-
function stageFiles(files, cwd) {
|
|
5408
|
+
async function stageFiles(files, cwd) {
|
|
5359
5409
|
if (!files || !Array.isArray(files)) return;
|
|
5360
5410
|
const existing = files.filter((f) => {
|
|
5361
5411
|
try {
|
|
5362
|
-
return
|
|
5412
|
+
return existsSync2(f);
|
|
5363
5413
|
} catch {
|
|
5364
5414
|
return false;
|
|
5365
5415
|
}
|
|
5366
5416
|
});
|
|
5367
5417
|
if (existing.length === 0) throw new Error("No files exist to stage");
|
|
5368
|
-
runGit2(["add", ...existing], cwd);
|
|
5418
|
+
await runGit2(["add", ...existing], cwd);
|
|
5369
5419
|
}
|
|
5370
|
-
function commitWithMessage(message, cwd) {
|
|
5371
|
-
return runGit2(["commit", "-m", message], cwd, GIT_COMMIT_TIMEOUT_MS);
|
|
5420
|
+
async function commitWithMessage(message, cwd) {
|
|
5421
|
+
return await runGit2(["commit", "-m", message], cwd, GIT_COMMIT_TIMEOUT_MS);
|
|
5372
5422
|
}
|
|
5373
|
-
function getWorktrees(cwd) {
|
|
5423
|
+
async function getWorktrees(cwd) {
|
|
5374
5424
|
try {
|
|
5375
|
-
const out = runGit2(["worktree", "list", "--porcelain"], cwd);
|
|
5425
|
+
const out = await runGit2(["worktree", "list", "--porcelain"], cwd);
|
|
5376
5426
|
if (!out) return [];
|
|
5377
5427
|
const entries = [];
|
|
5378
5428
|
let current = {};
|
|
@@ -5392,28 +5442,28 @@ function getWorktrees(cwd) {
|
|
|
5392
5442
|
return [];
|
|
5393
5443
|
}
|
|
5394
5444
|
}
|
|
5395
|
-
function simultaneousEditWarning(cwd) {
|
|
5396
|
-
const worktrees = getWorktrees(cwd);
|
|
5445
|
+
async function simultaneousEditWarning(cwd) {
|
|
5446
|
+
const worktrees = await getWorktrees(cwd);
|
|
5397
5447
|
if (worktrees.length > 1) {
|
|
5398
5448
|
const otherBranches = worktrees.filter((wt) => wt.branch).map((wt) => wt.branch.replace("refs/heads/", ""));
|
|
5399
5449
|
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.`;
|
|
5400
5450
|
}
|
|
5401
5451
|
return null;
|
|
5402
5452
|
}
|
|
5403
|
-
function getStagedDiff(cwd) {
|
|
5453
|
+
async function getStagedDiff(cwd) {
|
|
5404
5454
|
try {
|
|
5405
|
-
const
|
|
5406
|
-
const diff = runGit2(["diff", "--cached"], cwd);
|
|
5455
|
+
const stat5 = await runGit2(["diff", "--cached", "--stat"], cwd);
|
|
5456
|
+
const diff = await runGit2(["diff", "--cached"], cwd);
|
|
5407
5457
|
const MAX_DIFF = 2e4;
|
|
5408
5458
|
const truncated = diff.length > MAX_DIFF ? diff.slice(0, MAX_DIFF) + "\n\n... (diff truncated)" : diff;
|
|
5409
|
-
return { stat:
|
|
5459
|
+
return { stat: stat5 || "(no stat)", diff: truncated || "(clean)" };
|
|
5410
5460
|
} catch {
|
|
5411
5461
|
return { stat: "(unavailable)", diff: "(unavailable)" };
|
|
5412
5462
|
}
|
|
5413
5463
|
}
|
|
5414
|
-
function externalChangesSinceStage(cwd) {
|
|
5464
|
+
async function externalChangesSinceStage(cwd) {
|
|
5415
5465
|
try {
|
|
5416
|
-
const out = runGit2(["status", "--porcelain"], cwd);
|
|
5466
|
+
const out = await runGit2(["status", "--porcelain"], cwd);
|
|
5417
5467
|
if (!out) return null;
|
|
5418
5468
|
const unstaged = out.split("\n").filter((l) => l.trim()).filter((l) => {
|
|
5419
5469
|
const idx = l[0] ?? " ";
|
|
@@ -5444,14 +5494,14 @@ var VALID_TYPES = [
|
|
|
5444
5494
|
"build",
|
|
5445
5495
|
"revert"
|
|
5446
5496
|
];
|
|
5447
|
-
async function generateCommitFromDiff(api,
|
|
5497
|
+
async function generateCommitFromDiff(api, stat5, diff) {
|
|
5448
5498
|
if (!api.llm) return null;
|
|
5449
5499
|
try {
|
|
5450
5500
|
const result = await api.llm.complete(
|
|
5451
5501
|
`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.
|
|
5452
5502
|
|
|
5453
5503
|
Stat:
|
|
5454
|
-
${
|
|
5504
|
+
${stat5}
|
|
5455
5505
|
|
|
5456
5506
|
Diff:
|
|
5457
5507
|
${diff}`,
|
|
@@ -5588,7 +5638,7 @@ var plugin17 = {
|
|
|
5588
5638
|
}
|
|
5589
5639
|
if (files && files.length > 0) {
|
|
5590
5640
|
try {
|
|
5591
|
-
stageFiles(files);
|
|
5641
|
+
await stageFiles(files);
|
|
5592
5642
|
} catch (err) {
|
|
5593
5643
|
return {
|
|
5594
5644
|
ok: false,
|
|
@@ -5598,20 +5648,20 @@ var plugin17 = {
|
|
|
5598
5648
|
}
|
|
5599
5649
|
let staged = [];
|
|
5600
5650
|
try {
|
|
5601
|
-
staged = getStagedFiles();
|
|
5651
|
+
staged = await getStagedFiles();
|
|
5602
5652
|
} catch {
|
|
5603
5653
|
staged = [];
|
|
5604
5654
|
}
|
|
5605
5655
|
if (staged.length === 0) {
|
|
5606
5656
|
try {
|
|
5607
|
-
const changed = getChangedFiles();
|
|
5657
|
+
const changed = await getChangedFiles();
|
|
5608
5658
|
if (changed.length > 0) {
|
|
5609
5659
|
try {
|
|
5610
|
-
stageFiles(changed);
|
|
5660
|
+
await stageFiles(changed);
|
|
5611
5661
|
} catch {
|
|
5612
5662
|
}
|
|
5613
5663
|
try {
|
|
5614
|
-
staged = getStagedFiles();
|
|
5664
|
+
staged = await getStagedFiles();
|
|
5615
5665
|
} catch {
|
|
5616
5666
|
staged = [];
|
|
5617
5667
|
}
|
|
@@ -5619,10 +5669,10 @@ var plugin17 = {
|
|
|
5619
5669
|
} catch {
|
|
5620
5670
|
}
|
|
5621
5671
|
}
|
|
5622
|
-
const { stat:
|
|
5672
|
+
const { stat: stat5, diff: stagedDiff } = await getStagedDiff();
|
|
5623
5673
|
let generatedByLlm = false;
|
|
5624
5674
|
if (wantGenerate && staged.length > 0) {
|
|
5625
|
-
const g = await generateCommitFromDiff(api,
|
|
5675
|
+
const g = await generateCommitFromDiff(api, stat5, stagedDiff);
|
|
5626
5676
|
if (g) {
|
|
5627
5677
|
type = g.type;
|
|
5628
5678
|
if (g.scope) scope = g.scope;
|
|
@@ -5665,8 +5715,8 @@ var plugin17 = {
|
|
|
5665
5715
|
error: "Nothing staged. Add files with git add or provide files input."
|
|
5666
5716
|
};
|
|
5667
5717
|
}
|
|
5668
|
-
const worktreeWarn = simultaneousEditWarning();
|
|
5669
|
-
const externalChanges = externalChangesSinceStage();
|
|
5718
|
+
const worktreeWarn = await simultaneousEditWarning();
|
|
5719
|
+
const externalChanges = await externalChangesSinceStage();
|
|
5670
5720
|
let externalWarning = null;
|
|
5671
5721
|
if (externalChanges && externalChanges.length > 0) {
|
|
5672
5722
|
const preview = externalChanges.slice(0, 10).join(", ");
|
|
@@ -5683,7 +5733,7 @@ var plugin17 = {
|
|
|
5683
5733
|
stagedDiff: `
|
|
5684
5734
|
## Staged changes (dry run)
|
|
5685
5735
|
|
|
5686
|
-
${
|
|
5736
|
+
${stat5}
|
|
5687
5737
|
|
|
5688
5738
|
\`\`\`diff
|
|
5689
5739
|
${stagedDiff}
|
|
@@ -5691,15 +5741,15 @@ ${stagedDiff}
|
|
|
5691
5741
|
};
|
|
5692
5742
|
}
|
|
5693
5743
|
let preCommitDiff = stagedDiff;
|
|
5694
|
-
let preCommitStat =
|
|
5744
|
+
let preCommitStat = stat5;
|
|
5695
5745
|
if (staged.length === 0) {
|
|
5696
|
-
const fresh = getStagedDiff();
|
|
5746
|
+
const fresh = await getStagedDiff();
|
|
5697
5747
|
preCommitDiff = fresh.diff;
|
|
5698
5748
|
preCommitStat = fresh.stat;
|
|
5699
5749
|
}
|
|
5700
5750
|
let hash = "";
|
|
5701
5751
|
try {
|
|
5702
|
-
hash = commitWithMessage(msg);
|
|
5752
|
+
hash = await commitWithMessage(msg);
|
|
5703
5753
|
} catch (err) {
|
|
5704
5754
|
return {
|
|
5705
5755
|
ok: false,
|
|
@@ -5784,7 +5834,7 @@ var git_autocommit_default = plugin17;
|
|
|
5784
5834
|
|
|
5785
5835
|
// src/import-organizer/index.ts
|
|
5786
5836
|
import { spawn } from "node:child_process";
|
|
5787
|
-
import { existsSync as
|
|
5837
|
+
import { existsSync as existsSync3, statSync as statSync4 } from "node:fs";
|
|
5788
5838
|
import { basename as basename2, isAbsolute as isAbsolute7 } from "node:path";
|
|
5789
5839
|
var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
5790
5840
|
"npx",
|
|
@@ -5883,10 +5933,10 @@ function runCommand(command, args, timeoutMs, cwd) {
|
|
|
5883
5933
|
}
|
|
5884
5934
|
async function organizeImports(filePath, cfg, cwd) {
|
|
5885
5935
|
if (!withinProject(filePath)) return null;
|
|
5886
|
-
if (!
|
|
5936
|
+
if (!existsSync3(filePath)) return null;
|
|
5887
5937
|
let bytesBefore;
|
|
5888
5938
|
try {
|
|
5889
|
-
bytesBefore =
|
|
5939
|
+
bytesBefore = statSync4(filePath).size;
|
|
5890
5940
|
} catch {
|
|
5891
5941
|
return null;
|
|
5892
5942
|
}
|
|
@@ -5907,7 +5957,7 @@ async function organizeImports(filePath, cfg, cwd) {
|
|
|
5907
5957
|
if (result.code === 127) return null;
|
|
5908
5958
|
let bytesAfter;
|
|
5909
5959
|
try {
|
|
5910
|
-
bytesAfter =
|
|
5960
|
+
bytesAfter = statSync4(filePath).size;
|
|
5911
5961
|
} catch {
|
|
5912
5962
|
return null;
|
|
5913
5963
|
}
|
|
@@ -6632,7 +6682,7 @@ var plugin20 = {
|
|
|
6632
6682
|
var knowledge_graph_default = plugin20;
|
|
6633
6683
|
|
|
6634
6684
|
// src/lint-gate/index.ts
|
|
6635
|
-
import { execFile as
|
|
6685
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
6636
6686
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
6637
6687
|
import { mkdtemp, readFile as readFile2, rm, writeFile } from "node:fs/promises";
|
|
6638
6688
|
import { createRequire } from "node:module";
|
|
@@ -6702,7 +6752,7 @@ function resolveLocalLinter(name, cwd) {
|
|
|
6702
6752
|
function runCommand2(command, args, timeoutMs, cwd, signal) {
|
|
6703
6753
|
return new Promise((resolveResult) => {
|
|
6704
6754
|
try {
|
|
6705
|
-
|
|
6755
|
+
execFile5(
|
|
6706
6756
|
command,
|
|
6707
6757
|
args,
|
|
6708
6758
|
{
|
|
@@ -7345,7 +7395,7 @@ var plugin22 = {
|
|
|
7345
7395
|
var llm_cache_default = plugin22;
|
|
7346
7396
|
|
|
7347
7397
|
// src/loop-breaker/index.ts
|
|
7348
|
-
import { execFile as
|
|
7398
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
7349
7399
|
var state20 = {
|
|
7350
7400
|
lastFingerprint: null,
|
|
7351
7401
|
streak: 0,
|
|
@@ -7442,7 +7492,7 @@ function hashString2(value) {
|
|
|
7442
7492
|
async function gitDiffFingerprint(cwd, signal) {
|
|
7443
7493
|
try {
|
|
7444
7494
|
const diff = await new Promise((resolve28, reject) => {
|
|
7445
|
-
|
|
7495
|
+
execFile6(
|
|
7446
7496
|
"git",
|
|
7447
7497
|
["diff", "--no-ext-diff", "--"],
|
|
7448
7498
|
{
|
|
@@ -8010,15 +8060,134 @@ var plugin24 = {
|
|
|
8010
8060
|
var model_router_default = plugin24;
|
|
8011
8061
|
|
|
8012
8062
|
// src/notify-hub/index.ts
|
|
8063
|
+
import { lookup } from "node:dns/promises";
|
|
8064
|
+
|
|
8065
|
+
// src/notify-hub/webhook-channel.ts
|
|
8066
|
+
function freshCircuit() {
|
|
8067
|
+
return { open: false, consecutiveFailures: 0 };
|
|
8068
|
+
}
|
|
8069
|
+
var WebhookNotificationChannel = class {
|
|
8070
|
+
name = "webhook";
|
|
8071
|
+
type = "webhook";
|
|
8072
|
+
#url;
|
|
8073
|
+
#headers;
|
|
8074
|
+
#timeoutMs;
|
|
8075
|
+
#maxFailures;
|
|
8076
|
+
#circuit;
|
|
8077
|
+
/** Total deliveries attempted (across all resets). */
|
|
8078
|
+
#totalAttempted = 0;
|
|
8079
|
+
/** Total successful deliveries. */
|
|
8080
|
+
#totalDelivered = 0;
|
|
8081
|
+
/** Total failed deliveries. */
|
|
8082
|
+
#totalFailed = 0;
|
|
8083
|
+
/** Total suppressed by circuit breaker. */
|
|
8084
|
+
#totalSuppressed = 0;
|
|
8085
|
+
constructor(opts) {
|
|
8086
|
+
this.#url = opts.webhookUrl;
|
|
8087
|
+
this.#headers = opts.headers ?? {};
|
|
8088
|
+
this.#timeoutMs = opts.timeoutMs ?? 5e3;
|
|
8089
|
+
this.#maxFailures = opts.maxConsecutiveFailures ?? 5;
|
|
8090
|
+
this.#circuit = freshCircuit();
|
|
8091
|
+
}
|
|
8092
|
+
// -----------------------------------------------------------------------
|
|
8093
|
+
// NotificationChannel
|
|
8094
|
+
// -----------------------------------------------------------------------
|
|
8095
|
+
async deliver(msg) {
|
|
8096
|
+
const deliveredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8097
|
+
if (this.#circuit.open && this.#maxFailures > 0) {
|
|
8098
|
+
this.#totalSuppressed += 1;
|
|
8099
|
+
return {
|
|
8100
|
+
ok: false,
|
|
8101
|
+
channel: this.name,
|
|
8102
|
+
error: `circuit open after ${this.#circuit.consecutiveFailures} consecutive failures`,
|
|
8103
|
+
deliveredAt
|
|
8104
|
+
};
|
|
8105
|
+
}
|
|
8106
|
+
this.#totalAttempted += 1;
|
|
8107
|
+
const body = JSON.stringify({
|
|
8108
|
+
source: "wrongstack/notify-hub",
|
|
8109
|
+
event: msg.source,
|
|
8110
|
+
ts: deliveredAt,
|
|
8111
|
+
title: msg.title,
|
|
8112
|
+
message: msg.body,
|
|
8113
|
+
level: msg.level,
|
|
8114
|
+
...msg.metadata ?? {}
|
|
8115
|
+
});
|
|
8116
|
+
try {
|
|
8117
|
+
const controller = new AbortController();
|
|
8118
|
+
const timer = setTimeout(() => controller.abort(), this.#timeoutMs);
|
|
8119
|
+
try {
|
|
8120
|
+
const res = await fetch(this.#url, {
|
|
8121
|
+
method: "POST",
|
|
8122
|
+
headers: { "content-type": "application/json", ...this.#headers },
|
|
8123
|
+
body,
|
|
8124
|
+
signal: controller.signal
|
|
8125
|
+
});
|
|
8126
|
+
if (!res.ok) throw new Error(`webhook responded ${res.status}`);
|
|
8127
|
+
} finally {
|
|
8128
|
+
clearTimeout(timer);
|
|
8129
|
+
}
|
|
8130
|
+
this.#totalDelivered += 1;
|
|
8131
|
+
this.#circuit.consecutiveFailures = 0;
|
|
8132
|
+
this.#circuit.open = false;
|
|
8133
|
+
return { ok: true, channel: this.name, deliveredAt };
|
|
8134
|
+
} catch (err) {
|
|
8135
|
+
this.#totalFailed += 1;
|
|
8136
|
+
this.#circuit.consecutiveFailures += 1;
|
|
8137
|
+
if (this.#maxFailures > 0 && this.#circuit.consecutiveFailures >= this.#maxFailures) {
|
|
8138
|
+
this.#circuit.open = true;
|
|
8139
|
+
}
|
|
8140
|
+
return {
|
|
8141
|
+
ok: false,
|
|
8142
|
+
channel: this.name,
|
|
8143
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8144
|
+
deliveredAt
|
|
8145
|
+
};
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
async ping() {
|
|
8149
|
+
if (!this.#url) {
|
|
8150
|
+
return { ok: false, error: "no webhookUrl configured" };
|
|
8151
|
+
}
|
|
8152
|
+
if (this.#circuit.open) {
|
|
8153
|
+
return {
|
|
8154
|
+
ok: false,
|
|
8155
|
+
error: `circuit open after ${this.#circuit.consecutiveFailures} consecutive failures`
|
|
8156
|
+
};
|
|
8157
|
+
}
|
|
8158
|
+
return { ok: true };
|
|
8159
|
+
}
|
|
8160
|
+
// -----------------------------------------------------------------------
|
|
8161
|
+
// Diagnostics (not part of NotificationChannel)
|
|
8162
|
+
// -----------------------------------------------------------------------
|
|
8163
|
+
/** Reset the circuit breaker (e.g. after config update). */
|
|
8164
|
+
resetCircuit() {
|
|
8165
|
+
this.#circuit.open = false;
|
|
8166
|
+
this.#circuit.consecutiveFailures = 0;
|
|
8167
|
+
}
|
|
8168
|
+
/** Current circuit breaker state. */
|
|
8169
|
+
circuitStatus() {
|
|
8170
|
+
return { open: this.#circuit.open, consecutiveFailures: this.#circuit.consecutiveFailures };
|
|
8171
|
+
}
|
|
8172
|
+
/** Lifetime delivery counters (never reset). */
|
|
8173
|
+
counters() {
|
|
8174
|
+
return {
|
|
8175
|
+
attempted: this.#totalAttempted,
|
|
8176
|
+
delivered: this.#totalDelivered,
|
|
8177
|
+
failed: this.#totalFailed,
|
|
8178
|
+
suppressed: this.#totalSuppressed
|
|
8179
|
+
};
|
|
8180
|
+
}
|
|
8181
|
+
};
|
|
8182
|
+
|
|
8183
|
+
// src/notify-hub/index.ts
|
|
8184
|
+
var _pluginLog = null;
|
|
8013
8185
|
var state22 = {
|
|
8014
|
-
|
|
8015
|
-
failed: 0,
|
|
8016
|
-
suppressed: 0,
|
|
8017
|
-
consecutiveFailures: 0,
|
|
8018
|
-
circuitOpen: false,
|
|
8186
|
+
channel: null,
|
|
8019
8187
|
lastDelivery: null,
|
|
8020
8188
|
stopHookUnregister: null,
|
|
8021
|
-
eventUnsubscribers: []
|
|
8189
|
+
eventUnsubscribers: [],
|
|
8190
|
+
circuitWarned: false
|
|
8022
8191
|
};
|
|
8023
8192
|
var KNOWN_EVENTS = ["session.stop", "tool.error", "budget.threshold"];
|
|
8024
8193
|
var DEFAULTS19 = {
|
|
@@ -8041,6 +8210,21 @@ function isBlockedHostname(hostname) {
|
|
|
8041
8210
|
const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
8042
8211
|
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);
|
|
8043
8212
|
}
|
|
8213
|
+
async function hasPrivateResolvedIP(hostname) {
|
|
8214
|
+
try {
|
|
8215
|
+
const entries = await lookup(hostname, { all: true, verbatim: true });
|
|
8216
|
+
for (const { address } of entries) {
|
|
8217
|
+
if (isPrivateIPv4(address)) return true;
|
|
8218
|
+
const lower = address.toLowerCase();
|
|
8219
|
+
if (lower === "::1" || lower === "0:0:0:0:0:0:0:1" || lower.startsWith("fc") || lower.startsWith("fd") || lower.startsWith("fe80:")) {
|
|
8220
|
+
return true;
|
|
8221
|
+
}
|
|
8222
|
+
}
|
|
8223
|
+
return false;
|
|
8224
|
+
} catch {
|
|
8225
|
+
return false;
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8044
8228
|
function normalizeWebhookUrl(raw) {
|
|
8045
8229
|
if (typeof raw !== "string" || raw.trim().length === 0) return "";
|
|
8046
8230
|
try {
|
|
@@ -8072,49 +8256,37 @@ function readConfig20(raw) {
|
|
|
8072
8256
|
maxConsecutiveFailures: typeof r["maxConsecutiveFailures"] === "number" && r["maxConsecutiveFailures"] >= 1 ? r["maxConsecutiveFailures"] : DEFAULTS19.maxConsecutiveFailures
|
|
8073
8257
|
};
|
|
8074
8258
|
}
|
|
8075
|
-
async function deliver(
|
|
8076
|
-
|
|
8077
|
-
if (
|
|
8078
|
-
state22.suppressed += 1;
|
|
8259
|
+
async function deliver(event, payload) {
|
|
8260
|
+
const ch = state22.channel;
|
|
8261
|
+
if (!ch) {
|
|
8079
8262
|
return false;
|
|
8080
8263
|
}
|
|
8081
|
-
const
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8264
|
+
const result = await deliverViaChannel(ch, event, {
|
|
8265
|
+
title: typeof payload.title === "string" ? payload.title : event,
|
|
8266
|
+
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : JSON.stringify(payload),
|
|
8267
|
+
level: event === "tool.error" || event === "budget.threshold" ? "warning" : "info",
|
|
8268
|
+
source: event,
|
|
8269
|
+
metadata: payload
|
|
8086
8270
|
});
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
headers: { "content-type": "application/json", ...cfg.headers },
|
|
8094
|
-
body,
|
|
8095
|
-
signal: controller.signal
|
|
8096
|
-
});
|
|
8097
|
-
if (!res.ok) throw new Error(`webhook responded ${res.status}`);
|
|
8098
|
-
} finally {
|
|
8099
|
-
clearTimeout(timer);
|
|
8100
|
-
}
|
|
8101
|
-
state22.sent += 1;
|
|
8102
|
-
state22.consecutiveFailures = 0;
|
|
8271
|
+
return result.ok;
|
|
8272
|
+
}
|
|
8273
|
+
async function deliverViaChannel(ch, event, msg) {
|
|
8274
|
+
const result = await ch.deliver(msg);
|
|
8275
|
+
if (result.ok) {
|
|
8276
|
+
state22.circuitWarned = false;
|
|
8103
8277
|
state22.lastDelivery = { event, ok: true, when: (/* @__PURE__ */ new Date()).toISOString() };
|
|
8104
|
-
|
|
8105
|
-
} catch (err) {
|
|
8106
|
-
state22.failed += 1;
|
|
8107
|
-
state22.consecutiveFailures += 1;
|
|
8278
|
+
} else {
|
|
8108
8279
|
state22.lastDelivery = { event, ok: false, when: (/* @__PURE__ */ new Date()).toISOString() };
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
{
|
|
8280
|
+
const cs = ch.circuitStatus();
|
|
8281
|
+
if (cs.open && !state22.circuitWarned) {
|
|
8282
|
+
state22.circuitWarned = true;
|
|
8283
|
+
_pluginLog?.warn(
|
|
8284
|
+
`notify-hub: ${cs.consecutiveFailures} consecutive delivery failures \u2014 circuit opened, further notifications suppressed`,
|
|
8285
|
+
{ consecutiveFailures: cs.consecutiveFailures, event }
|
|
8114
8286
|
);
|
|
8115
8287
|
}
|
|
8116
|
-
return false;
|
|
8117
8288
|
}
|
|
8289
|
+
return result;
|
|
8118
8290
|
}
|
|
8119
8291
|
function truncateText(s, max) {
|
|
8120
8292
|
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
@@ -8161,12 +8333,10 @@ var plugin25 = {
|
|
|
8161
8333
|
}
|
|
8162
8334
|
}
|
|
8163
8335
|
},
|
|
8164
|
-
setup(api) {
|
|
8165
|
-
|
|
8166
|
-
state22.
|
|
8167
|
-
state22.
|
|
8168
|
-
state22.consecutiveFailures = 0;
|
|
8169
|
-
state22.circuitOpen = false;
|
|
8336
|
+
async setup(api) {
|
|
8337
|
+
_pluginLog = api.log;
|
|
8338
|
+
state22.circuitWarned = false;
|
|
8339
|
+
state22.channel = null;
|
|
8170
8340
|
state22.lastDelivery = null;
|
|
8171
8341
|
if (state22.stopHookUnregister) {
|
|
8172
8342
|
try {
|
|
@@ -8183,15 +8353,35 @@ var plugin25 = {
|
|
|
8183
8353
|
}
|
|
8184
8354
|
state22.eventUnsubscribers = [];
|
|
8185
8355
|
const cfg = readConfig20(api.config.extensions?.["notify-hub"]);
|
|
8186
|
-
|
|
8356
|
+
let active = cfg.enabled && cfg.webhookUrl.length > 0;
|
|
8357
|
+
if (active) {
|
|
8358
|
+
try {
|
|
8359
|
+
const url = new URL(cfg.webhookUrl);
|
|
8360
|
+
const hostnameBlocked = await hasPrivateResolvedIP(url.hostname);
|
|
8361
|
+
if (hostnameBlocked) {
|
|
8362
|
+
api.log.warn(
|
|
8363
|
+
`notify-hub: webhook URL resolves to a private/local IP (${url.hostname}) \u2014 disabling plugin`
|
|
8364
|
+
);
|
|
8365
|
+
active = false;
|
|
8366
|
+
}
|
|
8367
|
+
} catch {
|
|
8368
|
+
}
|
|
8369
|
+
}
|
|
8370
|
+
if (active) {
|
|
8371
|
+
state22.channel = new WebhookNotificationChannel({
|
|
8372
|
+
webhookUrl: cfg.webhookUrl,
|
|
8373
|
+
headers: cfg.headers,
|
|
8374
|
+
timeoutMs: cfg.timeoutMs,
|
|
8375
|
+
maxConsecutiveFailures: cfg.maxConsecutiveFailures
|
|
8376
|
+
});
|
|
8377
|
+
api.notifier?.registerChannel(state22.channel);
|
|
8378
|
+
}
|
|
8187
8379
|
if (active && cfg.events.includes("session.stop")) {
|
|
8188
8380
|
const stopHook = (input) => {
|
|
8189
|
-
void deliver(
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
api.log
|
|
8194
|
-
);
|
|
8381
|
+
void deliver("session.stop", {
|
|
8382
|
+
sessionId: input.sessionId ?? null,
|
|
8383
|
+
cwd: input.cwd ?? null
|
|
8384
|
+
});
|
|
8195
8385
|
};
|
|
8196
8386
|
state22.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
|
|
8197
8387
|
}
|
|
@@ -8199,26 +8389,21 @@ var plugin25 = {
|
|
|
8199
8389
|
const off = api.onPattern("tool.*", (eventName, payload) => {
|
|
8200
8390
|
if (!/error|failed/.test(eventName)) return;
|
|
8201
8391
|
const p = payload;
|
|
8202
|
-
void deliver(
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
500
|
|
8211
|
-
)
|
|
8212
|
-
},
|
|
8213
|
-
api.log
|
|
8214
|
-
);
|
|
8392
|
+
void deliver("tool.error", {
|
|
8393
|
+
tool: p?.tool ?? p?.name ?? "unknown",
|
|
8394
|
+
busEvent: eventName,
|
|
8395
|
+
error: truncateText(
|
|
8396
|
+
p?.error instanceof Error ? p.error.message : String(p?.error ?? ""),
|
|
8397
|
+
500
|
|
8398
|
+
)
|
|
8399
|
+
});
|
|
8215
8400
|
});
|
|
8216
8401
|
state22.eventUnsubscribers.push(off);
|
|
8217
8402
|
}
|
|
8218
8403
|
if (active && cfg.events.includes("budget.threshold")) {
|
|
8219
8404
|
const off = api.onPattern("budget.*", (eventName, payload) => {
|
|
8220
8405
|
if (!eventName.includes("threshold")) return;
|
|
8221
|
-
void deliver(
|
|
8406
|
+
void deliver("budget.threshold", { busEvent: eventName, detail: payload });
|
|
8222
8407
|
});
|
|
8223
8408
|
state22.eventUnsubscribers.push(off);
|
|
8224
8409
|
}
|
|
@@ -8243,26 +8428,23 @@ var plugin25 = {
|
|
|
8243
8428
|
mutating: true,
|
|
8244
8429
|
async execute(input) {
|
|
8245
8430
|
if (!cfg.enabled) return { ok: false, error: "notify-hub is disabled" };
|
|
8246
|
-
|
|
8431
|
+
const ch = state22.channel;
|
|
8432
|
+
if (!ch) {
|
|
8247
8433
|
return {
|
|
8248
8434
|
ok: false,
|
|
8249
8435
|
error: 'no webhookUrl configured \u2014 set config.extensions["notify-hub"].webhookUrl to enable deliveries'
|
|
8250
8436
|
};
|
|
8251
8437
|
}
|
|
8252
|
-
const
|
|
8253
|
-
|
|
8254
|
-
"
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
level: input.level === "warning" || input.level === "critical" ? input.level : "info"
|
|
8259
|
-
},
|
|
8260
|
-
api.log
|
|
8261
|
-
);
|
|
8438
|
+
const result = await deliverViaChannel(ch, "manual", {
|
|
8439
|
+
title: truncateText(String(input.title ?? "WrongStack notification"), 200),
|
|
8440
|
+
body: truncateText(String(input.message ?? ""), 2e3),
|
|
8441
|
+
level: input.level === "warning" || input.level === "critical" ? input.level : "info",
|
|
8442
|
+
source: "manual"
|
|
8443
|
+
});
|
|
8262
8444
|
return {
|
|
8263
|
-
ok:
|
|
8264
|
-
circuitOpen:
|
|
8265
|
-
...
|
|
8445
|
+
ok: result.ok,
|
|
8446
|
+
circuitOpen: ch.circuitStatus().open,
|
|
8447
|
+
...result.ok ? {} : { error: result.error ?? "delivery failed" }
|
|
8266
8448
|
};
|
|
8267
8449
|
}
|
|
8268
8450
|
});
|
|
@@ -8274,18 +8456,26 @@ var plugin25 = {
|
|
|
8274
8456
|
category: "Diagnostics",
|
|
8275
8457
|
mutating: false,
|
|
8276
8458
|
async execute() {
|
|
8459
|
+
const ch = state22.channel;
|
|
8460
|
+
const counters = ch?.counters() ?? {
|
|
8461
|
+
attempted: 0,
|
|
8462
|
+
delivered: 0,
|
|
8463
|
+
failed: 0,
|
|
8464
|
+
suppressed: 0
|
|
8465
|
+
};
|
|
8277
8466
|
return {
|
|
8278
8467
|
ok: true,
|
|
8279
8468
|
enabled: cfg.enabled,
|
|
8280
8469
|
webhookConfigured: cfg.webhookUrl.length > 0,
|
|
8281
8470
|
events: cfg.events,
|
|
8282
8471
|
timeoutMs: cfg.timeoutMs,
|
|
8283
|
-
circuitOpen:
|
|
8472
|
+
circuitOpen: ch?.circuitStatus().open ?? false,
|
|
8284
8473
|
counters: {
|
|
8285
|
-
sent:
|
|
8286
|
-
failed:
|
|
8287
|
-
suppressed:
|
|
8288
|
-
consecutiveFailures:
|
|
8474
|
+
sent: counters.delivered,
|
|
8475
|
+
failed: counters.failed,
|
|
8476
|
+
suppressed: counters.suppressed,
|
|
8477
|
+
consecutiveFailures: ch?.circuitStatus().consecutiveFailures ?? 0,
|
|
8478
|
+
totalAttempted: counters.attempted
|
|
8289
8479
|
},
|
|
8290
8480
|
lastDelivery: state22.lastDelivery
|
|
8291
8481
|
};
|
|
@@ -8299,6 +8489,8 @@ var plugin25 = {
|
|
|
8299
8489
|
});
|
|
8300
8490
|
},
|
|
8301
8491
|
teardown(api) {
|
|
8492
|
+
_pluginLog = null;
|
|
8493
|
+
state22.circuitWarned = false;
|
|
8302
8494
|
if (state22.stopHookUnregister) {
|
|
8303
8495
|
try {
|
|
8304
8496
|
state22.stopHookUnregister();
|
|
@@ -8313,25 +8505,22 @@ var plugin25 = {
|
|
|
8313
8505
|
}
|
|
8314
8506
|
}
|
|
8315
8507
|
state22.eventUnsubscribers = [];
|
|
8316
|
-
const
|
|
8317
|
-
state22.
|
|
8318
|
-
state22.failed = 0;
|
|
8319
|
-
state22.suppressed = 0;
|
|
8320
|
-
state22.consecutiveFailures = 0;
|
|
8321
|
-
state22.circuitOpen = false;
|
|
8508
|
+
const channelCounters = state22.channel?.counters();
|
|
8509
|
+
state22.channel = null;
|
|
8322
8510
|
state22.lastDelivery = null;
|
|
8323
|
-
api.log.info("notify-hub: teardown complete", {
|
|
8511
|
+
api.log.info("notify-hub: teardown complete", { channelCounters });
|
|
8324
8512
|
},
|
|
8325
8513
|
async health() {
|
|
8514
|
+
const ch = state22.channel;
|
|
8515
|
+
const cs = ch?.circuitStatus();
|
|
8516
|
+
const channelCounters = ch?.counters();
|
|
8517
|
+
const sent = channelCounters?.delivered ?? 0;
|
|
8518
|
+
const failed = channelCounters?.failed ?? 0;
|
|
8519
|
+
const suppressed = channelCounters?.suppressed ?? 0;
|
|
8326
8520
|
return {
|
|
8327
|
-
ok: !
|
|
8328
|
-
message:
|
|
8329
|
-
counters: {
|
|
8330
|
-
sent: state22.sent,
|
|
8331
|
-
failed: state22.failed,
|
|
8332
|
-
suppressed: state22.suppressed,
|
|
8333
|
-
consecutiveFailures: state22.consecutiveFailures
|
|
8334
|
-
}
|
|
8521
|
+
ok: !cs?.open,
|
|
8522
|
+
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`,
|
|
8523
|
+
counters: { sent, failed, suppressed, consecutiveFailures: cs?.consecutiveFailures ?? 0 }
|
|
8335
8524
|
};
|
|
8336
8525
|
}
|
|
8337
8526
|
};
|
|
@@ -8862,7 +9051,7 @@ function readConfig23(raw) {
|
|
|
8862
9051
|
var plugin_stack_observer_default = PLUGIN;
|
|
8863
9052
|
|
|
8864
9053
|
// src/pr-drafter/index.ts
|
|
8865
|
-
import { execFileSync as
|
|
9054
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8866
9055
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8867
9056
|
import { dirname as dirname5, isAbsolute as isAbsolute10, relative as relative9, resolve as resolve9 } from "node:path";
|
|
8868
9057
|
var API_VERSION13 = "^0.1.10";
|
|
@@ -8911,7 +9100,7 @@ function resolveProjectPath6(rawPath, cwd = process.cwd()) {
|
|
|
8911
9100
|
}
|
|
8912
9101
|
function gitBranch() {
|
|
8913
9102
|
try {
|
|
8914
|
-
const out =
|
|
9103
|
+
const out = execFileSync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
8915
9104
|
encoding: "utf-8",
|
|
8916
9105
|
cwd: process.cwd(),
|
|
8917
9106
|
stdio: ["pipe", "pipe", "ignore"],
|
|
@@ -8924,7 +9113,7 @@ function gitBranch() {
|
|
|
8924
9113
|
}
|
|
8925
9114
|
function gitDiff() {
|
|
8926
9115
|
try {
|
|
8927
|
-
return
|
|
9116
|
+
return execFileSync2("git", ["diff", "--stat"], {
|
|
8928
9117
|
encoding: "utf-8",
|
|
8929
9118
|
cwd: process.cwd(),
|
|
8930
9119
|
stdio: ["pipe", "pipe", "ignore"],
|
|
@@ -9924,8 +10113,8 @@ var secret_scanner_default = plugin30;
|
|
|
9924
10113
|
// src/semver-bump/index.ts
|
|
9925
10114
|
import { expectDefined as expectDefined2 } from "@wrongstack/core";
|
|
9926
10115
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
9927
|
-
import { execFileSync as
|
|
9928
|
-
import { existsSync as
|
|
10116
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
10117
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
9929
10118
|
import { isAbsolute as isAbsolute11, join as join3, relative as relative10, resolve as resolve10 } from "node:path";
|
|
9930
10119
|
var API_VERSION14 = "^0.1.10";
|
|
9931
10120
|
function resolveProjectRoot(rawCwd, root = process.cwd()) {
|
|
@@ -9946,7 +10135,7 @@ var state29 = {
|
|
|
9946
10135
|
};
|
|
9947
10136
|
function runGit3(args, cwd) {
|
|
9948
10137
|
try {
|
|
9949
|
-
return
|
|
10138
|
+
return execFileSync3("git", args, {
|
|
9950
10139
|
encoding: "utf-8",
|
|
9951
10140
|
cwd,
|
|
9952
10141
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -9961,7 +10150,7 @@ function runGit3(args, cwd) {
|
|
|
9961
10150
|
}
|
|
9962
10151
|
function getPackageJson(cwd) {
|
|
9963
10152
|
const path = cwd ? `${cwd}/package.json` : "package.json";
|
|
9964
|
-
if (!
|
|
10153
|
+
if (!existsSync4(path)) return null;
|
|
9965
10154
|
try {
|
|
9966
10155
|
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
9967
10156
|
} catch {
|
|
@@ -9971,14 +10160,14 @@ function getPackageJson(cwd) {
|
|
|
9971
10160
|
function collectManifests(root) {
|
|
9972
10161
|
const paths = [];
|
|
9973
10162
|
const rootPkg = join3(root, "package.json");
|
|
9974
|
-
if (
|
|
10163
|
+
if (existsSync4(rootPkg)) paths.push(rootPkg);
|
|
9975
10164
|
for (const group of ["packages", "apps"]) {
|
|
9976
10165
|
const groupDir = join3(root, group);
|
|
9977
|
-
if (!
|
|
10166
|
+
if (!existsSync4(groupDir)) continue;
|
|
9978
10167
|
for (const entry of readdirSync2(groupDir, { withFileTypes: true })) {
|
|
9979
10168
|
if (!entry.isDirectory()) continue;
|
|
9980
10169
|
const candidate = join3(groupDir, entry.name, "package.json");
|
|
9981
|
-
if (
|
|
10170
|
+
if (existsSync4(candidate)) paths.push(candidate);
|
|
9982
10171
|
}
|
|
9983
10172
|
}
|
|
9984
10173
|
return paths;
|
|
@@ -10170,9 +10359,9 @@ var plugin31 = {
|
|
|
10170
10359
|
const root = cwd ?? process.cwd();
|
|
10171
10360
|
const bumpScript = join3(root, "scripts", "bump-version.mjs");
|
|
10172
10361
|
const changed = collectManifests(root);
|
|
10173
|
-
if (
|
|
10362
|
+
if (existsSync4(bumpScript)) {
|
|
10174
10363
|
try {
|
|
10175
|
-
|
|
10364
|
+
execFileSync3(process.execPath, [bumpScript, "set", newVersion], {
|
|
10176
10365
|
cwd: root,
|
|
10177
10366
|
stdio: ["pipe", "pipe", "pipe"],
|
|
10178
10367
|
timeout: 3e4,
|
|
@@ -10184,7 +10373,7 @@ var plugin31 = {
|
|
|
10184
10373
|
}
|
|
10185
10374
|
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
10186
10375
|
const p = join3(root, "website", rel);
|
|
10187
|
-
if (
|
|
10376
|
+
if (existsSync4(p)) changed.push(p);
|
|
10188
10377
|
}
|
|
10189
10378
|
} else {
|
|
10190
10379
|
for (const manifest of changed) {
|
|
@@ -10862,8 +11051,8 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
|
|
|
10862
11051
|
var session_recap_default = plugin32;
|
|
10863
11052
|
|
|
10864
11053
|
// src/shell-check/index.ts
|
|
10865
|
-
import {
|
|
10866
|
-
import {
|
|
11054
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
11055
|
+
import { readdir } from "node:fs/promises";
|
|
10867
11056
|
import { isAbsolute as isAbsolute12, join as join4, relative as relative11, resolve as resolve11 } from "node:path";
|
|
10868
11057
|
var API_VERSION15 = "^0.1.10";
|
|
10869
11058
|
function withinProject3(p) {
|
|
@@ -10884,15 +11073,23 @@ var state31 = {
|
|
|
10884
11073
|
/** Most recent run summary, surfaced by health(). */
|
|
10885
11074
|
lastRun: null
|
|
10886
11075
|
};
|
|
10887
|
-
function runShellCheck(files, severity, cwd) {
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
11076
|
+
async function runShellCheck(files, severity, cwd) {
|
|
11077
|
+
try {
|
|
11078
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
11079
|
+
execFile7(
|
|
11080
|
+
"shellcheck",
|
|
11081
|
+
["--version"],
|
|
11082
|
+
{ encoding: "utf-8", windowsHide: true },
|
|
11083
|
+
(err) => {
|
|
11084
|
+
if (err) rejectPromise(err);
|
|
11085
|
+
else resolvePromise();
|
|
11086
|
+
}
|
|
10894
11087
|
);
|
|
10895
|
-
}
|
|
11088
|
+
});
|
|
11089
|
+
} catch {
|
|
11090
|
+
throw new Error(
|
|
11091
|
+
"shellcheck is not installed. Install via: apt install shellcheck / brew install shellcheck"
|
|
11092
|
+
);
|
|
10896
11093
|
}
|
|
10897
11094
|
const levelMap = {
|
|
10898
11095
|
error: "error",
|
|
@@ -10904,20 +11101,34 @@ function runShellCheck(files, severity, cwd) {
|
|
|
10904
11101
|
const args = ["-f", "json", "-S", severityFlag, ...files];
|
|
10905
11102
|
let raw;
|
|
10906
11103
|
try {
|
|
10907
|
-
raw =
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
11104
|
+
raw = await new Promise((resolvePromise, rejectPromise) => {
|
|
11105
|
+
execFile7(
|
|
11106
|
+
"shellcheck",
|
|
11107
|
+
args,
|
|
11108
|
+
{
|
|
11109
|
+
encoding: "utf-8",
|
|
11110
|
+
cwd,
|
|
11111
|
+
windowsHide: true,
|
|
11112
|
+
timeout: 6e4,
|
|
11113
|
+
maxBuffer: 16 * 1024 * 1024
|
|
11114
|
+
},
|
|
11115
|
+
(err, stdout, stderr) => {
|
|
11116
|
+
if (err) {
|
|
11117
|
+
const e = err;
|
|
11118
|
+
const diagnostic = stdout || e.stdout?.toString() || stderr || e.stderr?.toString() || "";
|
|
11119
|
+
if (diagnostic.trim()) {
|
|
11120
|
+
resolvePromise(diagnostic);
|
|
11121
|
+
return;
|
|
11122
|
+
}
|
|
11123
|
+
rejectPromise(err);
|
|
11124
|
+
return;
|
|
11125
|
+
}
|
|
11126
|
+
resolvePromise(stdout);
|
|
11127
|
+
}
|
|
11128
|
+
);
|
|
10913
11129
|
});
|
|
10914
|
-
} catch
|
|
10915
|
-
|
|
10916
|
-
if (e.stderr && !e.stderr.includes("shellcheck")) {
|
|
10917
|
-
raw = e.stderr;
|
|
10918
|
-
} else {
|
|
10919
|
-
return [];
|
|
10920
|
-
}
|
|
11130
|
+
} catch {
|
|
11131
|
+
return [];
|
|
10921
11132
|
}
|
|
10922
11133
|
if (!raw.trim()) return [];
|
|
10923
11134
|
try {
|
|
@@ -10934,21 +11145,23 @@ function runShellCheck(files, severity, cwd) {
|
|
|
10934
11145
|
return [];
|
|
10935
11146
|
}
|
|
10936
11147
|
}
|
|
10937
|
-
function findShellFiles(dir, pattern) {
|
|
11148
|
+
async function findShellFiles(dir, pattern) {
|
|
10938
11149
|
const results = [];
|
|
11150
|
+
let entries;
|
|
10939
11151
|
try {
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
11152
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
11153
|
+
} catch {
|
|
11154
|
+
return results;
|
|
11155
|
+
}
|
|
11156
|
+
for (const entry of entries) {
|
|
11157
|
+
const full = join4(dir, entry.name);
|
|
11158
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
|
|
11159
|
+
results.push(...await findShellFiles(full, pattern));
|
|
11160
|
+
} else if (entry.isFile() && (entry.name.endsWith(".sh") || entry.name === "Dockerfile")) {
|
|
11161
|
+
if (!pattern || entry.name.includes(pattern)) {
|
|
11162
|
+
results.push(full);
|
|
10949
11163
|
}
|
|
10950
11164
|
}
|
|
10951
|
-
} catch {
|
|
10952
11165
|
}
|
|
10953
11166
|
return results;
|
|
10954
11167
|
}
|
|
@@ -11049,7 +11262,7 @@ var plugin33 = {
|
|
|
11049
11262
|
if (files && files.length > 0) {
|
|
11050
11263
|
checkFiles = files;
|
|
11051
11264
|
} else {
|
|
11052
|
-
checkFiles = findShellFiles(directory, pattern);
|
|
11265
|
+
checkFiles = await findShellFiles(directory, pattern);
|
|
11053
11266
|
scannedDirectories = true;
|
|
11054
11267
|
}
|
|
11055
11268
|
if (checkFiles.length === 0) {
|
|
@@ -11070,7 +11283,7 @@ var plugin33 = {
|
|
|
11070
11283
|
}
|
|
11071
11284
|
let issues;
|
|
11072
11285
|
try {
|
|
11073
|
-
issues = runShellCheck(checkFiles, severity);
|
|
11286
|
+
issues = await runShellCheck(checkFiles, severity);
|
|
11074
11287
|
} catch (err) {
|
|
11075
11288
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11076
11289
|
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;
|