@wrongstack/plugins 0.309.0 → 0.310.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/cost-tracker/index.d.ts +2 -0
- package/dist/cost-tracker.js +24 -9
- package/dist/dependency-vulnerability-gate.js +31 -3
- package/dist/index.js +57 -24
- package/dist/path-guard.js +3 -9
- package/dist/todo-tracker/index.d.ts +29 -0
- package/dist/todo-tracker.js +2 -4
- package/package.json +6 -5
|
@@ -45,6 +45,8 @@ export interface ModelPricing {
|
|
|
45
45
|
input: number;
|
|
46
46
|
/** Cost per 1M output (completion) tokens in USD. */
|
|
47
47
|
output: number;
|
|
48
|
+
/** Cost per 1M prompt-cache read tokens; input rate is the safe fallback. */
|
|
49
|
+
cacheRead?: number | undefined;
|
|
48
50
|
}
|
|
49
51
|
declare const plugin: Plugin;
|
|
50
52
|
export default plugin;
|
package/dist/cost-tracker.js
CHANGED
|
@@ -12,13 +12,15 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
12
12
|
};
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
|
+
// src/cost-tracker/index.ts
|
|
16
|
+
import { expectDefined } from "@wrongstack/core/utils";
|
|
17
|
+
|
|
15
18
|
// src/runtime/index.ts
|
|
16
19
|
var runtime_exports = {};
|
|
17
20
|
__reExport(runtime_exports, runtime_star);
|
|
18
21
|
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
19
22
|
|
|
20
23
|
// src/cost-tracker/index.ts
|
|
21
|
-
import { expectDefined } from "@wrongstack/core/utils";
|
|
22
24
|
var API_VERSION = "^0.1.10";
|
|
23
25
|
var PRICING = {
|
|
24
26
|
"gpt-4o": { input: 5, output: 15 },
|
|
@@ -48,14 +50,14 @@ function readCostTrackerConfig(raw) {
|
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
var modelKeyCache = new runtime_exports.BoundedMap({ max: 256 });
|
|
51
|
-
function estimateCost(model,
|
|
53
|
+
function estimateCost(model, freshTokens, completionTokens, cachedTokens = 0) {
|
|
52
54
|
let key = modelKeyCache.get(model);
|
|
53
55
|
if (!key) {
|
|
54
56
|
key = model.toLowerCase();
|
|
55
57
|
modelKeyCache.set(model, key);
|
|
56
58
|
}
|
|
57
59
|
const pricing = pricingOverrides[key] ?? bundledFromRegistry[key] ?? PRICING[key] ?? DEFAULT_PRICING;
|
|
58
|
-
const inputCost =
|
|
60
|
+
const inputCost = freshTokens / 1e6 * pricing.input + cachedTokens / 1e6 * (pricing.cacheRead ?? pricing.input);
|
|
59
61
|
const outputCost = completionTokens / 1e6 * pricing.output;
|
|
60
62
|
return inputCost + outputCost;
|
|
61
63
|
}
|
|
@@ -89,12 +91,17 @@ var plugin = {
|
|
|
89
91
|
},
|
|
90
92
|
pricingOverrides: {
|
|
91
93
|
type: "object",
|
|
92
|
-
description: "Per-model pricing overrides in USD per 1M tokens.
|
|
94
|
+
description: "Per-model pricing overrides in USD per 1M tokens. Values are { input, output, cacheRead? }.",
|
|
93
95
|
additionalProperties: {
|
|
94
96
|
type: "object",
|
|
95
97
|
properties: {
|
|
96
98
|
input: { type: "number", minimum: 0, description: "Cost per 1M input tokens in USD" },
|
|
97
|
-
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" }
|
|
99
|
+
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" },
|
|
100
|
+
cacheRead: {
|
|
101
|
+
type: "number",
|
|
102
|
+
minimum: 0,
|
|
103
|
+
description: "Cost per 1M prompt-cache read tokens in USD"
|
|
104
|
+
}
|
|
98
105
|
},
|
|
99
106
|
required: ["input", "output"],
|
|
100
107
|
additionalProperties: false
|
|
@@ -127,7 +134,12 @@ var plugin = {
|
|
|
127
134
|
const input = v["input"];
|
|
128
135
|
const output = v["output"];
|
|
129
136
|
if (typeof input !== "number" || typeof output !== "number") continue;
|
|
130
|
-
|
|
137
|
+
const cacheRead = v["cacheRead"];
|
|
138
|
+
pricingOverrides[model.toLowerCase()] = {
|
|
139
|
+
input,
|
|
140
|
+
output,
|
|
141
|
+
...typeof cacheRead === "number" ? { cacheRead } : {}
|
|
142
|
+
};
|
|
131
143
|
}
|
|
132
144
|
}
|
|
133
145
|
if (api.modelsRegistry) {
|
|
@@ -142,7 +154,8 @@ var plugin = {
|
|
|
142
154
|
if (cost && typeof cost.input === "number" && typeof cost.output === "number") {
|
|
143
155
|
bundledFromRegistry[modelId.toLowerCase()] = {
|
|
144
156
|
input: cost.input,
|
|
145
|
-
output: cost.output
|
|
157
|
+
output: cost.output,
|
|
158
|
+
...typeof cost.cache_read === "number" ? { cacheRead: cost.cache_read } : {}
|
|
146
159
|
};
|
|
147
160
|
hydrated += 1;
|
|
148
161
|
}
|
|
@@ -169,10 +182,12 @@ var plugin = {
|
|
|
169
182
|
api.onEvent("provider.response", async (payload) => {
|
|
170
183
|
const usage = payload.usage;
|
|
171
184
|
const model = payload.ctx?.model ?? "unknown";
|
|
172
|
-
const
|
|
185
|
+
const cachedTokens = usage.cacheRead ?? 0;
|
|
186
|
+
const freshTokens = (usage.input ?? 0) + (usage.cacheWrite ?? 0);
|
|
187
|
+
const promptTokens = freshTokens + cachedTokens;
|
|
173
188
|
const completionTokens = usage.output ?? 0;
|
|
174
189
|
const totalTokens = promptTokens + completionTokens;
|
|
175
|
-
const costUsd = estimateCost(model,
|
|
190
|
+
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
176
191
|
const record = {
|
|
177
192
|
promptTokens,
|
|
178
193
|
completionTokens,
|
|
@@ -402,6 +402,7 @@ var state2 = {
|
|
|
402
402
|
auditsRun: 0,
|
|
403
403
|
blocks: 0,
|
|
404
404
|
warns: 0,
|
|
405
|
+
belowThresholdWarns: 0,
|
|
405
406
|
errors: 0,
|
|
406
407
|
lastResult: null,
|
|
407
408
|
hookUnregister: null
|
|
@@ -449,9 +450,11 @@ function parseAuditJson(jsonString) {
|
|
|
449
450
|
return null;
|
|
450
451
|
}
|
|
451
452
|
const out = { maxSeverity: null, counts: {}, total: 0 };
|
|
452
|
-
|
|
453
|
+
let recognizedShape = false;
|
|
454
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
453
455
|
const vulnerabilities = parsed["vulnerabilities"];
|
|
454
456
|
if (vulnerabilities && typeof vulnerabilities === "object" && !Array.isArray(vulnerabilities)) {
|
|
457
|
+
recognizedShape = true;
|
|
455
458
|
for (const entry of Object.values(vulnerabilities)) {
|
|
456
459
|
if (entry && typeof entry === "object") {
|
|
457
460
|
const severity = entry["severity"];
|
|
@@ -464,7 +467,8 @@ function parseAuditJson(jsonString) {
|
|
|
464
467
|
if (out.total === 0) {
|
|
465
468
|
const metadata = parsed["metadata"];
|
|
466
469
|
const metaVulns = metadata && typeof metadata === "object" ? metadata["vulnerabilities"] : void 0;
|
|
467
|
-
if (metaVulns && typeof metaVulns === "object") {
|
|
470
|
+
if (metaVulns && typeof metaVulns === "object" && !Array.isArray(metaVulns)) {
|
|
471
|
+
recognizedShape = true;
|
|
468
472
|
for (const [key, value] of Object.entries(metaVulns)) {
|
|
469
473
|
const count = typeof value === "number" ? value : 0;
|
|
470
474
|
if (count > 0 && SEVERITY_RANK[key] != null) {
|
|
@@ -480,6 +484,7 @@ function parseAuditJson(jsonString) {
|
|
|
480
484
|
}
|
|
481
485
|
}
|
|
482
486
|
if (Array.isArray(parsed)) {
|
|
487
|
+
recognizedShape = true;
|
|
483
488
|
for (const entry of parsed) {
|
|
484
489
|
if (entry && typeof entry === "object") {
|
|
485
490
|
const severity = entry["severity"];
|
|
@@ -489,6 +494,7 @@ function parseAuditJson(jsonString) {
|
|
|
489
494
|
}
|
|
490
495
|
}
|
|
491
496
|
}
|
|
497
|
+
if (!recognizedShape) return null;
|
|
492
498
|
return out;
|
|
493
499
|
}
|
|
494
500
|
function exceedsThreshold(report, threshold) {
|
|
@@ -598,6 +604,7 @@ var plugin2 = {
|
|
|
598
604
|
state2.auditsRun = 0;
|
|
599
605
|
state2.blocks = 0;
|
|
600
606
|
state2.warns = 0;
|
|
607
|
+
state2.belowThresholdWarns = 0;
|
|
601
608
|
state2.errors = 0;
|
|
602
609
|
state2.lastResult = null;
|
|
603
610
|
if (state2.hookUnregister) {
|
|
@@ -618,7 +625,13 @@ var plugin2 = {
|
|
|
618
625
|
const result = await runAudit(cfg);
|
|
619
626
|
if (!result) {
|
|
620
627
|
state2.errors += 1;
|
|
621
|
-
|
|
628
|
+
api.metrics.counter("audit_errors");
|
|
629
|
+
api.log.warn("dependency-vulnerability-gate: audit did not complete; install not vetted", {
|
|
630
|
+
managerHint: "see dependency_audit_status for counters"
|
|
631
|
+
});
|
|
632
|
+
return {
|
|
633
|
+
additionalContext: "\n\u26A0\uFE0F dependency-vulnerability-gate: the package audit could not be completed (timeout or unreadable output), so these dependencies were NOT checked for known vulnerabilities."
|
|
634
|
+
};
|
|
622
635
|
}
|
|
623
636
|
state2.auditsRun += 1;
|
|
624
637
|
state2.lastResult = {
|
|
@@ -630,6 +643,17 @@ var plugin2 = {
|
|
|
630
643
|
when: (/* @__PURE__ */ new Date()).toISOString()
|
|
631
644
|
};
|
|
632
645
|
if (!exceedsThreshold(result.report, cfg.severityThreshold)) {
|
|
646
|
+
if (result.report.total > 0) {
|
|
647
|
+
state2.belowThresholdWarns += 1;
|
|
648
|
+
api.metrics.counter("below_threshold_warns");
|
|
649
|
+
const belowCounts = Object.entries(result.report.counts).filter(([, count]) => count > 0).map(([sev, count]) => `${sev}: ${count}`).join(", ");
|
|
650
|
+
return {
|
|
651
|
+
additionalContext: `
|
|
652
|
+
\u2139\uFE0F dependency-vulnerability-gate: ${result.manager} audit found vulnerabilities BELOW the configured threshold (${cfg.severityThreshold}); not blocking.
|
|
653
|
+
Max severity: ${result.report.maxSeverity}
|
|
654
|
+
Counts: ${belowCounts || "unknown"}`
|
|
655
|
+
};
|
|
656
|
+
}
|
|
633
657
|
return;
|
|
634
658
|
}
|
|
635
659
|
const countsText = Object.entries(result.report.counts).filter(([, count]) => count > 0).map(([sev, count]) => `${sev}: ${count}`).join(", ");
|
|
@@ -671,6 +695,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
671
695
|
auditsRun: state2.auditsRun,
|
|
672
696
|
blocks: state2.blocks,
|
|
673
697
|
warns: state2.warns,
|
|
698
|
+
belowThresholdWarns: state2.belowThresholdWarns,
|
|
674
699
|
errors: state2.errors
|
|
675
700
|
},
|
|
676
701
|
lastResult: state2.lastResult
|
|
@@ -697,6 +722,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
697
722
|
auditsRun: state2.auditsRun,
|
|
698
723
|
blocks: state2.blocks,
|
|
699
724
|
warns: state2.warns,
|
|
725
|
+
belowThresholdWarns: state2.belowThresholdWarns,
|
|
700
726
|
errors: state2.errors
|
|
701
727
|
};
|
|
702
728
|
state2.invocations = 0;
|
|
@@ -704,6 +730,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
704
730
|
state2.auditsRun = 0;
|
|
705
731
|
state2.blocks = 0;
|
|
706
732
|
state2.warns = 0;
|
|
733
|
+
state2.belowThresholdWarns = 0;
|
|
707
734
|
state2.errors = 0;
|
|
708
735
|
state2.lastResult = null;
|
|
709
736
|
api.log.info("dependency-vulnerability-gate: teardown complete", { final });
|
|
@@ -718,6 +745,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
718
745
|
auditsRun: state2.auditsRun,
|
|
719
746
|
blocks: state2.blocks,
|
|
720
747
|
warns: state2.warns,
|
|
748
|
+
belowThresholdWarns: state2.belowThresholdWarns,
|
|
721
749
|
errors: state2.errors
|
|
722
750
|
},
|
|
723
751
|
lastResult: state2.lastResult
|
package/dist/index.js
CHANGED
|
@@ -4370,14 +4370,14 @@ function readCostTrackerConfig(raw) {
|
|
|
4370
4370
|
};
|
|
4371
4371
|
}
|
|
4372
4372
|
var modelKeyCache = new runtime_exports.BoundedMap({ max: 256 });
|
|
4373
|
-
function estimateCost(model,
|
|
4373
|
+
function estimateCost(model, freshTokens, completionTokens, cachedTokens = 0) {
|
|
4374
4374
|
let key = modelKeyCache.get(model);
|
|
4375
4375
|
if (!key) {
|
|
4376
4376
|
key = model.toLowerCase();
|
|
4377
4377
|
modelKeyCache.set(model, key);
|
|
4378
4378
|
}
|
|
4379
4379
|
const pricing = pricingOverrides[key] ?? bundledFromRegistry[key] ?? PRICING[key] ?? DEFAULT_PRICING;
|
|
4380
|
-
const inputCost =
|
|
4380
|
+
const inputCost = freshTokens / 1e6 * pricing.input + cachedTokens / 1e6 * (pricing.cacheRead ?? pricing.input);
|
|
4381
4381
|
const outputCost = completionTokens / 1e6 * pricing.output;
|
|
4382
4382
|
return inputCost + outputCost;
|
|
4383
4383
|
}
|
|
@@ -4411,12 +4411,17 @@ var plugin14 = {
|
|
|
4411
4411
|
},
|
|
4412
4412
|
pricingOverrides: {
|
|
4413
4413
|
type: "object",
|
|
4414
|
-
description: "Per-model pricing overrides in USD per 1M tokens.
|
|
4414
|
+
description: "Per-model pricing overrides in USD per 1M tokens. Values are { input, output, cacheRead? }.",
|
|
4415
4415
|
additionalProperties: {
|
|
4416
4416
|
type: "object",
|
|
4417
4417
|
properties: {
|
|
4418
4418
|
input: { type: "number", minimum: 0, description: "Cost per 1M input tokens in USD" },
|
|
4419
|
-
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" }
|
|
4419
|
+
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" },
|
|
4420
|
+
cacheRead: {
|
|
4421
|
+
type: "number",
|
|
4422
|
+
minimum: 0,
|
|
4423
|
+
description: "Cost per 1M prompt-cache read tokens in USD"
|
|
4424
|
+
}
|
|
4420
4425
|
},
|
|
4421
4426
|
required: ["input", "output"],
|
|
4422
4427
|
additionalProperties: false
|
|
@@ -4449,7 +4454,12 @@ var plugin14 = {
|
|
|
4449
4454
|
const input = v["input"];
|
|
4450
4455
|
const output = v["output"];
|
|
4451
4456
|
if (typeof input !== "number" || typeof output !== "number") continue;
|
|
4452
|
-
|
|
4457
|
+
const cacheRead = v["cacheRead"];
|
|
4458
|
+
pricingOverrides[model.toLowerCase()] = {
|
|
4459
|
+
input,
|
|
4460
|
+
output,
|
|
4461
|
+
...typeof cacheRead === "number" ? { cacheRead } : {}
|
|
4462
|
+
};
|
|
4453
4463
|
}
|
|
4454
4464
|
}
|
|
4455
4465
|
if (api.modelsRegistry) {
|
|
@@ -4464,7 +4474,8 @@ var plugin14 = {
|
|
|
4464
4474
|
if (cost && typeof cost.input === "number" && typeof cost.output === "number") {
|
|
4465
4475
|
bundledFromRegistry[modelId.toLowerCase()] = {
|
|
4466
4476
|
input: cost.input,
|
|
4467
|
-
output: cost.output
|
|
4477
|
+
output: cost.output,
|
|
4478
|
+
...typeof cost.cache_read === "number" ? { cacheRead: cost.cache_read } : {}
|
|
4468
4479
|
};
|
|
4469
4480
|
hydrated += 1;
|
|
4470
4481
|
}
|
|
@@ -4491,10 +4502,12 @@ var plugin14 = {
|
|
|
4491
4502
|
api.onEvent("provider.response", async (payload) => {
|
|
4492
4503
|
const usage = payload.usage;
|
|
4493
4504
|
const model = payload.ctx?.model ?? "unknown";
|
|
4494
|
-
const
|
|
4505
|
+
const cachedTokens = usage.cacheRead ?? 0;
|
|
4506
|
+
const freshTokens = (usage.input ?? 0) + (usage.cacheWrite ?? 0);
|
|
4507
|
+
const promptTokens = freshTokens + cachedTokens;
|
|
4495
4508
|
const completionTokens = usage.output ?? 0;
|
|
4496
4509
|
const totalTokens = promptTokens + completionTokens;
|
|
4497
|
-
const costUsd = estimateCost(model,
|
|
4510
|
+
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
4498
4511
|
const record = {
|
|
4499
4512
|
promptTokens,
|
|
4500
4513
|
completionTokens,
|
|
@@ -5713,6 +5726,7 @@ var state17 = {
|
|
|
5713
5726
|
auditsRun: 0,
|
|
5714
5727
|
blocks: 0,
|
|
5715
5728
|
warns: 0,
|
|
5729
|
+
belowThresholdWarns: 0,
|
|
5716
5730
|
errors: 0,
|
|
5717
5731
|
lastResult: null,
|
|
5718
5732
|
hookUnregister: null
|
|
@@ -5760,9 +5774,11 @@ function parseAuditJson(jsonString) {
|
|
|
5760
5774
|
return null;
|
|
5761
5775
|
}
|
|
5762
5776
|
const out = { maxSeverity: null, counts: {}, total: 0 };
|
|
5763
|
-
|
|
5777
|
+
let recognizedShape = false;
|
|
5778
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5764
5779
|
const vulnerabilities = parsed["vulnerabilities"];
|
|
5765
5780
|
if (vulnerabilities && typeof vulnerabilities === "object" && !Array.isArray(vulnerabilities)) {
|
|
5781
|
+
recognizedShape = true;
|
|
5766
5782
|
for (const entry of Object.values(vulnerabilities)) {
|
|
5767
5783
|
if (entry && typeof entry === "object") {
|
|
5768
5784
|
const severity = entry["severity"];
|
|
@@ -5775,7 +5791,8 @@ function parseAuditJson(jsonString) {
|
|
|
5775
5791
|
if (out.total === 0) {
|
|
5776
5792
|
const metadata = parsed["metadata"];
|
|
5777
5793
|
const metaVulns = metadata && typeof metadata === "object" ? metadata["vulnerabilities"] : void 0;
|
|
5778
|
-
if (metaVulns && typeof metaVulns === "object") {
|
|
5794
|
+
if (metaVulns && typeof metaVulns === "object" && !Array.isArray(metaVulns)) {
|
|
5795
|
+
recognizedShape = true;
|
|
5779
5796
|
for (const [key, value] of Object.entries(metaVulns)) {
|
|
5780
5797
|
const count = typeof value === "number" ? value : 0;
|
|
5781
5798
|
if (count > 0 && SEVERITY_RANK[key] != null) {
|
|
@@ -5791,6 +5808,7 @@ function parseAuditJson(jsonString) {
|
|
|
5791
5808
|
}
|
|
5792
5809
|
}
|
|
5793
5810
|
if (Array.isArray(parsed)) {
|
|
5811
|
+
recognizedShape = true;
|
|
5794
5812
|
for (const entry of parsed) {
|
|
5795
5813
|
if (entry && typeof entry === "object") {
|
|
5796
5814
|
const severity = entry["severity"];
|
|
@@ -5800,6 +5818,7 @@ function parseAuditJson(jsonString) {
|
|
|
5800
5818
|
}
|
|
5801
5819
|
}
|
|
5802
5820
|
}
|
|
5821
|
+
if (!recognizedShape) return null;
|
|
5803
5822
|
return out;
|
|
5804
5823
|
}
|
|
5805
5824
|
function exceedsThreshold(report, threshold) {
|
|
@@ -5909,6 +5928,7 @@ var plugin18 = {
|
|
|
5909
5928
|
state17.auditsRun = 0;
|
|
5910
5929
|
state17.blocks = 0;
|
|
5911
5930
|
state17.warns = 0;
|
|
5931
|
+
state17.belowThresholdWarns = 0;
|
|
5912
5932
|
state17.errors = 0;
|
|
5913
5933
|
state17.lastResult = null;
|
|
5914
5934
|
if (state17.hookUnregister) {
|
|
@@ -5929,7 +5949,13 @@ var plugin18 = {
|
|
|
5929
5949
|
const result = await runAudit(cfg);
|
|
5930
5950
|
if (!result) {
|
|
5931
5951
|
state17.errors += 1;
|
|
5932
|
-
|
|
5952
|
+
api.metrics.counter("audit_errors");
|
|
5953
|
+
api.log.warn("dependency-vulnerability-gate: audit did not complete; install not vetted", {
|
|
5954
|
+
managerHint: "see dependency_audit_status for counters"
|
|
5955
|
+
});
|
|
5956
|
+
return {
|
|
5957
|
+
additionalContext: "\n\u26A0\uFE0F dependency-vulnerability-gate: the package audit could not be completed (timeout or unreadable output), so these dependencies were NOT checked for known vulnerabilities."
|
|
5958
|
+
};
|
|
5933
5959
|
}
|
|
5934
5960
|
state17.auditsRun += 1;
|
|
5935
5961
|
state17.lastResult = {
|
|
@@ -5941,6 +5967,17 @@ var plugin18 = {
|
|
|
5941
5967
|
when: (/* @__PURE__ */ new Date()).toISOString()
|
|
5942
5968
|
};
|
|
5943
5969
|
if (!exceedsThreshold(result.report, cfg.severityThreshold)) {
|
|
5970
|
+
if (result.report.total > 0) {
|
|
5971
|
+
state17.belowThresholdWarns += 1;
|
|
5972
|
+
api.metrics.counter("below_threshold_warns");
|
|
5973
|
+
const belowCounts = Object.entries(result.report.counts).filter(([, count]) => count > 0).map(([sev, count]) => `${sev}: ${count}`).join(", ");
|
|
5974
|
+
return {
|
|
5975
|
+
additionalContext: `
|
|
5976
|
+
\u2139\uFE0F dependency-vulnerability-gate: ${result.manager} audit found vulnerabilities BELOW the configured threshold (${cfg.severityThreshold}); not blocking.
|
|
5977
|
+
Max severity: ${result.report.maxSeverity}
|
|
5978
|
+
Counts: ${belowCounts || "unknown"}`
|
|
5979
|
+
};
|
|
5980
|
+
}
|
|
5944
5981
|
return;
|
|
5945
5982
|
}
|
|
5946
5983
|
const countsText = Object.entries(result.report.counts).filter(([, count]) => count > 0).map(([sev, count]) => `${sev}: ${count}`).join(", ");
|
|
@@ -5982,6 +6019,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
5982
6019
|
auditsRun: state17.auditsRun,
|
|
5983
6020
|
blocks: state17.blocks,
|
|
5984
6021
|
warns: state17.warns,
|
|
6022
|
+
belowThresholdWarns: state17.belowThresholdWarns,
|
|
5985
6023
|
errors: state17.errors
|
|
5986
6024
|
},
|
|
5987
6025
|
lastResult: state17.lastResult
|
|
@@ -6008,6 +6046,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
6008
6046
|
auditsRun: state17.auditsRun,
|
|
6009
6047
|
blocks: state17.blocks,
|
|
6010
6048
|
warns: state17.warns,
|
|
6049
|
+
belowThresholdWarns: state17.belowThresholdWarns,
|
|
6011
6050
|
errors: state17.errors
|
|
6012
6051
|
};
|
|
6013
6052
|
state17.invocations = 0;
|
|
@@ -6015,6 +6054,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
6015
6054
|
state17.auditsRun = 0;
|
|
6016
6055
|
state17.blocks = 0;
|
|
6017
6056
|
state17.warns = 0;
|
|
6057
|
+
state17.belowThresholdWarns = 0;
|
|
6018
6058
|
state17.errors = 0;
|
|
6019
6059
|
state17.lastResult = null;
|
|
6020
6060
|
api.log.info("dependency-vulnerability-gate: teardown complete", { final });
|
|
@@ -6029,6 +6069,7 @@ Review the audit output or adjust the dependency choice.`;
|
|
|
6029
6069
|
auditsRun: state17.auditsRun,
|
|
6030
6070
|
blocks: state17.blocks,
|
|
6031
6071
|
warns: state17.warns,
|
|
6072
|
+
belowThresholdWarns: state17.belowThresholdWarns,
|
|
6032
6073
|
errors: state17.errors
|
|
6033
6074
|
},
|
|
6034
6075
|
lastResult: state17.lastResult
|
|
@@ -13612,7 +13653,7 @@ function stripLauncherAtBoundary(command, launcher, valueTaking) {
|
|
|
13612
13653
|
}
|
|
13613
13654
|
return `${command.slice(0, match.index)}${boundary}${after.slice(consumed).replace(/^\s+/, "")}`;
|
|
13614
13655
|
}
|
|
13615
|
-
var XARGS_OPTIONS = String.raw`(?:\s+(?:(?:-[InLsPjeE]|--(?:arg-file|replace|max-args|max-lines|max-chars|max-procs))\s+[^\s]
|
|
13656
|
+
var XARGS_OPTIONS = String.raw`(?:\s+(?:(?:-[InLsPjeE]|--(?:arg-file|replace|max-args|max-lines|max-chars|max-procs))\s+[^\s-][^\s]*|-[^\s]+))*`;
|
|
13616
13657
|
var COMMAND_BOUNDARY = String.raw`(?:^|[;&|\r\n]\s*|\{\s*|(?<![$(])\(\s*|\bxargs${XARGS_OPTIONS}\s+)`;
|
|
13617
13658
|
function commandRecursivelyDeletes(command) {
|
|
13618
13659
|
const stripped = stripTransparentLaunchers(maskNonExecutingHeredocBodies(command));
|
|
@@ -13944,19 +13985,13 @@ function destructiveTargetsAtDepth(command, depth) {
|
|
|
13944
13985
|
if (destination) targets.push(destination);
|
|
13945
13986
|
c = copy.exec(normalizedCommand);
|
|
13946
13987
|
}
|
|
13947
|
-
const tee = new RegExp(
|
|
13948
|
-
String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(tee)\s+([^;&|\r\n]+)`,
|
|
13949
|
-
"gi"
|
|
13950
|
-
);
|
|
13988
|
+
const tee = new RegExp(String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(tee)\s+([^;&|\r\n]+)`, "gi");
|
|
13951
13989
|
let t = tee.exec(normalizedCommand);
|
|
13952
13990
|
while (t !== null) {
|
|
13953
13991
|
if (!tokenIsQuoted(t, t[1] ?? "")) targets.push(...shellArgs(t[2] ?? ""));
|
|
13954
13992
|
t = tee.exec(normalizedCommand);
|
|
13955
13993
|
}
|
|
13956
|
-
const dd = new RegExp(
|
|
13957
|
-
String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(dd)\s+([^;&|\r\n]+)`,
|
|
13958
|
-
"gi"
|
|
13959
|
-
);
|
|
13994
|
+
const dd = new RegExp(String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(dd)\s+([^;&|\r\n]+)`, "gi");
|
|
13960
13995
|
let d = dd.exec(normalizedCommand);
|
|
13961
13996
|
while (d !== null) {
|
|
13962
13997
|
if (!tokenIsQuoted(d, d[1] ?? "")) {
|
|
@@ -22651,9 +22686,10 @@ var plugin60 = {
|
|
|
22651
22686
|
var todo_listener_default = plugin60;
|
|
22652
22687
|
|
|
22653
22688
|
// src/todo-tracker/index.ts
|
|
22654
|
-
import * as fsp from "node:fs/promises";
|
|
22655
22689
|
import { randomUUID } from "node:crypto";
|
|
22690
|
+
import * as fsp from "node:fs/promises";
|
|
22656
22691
|
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
22692
|
+
import { nowIso } from "@wrongstack/primitives";
|
|
22657
22693
|
function deriveFilePath(api) {
|
|
22658
22694
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
22659
22695
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -22698,9 +22734,6 @@ var state56 = {
|
|
|
22698
22734
|
/** Most recent mutation for /diag plugins visibility. */
|
|
22699
22735
|
lastMutation: null
|
|
22700
22736
|
};
|
|
22701
|
-
function nowIso() {
|
|
22702
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
22703
|
-
}
|
|
22704
22737
|
function ensureFile() {
|
|
22705
22738
|
if (!state56.file) {
|
|
22706
22739
|
state56.file = {
|
package/dist/path-guard.js
CHANGED
|
@@ -505,7 +505,7 @@ function stripLauncherAtBoundary(command, launcher, valueTaking) {
|
|
|
505
505
|
}
|
|
506
506
|
return `${command.slice(0, match.index)}${boundary}${after.slice(consumed).replace(/^\s+/, "")}`;
|
|
507
507
|
}
|
|
508
|
-
var XARGS_OPTIONS = String.raw`(?:\s+(?:(?:-[InLsPjeE]|--(?:arg-file|replace|max-args|max-lines|max-chars|max-procs))\s+[^\s]
|
|
508
|
+
var XARGS_OPTIONS = String.raw`(?:\s+(?:(?:-[InLsPjeE]|--(?:arg-file|replace|max-args|max-lines|max-chars|max-procs))\s+[^\s-][^\s]*|-[^\s]+))*`;
|
|
509
509
|
var COMMAND_BOUNDARY = String.raw`(?:^|[;&|\r\n]\s*|\{\s*|(?<![$(])\(\s*|\bxargs${XARGS_OPTIONS}\s+)`;
|
|
510
510
|
function commandRecursivelyDeletes(command) {
|
|
511
511
|
const stripped = stripTransparentLaunchers(maskNonExecutingHeredocBodies(command));
|
|
@@ -837,19 +837,13 @@ function destructiveTargetsAtDepth(command, depth) {
|
|
|
837
837
|
if (destination) targets.push(destination);
|
|
838
838
|
c = copy.exec(normalizedCommand);
|
|
839
839
|
}
|
|
840
|
-
const tee = new RegExp(
|
|
841
|
-
String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(tee)\s+([^;&|\r\n]+)`,
|
|
842
|
-
"gi"
|
|
843
|
-
);
|
|
840
|
+
const tee = new RegExp(String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(tee)\s+([^;&|\r\n]+)`, "gi");
|
|
844
841
|
let t = tee.exec(normalizedCommand);
|
|
845
842
|
while (t !== null) {
|
|
846
843
|
if (!tokenIsQuoted(t, t[1] ?? "")) targets.push(...shellArgs(t[2] ?? ""));
|
|
847
844
|
t = tee.exec(normalizedCommand);
|
|
848
845
|
}
|
|
849
|
-
const dd = new RegExp(
|
|
850
|
-
String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(dd)\s+([^;&|\r\n]+)`,
|
|
851
|
-
"gi"
|
|
852
|
-
);
|
|
846
|
+
const dd = new RegExp(String.raw`${COMMAND_BOUNDARY}(?:sudo\s+)?(dd)\s+([^;&|\r\n]+)`, "gi");
|
|
853
847
|
let d = dd.exec(normalizedCommand);
|
|
854
848
|
while (d !== null) {
|
|
855
849
|
if (!tokenIsQuoted(d, d[1] ?? "")) {
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* todo-tracker plugin — Persistent, project-scoped todo backlog that
|
|
3
|
+
* survives across sessions.
|
|
4
|
+
*
|
|
5
|
+
* Why a separate plugin from the built-in `todo` tool?
|
|
6
|
+
* - The built-in `todo` tool mutates `ctx.todos`, which is
|
|
7
|
+
* session-scoped and auto-clears when all items complete.
|
|
8
|
+
* - todo-tracker writes to disk (`~/.wrongstack/projects/<slug>/todo-tracker.json`)
|
|
9
|
+
* and survives across sessions. Items are explicit add/complete;
|
|
10
|
+
* no auto-clear.
|
|
11
|
+
*
|
|
12
|
+
* Use cases:
|
|
13
|
+
* - Backlog of work the user wants to track over days/weeks
|
|
14
|
+
* - Items the LLM noticed but didn't finish — pull them into a fresh
|
|
15
|
+
* session via `todo_tracker_pull` (the LLM then registers them with
|
|
16
|
+
* the session's `ctx.todos` via the built-in `todo` tool)
|
|
17
|
+
* - Per-project scratchpad that survives `wstack resume <id>`
|
|
18
|
+
*
|
|
19
|
+
* Tools registered:
|
|
20
|
+
* - todo_tracker_list : List items, filterable by status/tag/priority
|
|
21
|
+
* - todo_tracker_add : Append a new item
|
|
22
|
+
* - todo_tracker_complete : Mark an item completed (idempotent)
|
|
23
|
+
* - todo_tracker_drop : Mark an item dropped (idempotent)
|
|
24
|
+
* - todo_tracker_remove : Permanently delete by id
|
|
25
|
+
* - todo_tracker_pull : Return pending items for LLM to promote
|
|
26
|
+
* into the session's ctx.todos via the
|
|
27
|
+
* built-in `todo` tool
|
|
28
|
+
* - todo_tracker_status : Counters + last update timestamp
|
|
29
|
+
*/
|
|
1
30
|
import type { Plugin } from '@wrongstack/core/types';
|
|
2
31
|
declare const plugin: Plugin;
|
|
3
32
|
export default plugin;
|
package/dist/todo-tracker.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// src/todo-tracker/index.ts
|
|
2
|
-
import * as fsp from "node:fs/promises";
|
|
3
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import * as fsp from "node:fs/promises";
|
|
4
4
|
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
5
|
+
import { nowIso } from "@wrongstack/primitives";
|
|
5
6
|
function deriveFilePath(api) {
|
|
6
7
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
7
8
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -46,9 +47,6 @@ var state = {
|
|
|
46
47
|
/** Most recent mutation for /diag plugins visibility. */
|
|
47
48
|
lastMutation: null
|
|
48
49
|
};
|
|
49
|
-
function nowIso() {
|
|
50
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
51
|
-
}
|
|
52
50
|
function ensureFile() {
|
|
53
51
|
if (!state.file) {
|
|
54
52
|
state.file = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.310.0",
|
|
4
4
|
"description": "Official WrongStack collection of focused plugins for code quality, security, observability, planning, and agent coordination",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -300,12 +300,13 @@
|
|
|
300
300
|
"devDependencies": {
|
|
301
301
|
"@types/node": "^26.2.0",
|
|
302
302
|
"typescript": "^7.0.2",
|
|
303
|
-
"vitest": "^4.1.
|
|
303
|
+
"vitest": "^4.1.11"
|
|
304
304
|
},
|
|
305
305
|
"dependencies": {
|
|
306
|
-
"@wrongstack/
|
|
307
|
-
"@wrongstack/
|
|
308
|
-
"@wrongstack/
|
|
306
|
+
"@wrongstack/core": "0.310.0",
|
|
307
|
+
"@wrongstack/tools": "0.310.0",
|
|
308
|
+
"@wrongstack/primitives": "0.310.0",
|
|
309
|
+
"@wrongstack/plugin-sdk": "0.310.0"
|
|
309
310
|
},
|
|
310
311
|
"scripts": {
|
|
311
312
|
"build": "node ../../scripts/build-package.mjs",
|