@wrongstack/plugins 0.295.0 → 0.296.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +31 -3
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-i18n-extractor.js +5 -0
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +116 -3
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +2 -0
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +34 -8
- package/dist/code-metrics.js +5 -0
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +35 -8
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +101 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector/index.d.ts.map +1 -1
- package/dist/dead-code-detector.js +9 -1
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +43 -8
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +112 -2
- package/dist/doc-sync-guard.js +17 -1
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +102 -2
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +30 -4
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +2 -0
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +288 -59
- package/dist/git-autocommit/index.d.ts +12 -0
- package/dist/git-autocommit/index.d.ts.map +1 -1
- package/dist/git-autocommit.js +58 -4
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +152 -21
- package/dist/index.js +1413 -590
- package/dist/injection-shield/index.d.ts +16 -0
- package/dist/injection-shield/index.d.ts.map +1 -1
- package/dist/injection-shield.js +12 -4
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +60 -26
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +115 -2
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +15 -5
- package/dist/migration-planner.js +15 -1
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/pr-drafter/index.d.ts.map +1 -1
- package/dist/pr-drafter.js +20 -1
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +119 -4
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/handles.d.ts +46 -0
- package/dist/runtime/handles.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +309 -22
- package/dist/schema-evolution-guard.js +5 -0
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +194 -50
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +132 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +21 -2
- package/dist/session-recap/index.d.ts.map +1 -1
- package/dist/session-recap.js +18 -1
- package/dist/smart-rename/index.d.ts +2 -0
- package/dist/smart-rename/index.d.ts.map +1 -1
- package/dist/smart-rename.js +16 -2
- package/dist/spec-linker/index.d.ts.map +1 -1
- package/dist/spec-linker.js +19 -2
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +45 -3
- package/dist/test-coverage-gate.js +17 -1
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +142 -9
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +42 -2
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-budget/index.d.ts.map +1 -1
- package/dist/token-budget.js +31 -19
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +108 -17
- package/package.json +3 -3
package/dist/spec-linker.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
// src/spec-linker/index.ts
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
|
|
4
|
+
// src/runtime/local-bin.ts
|
|
5
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
6
|
+
|
|
7
|
+
// src/runtime/handles.ts
|
|
8
|
+
function releaseHandle(off) {
|
|
9
|
+
if (off) {
|
|
10
|
+
try {
|
|
11
|
+
off();
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/runtime/index.ts
|
|
19
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
20
|
+
|
|
4
21
|
// src/manifest/index.ts
|
|
5
22
|
var OFFICIAL_PLUGIN_NAMES = [
|
|
6
23
|
"agent-handoff",
|
|
@@ -330,8 +347,8 @@ var plugin = {
|
|
|
330
347
|
state.skippedNonMd = 0;
|
|
331
348
|
state.readErrorCount = 0;
|
|
332
349
|
state.autoFixApplied = 0;
|
|
333
|
-
state.postHookUnregister =
|
|
334
|
-
state.preHookUnregister =
|
|
350
|
+
state.postHookUnregister = releaseHandle(state.postHookUnregister);
|
|
351
|
+
state.preHookUnregister = releaseHandle(state.preHookUnregister);
|
|
335
352
|
const cfg = readConfig(api.config.extensions?.["spec-linker"]);
|
|
336
353
|
const postHook = async (input) => {
|
|
337
354
|
if (!cfg.enabled) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/template-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/template-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA0IrD,QAAA,MAAM,MAAM,EAAE,MA+Sb,CAAC;eAEa,MAAM"}
|
package/dist/template-engine.js
CHANGED
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
// src/template-engine/index.ts
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { isAbsolute } from "node:path";
|
|
3
|
+
import { isAbsolute as isAbsolute2 } from "node:path";
|
|
4
|
+
|
|
5
|
+
// src/runtime/index.ts
|
|
6
|
+
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/handles.ts
|
|
12
|
+
function releaseHandle(off) {
|
|
13
|
+
if (off) {
|
|
14
|
+
try {
|
|
15
|
+
off();
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/runtime/index.ts
|
|
23
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
24
|
+
function hasLeadingDash(arg) {
|
|
25
|
+
return arg.length > 0 && arg.startsWith("-");
|
|
26
|
+
}
|
|
27
|
+
function withinProjectPath(projectRoot, candidate) {
|
|
28
|
+
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
29
|
+
if (hasLeadingDash(candidate)) return false;
|
|
30
|
+
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
31
|
+
const rel = relative(projectRoot, resolved);
|
|
32
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
33
|
+
}
|
|
34
|
+
function withinProject(p) {
|
|
35
|
+
const cwd = process.cwd();
|
|
36
|
+
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/template-engine/index.ts
|
|
4
40
|
var API_VERSION = "^0.1.10";
|
|
5
41
|
var templates = /* @__PURE__ */ new Map();
|
|
42
|
+
var contributorUnregister = null;
|
|
6
43
|
function expandTemplate(template, variables) {
|
|
7
44
|
let result = template;
|
|
8
45
|
result = result.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
@@ -47,9 +84,12 @@ function renderTemplateRaw(template, variables) {
|
|
|
47
84
|
return result;
|
|
48
85
|
}
|
|
49
86
|
function validateRelativeTemplatePath(field, value) {
|
|
50
|
-
if (
|
|
87
|
+
if (isAbsolute2(value) || value.split(/[\\/]+/).includes("..")) {
|
|
51
88
|
return `${field} must be a relative path without ".." components`;
|
|
52
89
|
}
|
|
90
|
+
if (!withinProject(value)) {
|
|
91
|
+
return `${field} must resolve inside the project directory`;
|
|
92
|
+
}
|
|
53
93
|
return null;
|
|
54
94
|
}
|
|
55
95
|
var plugin = {
|
|
@@ -272,7 +312,8 @@ var plugin = {
|
|
|
272
312
|
};
|
|
273
313
|
}
|
|
274
314
|
});
|
|
275
|
-
|
|
315
|
+
contributorUnregister = releaseHandle(contributorUnregister);
|
|
316
|
+
contributorUnregister = api.registerSystemPromptContributor(async () => [
|
|
276
317
|
{
|
|
277
318
|
type: "text",
|
|
278
319
|
text: `Template engine available:
|
|
@@ -287,6 +328,7 @@ var plugin = {
|
|
|
287
328
|
teardown(api) {
|
|
288
329
|
const count = templates.size;
|
|
289
330
|
templates.clear();
|
|
331
|
+
contributorUnregister = releaseHandle(contributorUnregister);
|
|
290
332
|
api.log.info("template-engine: teardown complete", { cleared: count });
|
|
291
333
|
},
|
|
292
334
|
async health() {
|
|
@@ -3,6 +3,22 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
|
|
4
4
|
// src/runtime/index.ts
|
|
5
5
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
// src/runtime/local-bin.ts
|
|
8
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
9
|
+
|
|
10
|
+
// src/runtime/handles.ts
|
|
11
|
+
function releaseHandle(off) {
|
|
12
|
+
if (off) {
|
|
13
|
+
try {
|
|
14
|
+
off();
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/runtime/index.ts
|
|
6
22
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
7
23
|
function hasLeadingDash(arg) {
|
|
8
24
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -130,7 +146,7 @@ var plugin = {
|
|
|
130
146
|
state.skippedCount = 0;
|
|
131
147
|
state.lastOverallPct = null;
|
|
132
148
|
state.lastResult = null;
|
|
133
|
-
state.hookUnregister =
|
|
149
|
+
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
134
150
|
const cfg = readConfig(api.config.extensions?.["test-coverage-gate"]);
|
|
135
151
|
const hook = (input) => {
|
|
136
152
|
if (!cfg.enabled) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAufrD,QAAA,MAAM,MAAM,EAAE,MA+Tb,CAAC;eAEa,MAAM"}
|
package/dist/test-runner-gate.js
CHANGED
|
@@ -2,9 +2,120 @@
|
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { access } from "node:fs/promises";
|
|
4
4
|
import { basename as basename2, dirname, isAbsolute as isAbsolute2, join } from "node:path";
|
|
5
|
+
import { buildWin32CmdShimInvocation as buildWin32CmdShimInvocation2, resolveWin32Command as resolveWin32Command2 } from "@wrongstack/tools/win32";
|
|
5
6
|
|
|
6
7
|
// src/runtime/index.ts
|
|
7
8
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
9
|
+
|
|
10
|
+
// src/runtime/local-bin.ts
|
|
11
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
12
|
+
|
|
13
|
+
// src/runtime/bounded-map.ts
|
|
14
|
+
var BoundedMap = class {
|
|
15
|
+
map = /* @__PURE__ */ new Map();
|
|
16
|
+
max;
|
|
17
|
+
ttlMs;
|
|
18
|
+
now;
|
|
19
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
20
|
+
evictions = 0;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
const normalizedMax = Math.floor(options.max);
|
|
23
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
24
|
+
this.ttlMs = options.ttlMs;
|
|
25
|
+
this.now = options.now ?? Date.now;
|
|
26
|
+
}
|
|
27
|
+
expired(entry) {
|
|
28
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
29
|
+
}
|
|
30
|
+
get(key) {
|
|
31
|
+
const entry = this.map.get(key);
|
|
32
|
+
if (entry === void 0) return void 0;
|
|
33
|
+
if (this.expired(entry)) {
|
|
34
|
+
this.map.delete(key);
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
this.map.delete(key);
|
|
38
|
+
this.map.set(key, entry);
|
|
39
|
+
return entry.value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
43
|
+
* diagnostics that must not perturb the eviction order.
|
|
44
|
+
*/
|
|
45
|
+
peek(key) {
|
|
46
|
+
const entry = this.map.get(key);
|
|
47
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
48
|
+
return entry.value;
|
|
49
|
+
}
|
|
50
|
+
has(key) {
|
|
51
|
+
const entry = this.map.get(key);
|
|
52
|
+
if (entry === void 0) return false;
|
|
53
|
+
if (this.expired(entry)) {
|
|
54
|
+
this.map.delete(key);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
set(key, value) {
|
|
60
|
+
this.map.delete(key);
|
|
61
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
62
|
+
while (this.map.size > this.max) {
|
|
63
|
+
const coldest = this.map.keys().next().value;
|
|
64
|
+
if (coldest === void 0) break;
|
|
65
|
+
this.map.delete(coldest);
|
|
66
|
+
this.evictions += 1;
|
|
67
|
+
}
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
delete(key) {
|
|
71
|
+
return this.map.delete(key);
|
|
72
|
+
}
|
|
73
|
+
clear() {
|
|
74
|
+
this.map.clear();
|
|
75
|
+
this.evictions = 0;
|
|
76
|
+
}
|
|
77
|
+
get size() {
|
|
78
|
+
return this.map.size;
|
|
79
|
+
}
|
|
80
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
81
|
+
get evictionCount() {
|
|
82
|
+
return this.evictions;
|
|
83
|
+
}
|
|
84
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
85
|
+
prune() {
|
|
86
|
+
if (this.ttlMs === void 0) return 0;
|
|
87
|
+
let removed = 0;
|
|
88
|
+
for (const [key, entry] of this.map) {
|
|
89
|
+
if (this.expired(entry)) {
|
|
90
|
+
this.map.delete(key);
|
|
91
|
+
removed += 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return removed;
|
|
95
|
+
}
|
|
96
|
+
/** Live (non-expired) entries, coldest first. */
|
|
97
|
+
*entries() {
|
|
98
|
+
for (const [key, entry] of this.map) {
|
|
99
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
[Symbol.iterator]() {
|
|
103
|
+
return this.entries();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// src/runtime/handles.ts
|
|
108
|
+
function releaseHandle(off) {
|
|
109
|
+
if (off) {
|
|
110
|
+
try {
|
|
111
|
+
off();
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/runtime/index.ts
|
|
8
119
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
9
120
|
function hasLeadingDash(arg) {
|
|
10
121
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -22,6 +133,15 @@ function withinProject(p) {
|
|
|
22
133
|
}
|
|
23
134
|
|
|
24
135
|
// src/test-runner-gate/index.ts
|
|
136
|
+
function resolveExec(command, args) {
|
|
137
|
+
const resolved = resolveWin32Command2(command);
|
|
138
|
+
const needsShell = process.platform === "win32" && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
139
|
+
if (needsShell) {
|
|
140
|
+
const shim = buildWin32CmdShimInvocation2(resolved, args);
|
|
141
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
142
|
+
}
|
|
143
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
144
|
+
}
|
|
25
145
|
var API_VERSION = "^0.1.10";
|
|
26
146
|
var state = {
|
|
27
147
|
invocationCount: 0,
|
|
@@ -86,7 +206,7 @@ function pathContentHash(content) {
|
|
|
86
206
|
}
|
|
87
207
|
return h >>> 0;
|
|
88
208
|
}
|
|
89
|
-
var lastPassedHash =
|
|
209
|
+
var lastPassedHash = new BoundedMap({ max: 1024 });
|
|
90
210
|
var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
91
211
|
"npx",
|
|
92
212
|
"pnpm",
|
|
@@ -141,10 +261,13 @@ async function detectRunner(requested) {
|
|
|
141
261
|
if (!match) return null;
|
|
142
262
|
try {
|
|
143
263
|
await new Promise((resolve2, reject) => {
|
|
144
|
-
|
|
264
|
+
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
265
|
+
execFile(ex.cmd, ex.args, {
|
|
145
266
|
encoding: "utf-8",
|
|
146
267
|
timeout: 5e3,
|
|
147
|
-
cwd: process.cwd()
|
|
268
|
+
cwd: process.cwd(),
|
|
269
|
+
windowsHide: true,
|
|
270
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
148
271
|
}, (err) => err ? reject(err) : resolve2());
|
|
149
272
|
});
|
|
150
273
|
return match;
|
|
@@ -155,10 +278,13 @@ async function detectRunner(requested) {
|
|
|
155
278
|
for (const candidate of candidates) {
|
|
156
279
|
try {
|
|
157
280
|
await new Promise((resolve2, reject) => {
|
|
158
|
-
|
|
281
|
+
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
282
|
+
execFile(ex.cmd, ex.args, {
|
|
159
283
|
encoding: "utf-8",
|
|
160
284
|
timeout: 5e3,
|
|
161
|
-
cwd: process.cwd()
|
|
285
|
+
cwd: process.cwd(),
|
|
286
|
+
windowsHide: true,
|
|
287
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
162
288
|
}, (err) => err ? reject(err) : resolve2());
|
|
163
289
|
});
|
|
164
290
|
return candidate;
|
|
@@ -206,10 +332,17 @@ async function runTests(testFile, runner, customCommand, timeoutMs) {
|
|
|
206
332
|
try {
|
|
207
333
|
const { stdout: out } = await new Promise(
|
|
208
334
|
(resolve2, reject) => {
|
|
335
|
+
const ex = resolveExec(cmd, fullArgs);
|
|
209
336
|
execFile(
|
|
210
|
-
cmd,
|
|
211
|
-
|
|
212
|
-
{
|
|
337
|
+
ex.cmd,
|
|
338
|
+
ex.args,
|
|
339
|
+
{
|
|
340
|
+
encoding: "utf-8",
|
|
341
|
+
timeout: timeoutMs,
|
|
342
|
+
cwd: process.cwd(),
|
|
343
|
+
windowsHide: true,
|
|
344
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
345
|
+
},
|
|
213
346
|
(err, out2, stderr) => {
|
|
214
347
|
if (err) reject(Object.assign(err, { stdout: out2, stderr }));
|
|
215
348
|
else resolve2({ stdout: out2, stderr });
|
|
@@ -329,7 +462,7 @@ var plugin = {
|
|
|
329
462
|
state.errorCount = 0;
|
|
330
463
|
state.extensionSkippedCount = 0;
|
|
331
464
|
state.cachedSkipCount = 0;
|
|
332
|
-
state.hookUnregister =
|
|
465
|
+
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
333
466
|
state.lastResult = null;
|
|
334
467
|
lastPassedHash.clear();
|
|
335
468
|
const cfg = readConfig(api.config.extensions?.["test-runner-gate"]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-listener/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-listener/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoGrD,QAAA,MAAM,MAAM,EAAE,MAuNb,CAAC;eAEa,MAAM"}
|
package/dist/todo-listener.js
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
// src/runtime/local-bin.ts
|
|
2
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
3
|
+
|
|
4
|
+
// src/runtime/safe-json.ts
|
|
5
|
+
var UNSERIALIZABLE = "[unserializable]";
|
|
6
|
+
function safeJsonStringify(value, indent) {
|
|
7
|
+
try {
|
|
8
|
+
const stack = [];
|
|
9
|
+
const out = JSON.stringify(
|
|
10
|
+
value,
|
|
11
|
+
function replacer(_key, val) {
|
|
12
|
+
if (typeof val === "bigint") return `${val.toString()}n`;
|
|
13
|
+
if (val === null || typeof val !== "object") return val;
|
|
14
|
+
while (stack.length > 0 && stack[stack.length - 1] !== this) stack.pop();
|
|
15
|
+
if (stack.includes(val)) return "[circular]";
|
|
16
|
+
stack.push(val);
|
|
17
|
+
return val;
|
|
18
|
+
},
|
|
19
|
+
indent
|
|
20
|
+
);
|
|
21
|
+
return out ?? String(value);
|
|
22
|
+
} catch {
|
|
23
|
+
return UNSERIALIZABLE;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/runtime/handles.ts
|
|
28
|
+
function releaseHandle(off) {
|
|
29
|
+
if (off) {
|
|
30
|
+
try {
|
|
31
|
+
off();
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/runtime/index.ts
|
|
39
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
40
|
+
|
|
1
41
|
// src/todo-listener/index.ts
|
|
2
42
|
var state = {
|
|
3
43
|
invocationCount: 0,
|
|
@@ -71,7 +111,7 @@ var plugin = {
|
|
|
71
111
|
state.lastMessageId = null;
|
|
72
112
|
state.lastPayloadHash = "";
|
|
73
113
|
state.lastBroadcastAt = 0;
|
|
74
|
-
state.hookUnregister =
|
|
114
|
+
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
75
115
|
const cfg = readConfig(api.config.extensions?.["todo-listener"]);
|
|
76
116
|
const mailbox = api.mailbox;
|
|
77
117
|
const hook = async (input) => {
|
|
@@ -112,7 +152,7 @@ var plugin = {
|
|
|
112
152
|
0,
|
|
113
153
|
200
|
|
114
154
|
);
|
|
115
|
-
const body =
|
|
155
|
+
const body = safeJsonStringify(payload, 2);
|
|
116
156
|
const sendInput = {
|
|
117
157
|
from: `plugin:todo-listener`,
|
|
118
158
|
to: "*",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-tracker/index.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-tracker/index.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAuKrD,QAAA,MAAM,MAAM,EAAE,MAsZb,CAAC;eAEa,MAAM"}
|
package/dist/todo-tracker.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/todo-tracker/index.ts
|
|
2
2
|
import * as fsp from "node:fs/promises";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4
5
|
function deriveFilePath(api) {
|
|
5
6
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
6
7
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -30,10 +31,8 @@ async function loadFile(filePath) {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
async function saveFile(filePath, file) {
|
|
33
|
-
|
|
34
|
-
await
|
|
35
|
-
await fsp.writeFile(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", mode: 384 });
|
|
36
|
-
await fsp.rename(tmp, filePath);
|
|
34
|
+
await ensureDir(filePath.replace(/[/\\][^/\\]+$/, ""));
|
|
35
|
+
await atomicWrite(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
37
36
|
}
|
|
38
37
|
var state = {
|
|
39
38
|
filePath: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-budget/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-budget/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA8HrD,QAAA,MAAM,MAAM,EAAE,MAyQb,CAAC;eAEa,MAAM"}
|
package/dist/token-budget.js
CHANGED
|
@@ -34,16 +34,36 @@ function modelMatches(pattern, model) {
|
|
|
34
34
|
}
|
|
35
35
|
return model.toLowerCase() === pattern.toLowerCase();
|
|
36
36
|
}
|
|
37
|
+
function readBoundedNumber(value, min, max, fallback) {
|
|
38
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
39
|
+
if (value < min || value > max) return fallback;
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
37
42
|
function readConfig(raw) {
|
|
38
43
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
39
44
|
const r = raw;
|
|
45
|
+
const warnPercent = readBoundedNumber(r["warnPercent"], 1, 100, DEFAULTS.warnPercent);
|
|
46
|
+
const stopPercent = readBoundedNumber(r["stopPercent"], 1, 100, DEFAULTS.stopPercent);
|
|
40
47
|
return {
|
|
41
|
-
limit:
|
|
42
|
-
warnPercent
|
|
43
|
-
|
|
48
|
+
limit: readBoundedNumber(r["limit"], 0, Number.MAX_SAFE_INTEGER, DEFAULTS.limit),
|
|
49
|
+
warnPercent,
|
|
50
|
+
// A warn threshold above the stop threshold can never fire — the run
|
|
51
|
+
// stops first. Clamp so the pair always describes a reachable window.
|
|
52
|
+
stopPercent: Math.max(stopPercent, warnPercent),
|
|
44
53
|
model: typeof r["model"] === "string" ? r["model"] : ""
|
|
45
54
|
};
|
|
46
55
|
}
|
|
56
|
+
function clearRegistrations() {
|
|
57
|
+
for (const key of ["hookUnregister", "postHookUnregister"]) {
|
|
58
|
+
const off = state[key];
|
|
59
|
+
if (!off) continue;
|
|
60
|
+
try {
|
|
61
|
+
off();
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
state[key] = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
47
67
|
var plugin = {
|
|
48
68
|
name: "token-budget",
|
|
49
69
|
version: "0.1.0",
|
|
@@ -90,9 +110,8 @@ var plugin = {
|
|
|
90
110
|
state.stopFired = false;
|
|
91
111
|
state.warnContextInjected = false;
|
|
92
112
|
state.stopContextInjected = false;
|
|
93
|
-
state.hookUnregister = null;
|
|
94
|
-
state.postHookUnregister = null;
|
|
95
113
|
state.lastRequest = null;
|
|
114
|
+
clearRegistrations();
|
|
96
115
|
const cfg = readConfig(api.config.extensions?.["token-budget"]);
|
|
97
116
|
api.onEvent("provider.response", (payload) => {
|
|
98
117
|
const p = payload;
|
|
@@ -189,6 +208,12 @@ var plugin = {
|
|
|
189
208
|
remaining,
|
|
190
209
|
percent,
|
|
191
210
|
requestCount: state.requestCount,
|
|
211
|
+
// The EFFECTIVE thresholds, after out-of-range values fall back to
|
|
212
|
+
// the defaults and warn/stop are ordered. Without these the user
|
|
213
|
+
// cannot tell that a rejected or clamped setting is not in force.
|
|
214
|
+
warnPercent: cfg.warnPercent,
|
|
215
|
+
stopPercent: cfg.stopPercent,
|
|
216
|
+
model: cfg.model === "" ? null : cfg.model,
|
|
192
217
|
breakdown: {
|
|
193
218
|
prompt: state.totalPromptTokens,
|
|
194
219
|
completion: state.totalCompletionTokens
|
|
@@ -207,20 +232,7 @@ var plugin = {
|
|
|
207
232
|
});
|
|
208
233
|
},
|
|
209
234
|
teardown(api) {
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
state.hookUnregister();
|
|
213
|
-
} catch {
|
|
214
|
-
}
|
|
215
|
-
state.hookUnregister = null;
|
|
216
|
-
}
|
|
217
|
-
if (state.postHookUnregister) {
|
|
218
|
-
try {
|
|
219
|
-
state.postHookUnregister();
|
|
220
|
-
} catch {
|
|
221
|
-
}
|
|
222
|
-
state.postHookUnregister = null;
|
|
223
|
-
}
|
|
235
|
+
clearRegistrations();
|
|
224
236
|
const final = {
|
|
225
237
|
totalTokens: state.totalTokens,
|
|
226
238
|
requestCount: state.requestCount,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-throttle/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AA8ChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAE5E;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EAAE,EACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,MAAM,CAoBR;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-throttle/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AA8ChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAE5E;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EAAE,EACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,MAAM,CAoBR;AAyED,QAAA,MAAM,MAAM,EAAE,MAqKb,CAAC;eAEa,MAAM"}
|
package/dist/token-throttle.js
CHANGED
|
@@ -60,7 +60,21 @@ function estimateRequestTokens(request, charsPerToken) {
|
|
|
60
60
|
walk(request["messages"]);
|
|
61
61
|
return Math.ceil(chars / charsPerToken);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
function sleep(ms, signal) {
|
|
64
|
+
if (signal?.aborted) return Promise.resolve();
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
signal?.removeEventListener("abort", onAbort);
|
|
68
|
+
resolve();
|
|
69
|
+
}, ms);
|
|
70
|
+
timer.unref?.();
|
|
71
|
+
function onAbort() {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve();
|
|
74
|
+
}
|
|
75
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
64
78
|
var plugin = {
|
|
65
79
|
name: "token-throttle",
|
|
66
80
|
version: "0.1.0",
|
|
@@ -119,6 +133,7 @@ var plugin = {
|
|
|
119
133
|
name: "token-throttle",
|
|
120
134
|
owner: "token-throttle",
|
|
121
135
|
async wrapProviderRunner(_ctx, request, inner) {
|
|
136
|
+
const signal = _ctx?.signal;
|
|
122
137
|
const req = request ?? {};
|
|
123
138
|
state.invocations += 1;
|
|
124
139
|
const now = Date.now();
|
|
@@ -132,7 +147,7 @@ var plugin = {
|
|
|
132
147
|
api.metrics.counter("throttled");
|
|
133
148
|
api.metrics.histogram("delay_ms", delay);
|
|
134
149
|
api.log.info("token-throttle: delaying provider call", { delayMs: delay, projected });
|
|
135
|
-
await sleep(delay);
|
|
150
|
+
await sleep(delay, signal);
|
|
136
151
|
}
|
|
137
152
|
const response = await inner(_ctx, request);
|
|
138
153
|
const used = (response?.usage?.input ?? 0) + (response?.usage?.output ?? 0) || projected;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/type-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/type-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgOrD,QAAA,MAAM,MAAM,EAAE,MAkOb,CAAC;eAEa,MAAM"}
|