@wrongstack/plugins 0.282.0 → 0.282.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/README.md +2 -2
- package/dist/auto-escalate.d.ts +1 -1
- package/dist/branch-guard.d.ts +6 -5
- package/dist/branch-guard.js +54 -4
- package/dist/context-pins.js +4 -4
- package/dist/cost-tracker.d.ts +1 -1
- package/dist/cost-tracker.js +0 -3
- package/dist/cron.js +18 -8
- package/dist/format-on-save.js +29 -14
- package/dist/index.js +136 -50
- package/dist/plugin-stack-observer.js +31 -18
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @wrongstack/plugins
|
|
2
2
|
|
|
3
3
|
First-party plugin collection for [WrongStack](https://github.com/WrongStack/WrongStack).
|
|
4
|
-
Sixty-
|
|
4
|
+
Sixty-three focused, single-purpose plugins ship in this package. Core safety
|
|
5
5
|
plugins load automatically for every `wstack` session; provider-wire plugins
|
|
6
6
|
are opt-in because they can change model-call semantics.
|
|
7
7
|
|
|
@@ -153,7 +153,7 @@ the full lookup chain.
|
|
|
153
153
|
"cost-tracker": {
|
|
154
154
|
"pricingOverrides": {
|
|
155
155
|
"gpt-4o": { "input": 7, output: 21 },
|
|
156
|
-
"
|
|
156
|
+
"anthropic-test-model": { "input": 4, output: 20 }
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
}
|
package/dist/auto-escalate.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { Plugin } from '@wrongstack/core';
|
|
|
27
27
|
* ```jsonc
|
|
28
28
|
* {
|
|
29
29
|
* "enabled": false,
|
|
30
|
-
* "escalation": ["
|
|
30
|
+
* "escalation": ["provider/model-standard", "provider/model-premium"],
|
|
31
31
|
* "retryablePatterns": ["overload", "rate.?limit", "429", "50[023]", "timeout", "ETIMEDOUT", "ECONNRESET"]
|
|
32
32
|
* }
|
|
33
33
|
* ```
|
package/dist/branch-guard.d.ts
CHANGED
|
@@ -8,17 +8,18 @@ import { Plugin } from '@wrongstack/core';
|
|
|
8
8
|
* - branch_guard_status : Show protected branches, mode, and counters.
|
|
9
9
|
*
|
|
10
10
|
* Hooks registered:
|
|
11
|
-
* - PreToolUse with matcher `bash|git_autocommit`. Inspects the tool
|
|
12
|
-
* input for git commit / push / merge
|
|
13
|
-
* the tool call itself (git_autocommit). If the current
|
|
14
|
-
* protected, the call is blocked with a clear reason.
|
|
11
|
+
* - PreToolUse with matcher `bash|git|git_autocommit`. Inspects the tool
|
|
12
|
+
* input for git commit / push / merge commands (bash), structured git
|
|
13
|
+
* operations (git), or the tool call itself (git_autocommit). If the current
|
|
14
|
+
* branch is protected, the call is blocked with a clear reason.
|
|
15
15
|
*
|
|
16
16
|
* Config (`config.extensions['branch-guard']`):
|
|
17
17
|
*
|
|
18
18
|
* ```jsonc
|
|
19
19
|
* {
|
|
20
|
+
* "enabled": true, // set false to make the hook a no-op
|
|
20
21
|
* "branches": ["main", "master"], // protected branch names
|
|
21
|
-
* "mode": "block", // "block" | "warn"
|
|
22
|
+
* "mode": "block", // "block" | "warn" | "off"
|
|
22
23
|
* "blockMerge": true, // also block merges into protected
|
|
23
24
|
* "blockPush": true, // also block pushes from protected
|
|
24
25
|
* "blockCommit": true // also block commits on protected
|
package/dist/branch-guard.js
CHANGED
|
@@ -7,9 +7,11 @@ var state = {
|
|
|
7
7
|
blockCount: 0,
|
|
8
8
|
warnCount: 0,
|
|
9
9
|
hookUnregister: null,
|
|
10
|
+
configUnregister: null,
|
|
10
11
|
lastBlock: null
|
|
11
12
|
};
|
|
12
13
|
var DEFAULTS = {
|
|
14
|
+
enabled: true,
|
|
13
15
|
branches: ["main", "master"],
|
|
14
16
|
mode: "block",
|
|
15
17
|
blockCommit: true,
|
|
@@ -20,14 +22,36 @@ function readConfig(raw) {
|
|
|
20
22
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
21
23
|
const r = raw;
|
|
22
24
|
const branches = Array.isArray(r["branches"]) ? r["branches"].filter((b) => typeof b === "string") : DEFAULTS.branches;
|
|
25
|
+
const mode = r["mode"] === "warn" ? "warn" : r["mode"] === "off" ? "off" : "block";
|
|
23
26
|
return {
|
|
27
|
+
enabled: r["enabled"] !== false && mode !== "off",
|
|
24
28
|
branches: branches.length > 0 ? branches : DEFAULTS.branches,
|
|
25
|
-
mode
|
|
29
|
+
mode,
|
|
26
30
|
blockCommit: r["blockCommit"] !== false,
|
|
27
31
|
blockPush: r["blockPush"] !== false,
|
|
28
32
|
blockMerge: r["blockMerge"] !== false
|
|
29
33
|
};
|
|
30
34
|
}
|
|
35
|
+
function readHostConfig(raw) {
|
|
36
|
+
const host = raw && typeof raw === "object" ? raw : {};
|
|
37
|
+
const extensions = host["extensions"];
|
|
38
|
+
const branchGuardOptions = extensions && typeof extensions === "object" ? extensions["branch-guard"] : void 0;
|
|
39
|
+
const cfg = readConfig(branchGuardOptions);
|
|
40
|
+
if (hasDisabledPluginEntry(host["plugins"])) {
|
|
41
|
+
return { ...cfg, enabled: false, mode: "off" };
|
|
42
|
+
}
|
|
43
|
+
return cfg;
|
|
44
|
+
}
|
|
45
|
+
function hasDisabledPluginEntry(raw) {
|
|
46
|
+
if (!Array.isArray(raw)) return false;
|
|
47
|
+
return raw.some((entry) => {
|
|
48
|
+
if (!entry || typeof entry !== "object") return false;
|
|
49
|
+
const r = entry;
|
|
50
|
+
if (r["enabled"] !== false) return false;
|
|
51
|
+
const name = typeof r["name"] === "string" ? r["name"] : "";
|
|
52
|
+
return name === "branch-guard" || name === "@wrongstack/plugins/branch-guard";
|
|
53
|
+
});
|
|
54
|
+
}
|
|
31
55
|
function getCurrentBranch(cwd) {
|
|
32
56
|
try {
|
|
33
57
|
const branch = execSync("git branch --show-current", {
|
|
@@ -67,6 +91,16 @@ function detectGitCommand(command) {
|
|
|
67
91
|
}
|
|
68
92
|
return null;
|
|
69
93
|
}
|
|
94
|
+
function detectStructuredGitCommand(input) {
|
|
95
|
+
const command = input["command"];
|
|
96
|
+
if (command === "commit") {
|
|
97
|
+
if (input["dry_run"] === true) return null;
|
|
98
|
+
return { type: "commit", snippet: "git commit" };
|
|
99
|
+
}
|
|
100
|
+
if (command === "push") return { type: "push", snippet: "git push" };
|
|
101
|
+
if (command === "merge") return { type: "merge", snippet: "git merge" };
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
70
104
|
function shouldBlock(op, cfg) {
|
|
71
105
|
if (op === "commit") return cfg.blockCommit;
|
|
72
106
|
if (op === "push") return cfg.blockPush;
|
|
@@ -117,14 +151,18 @@ var plugin = {
|
|
|
117
151
|
state.blockCount = 0;
|
|
118
152
|
state.warnCount = 0;
|
|
119
153
|
state.hookUnregister = null;
|
|
154
|
+
state.configUnregister = null;
|
|
120
155
|
state.lastBlock = null;
|
|
121
|
-
|
|
156
|
+
let cfg = readHostConfig(api.config);
|
|
157
|
+
state.configUnregister = api.onConfigChange((next) => {
|
|
158
|
+
cfg = readHostConfig(next);
|
|
159
|
+
});
|
|
122
160
|
const cwd = typeof process.cwd === "function" ? process.cwd() : void 0;
|
|
123
|
-
const protectedSet = new Set(cfg.branches);
|
|
124
161
|
const hook = (input) => {
|
|
125
162
|
const toolName = input.toolName ?? "";
|
|
126
163
|
const inp = input.toolInput ?? {};
|
|
127
164
|
state.invocationCount += 1;
|
|
165
|
+
if (!cfg.enabled || cfg.mode === "off") return;
|
|
128
166
|
let gitOp = null;
|
|
129
167
|
if (toolName === "git_autocommit") {
|
|
130
168
|
if (inp["dry_run"] === true) return;
|
|
@@ -133,11 +171,14 @@ var plugin = {
|
|
|
133
171
|
const command = inp["command"];
|
|
134
172
|
if (typeof command !== "string") return;
|
|
135
173
|
gitOp = detectGitCommand(command);
|
|
174
|
+
} else if (toolName === "git") {
|
|
175
|
+
gitOp = detectStructuredGitCommand(inp);
|
|
136
176
|
}
|
|
137
177
|
if (!gitOp) return;
|
|
138
178
|
if (!shouldBlock(gitOp.type, cfg)) return;
|
|
139
179
|
const branch = getCurrentBranch(cwd);
|
|
140
180
|
if (!branch) return;
|
|
181
|
+
const protectedSet = new Set(cfg.branches);
|
|
141
182
|
if (!protectedSet.has(branch)) return;
|
|
142
183
|
const when = (/* @__PURE__ */ new Date()).toISOString();
|
|
143
184
|
const opVerb = gitOp.type === "commit" ? "committing to" : gitOp.type === "push" ? "pushing from" : "merging into";
|
|
@@ -174,7 +215,7 @@ var plugin = {
|
|
|
174
215
|
\u26A0\uFE0F branch-guard: you are ${opVerb} protected branch '${branch}'. ` + (hasUncommitted ? `You have uncommitted changes \u2014 consider \`git stash\` before switching branches. ` : "") + `Use a feature branch instead. Protected: ${cfg.branches.join(", ")}.`
|
|
175
216
|
};
|
|
176
217
|
};
|
|
177
|
-
state.hookUnregister = api.registerHook("PreToolUse", "bash|git_autocommit", hook);
|
|
218
|
+
state.hookUnregister = api.registerHook("PreToolUse", "bash|git|git_autocommit", hook);
|
|
178
219
|
api.tools.register({
|
|
179
220
|
name: "branch_guard_status",
|
|
180
221
|
description: "Reports branch-guard state: protected branches, mode, and per-session invocation/block/warn counters.",
|
|
@@ -185,6 +226,7 @@ var plugin = {
|
|
|
185
226
|
async execute() {
|
|
186
227
|
return {
|
|
187
228
|
ok: true,
|
|
229
|
+
enabled: cfg.enabled,
|
|
188
230
|
branches: cfg.branches,
|
|
189
231
|
mode: cfg.mode,
|
|
190
232
|
blockCommit: cfg.blockCommit,
|
|
@@ -201,11 +243,19 @@ var plugin = {
|
|
|
201
243
|
});
|
|
202
244
|
api.log.info("branch-guard plugin loaded", {
|
|
203
245
|
version: "0.1.0",
|
|
246
|
+
enabled: cfg.enabled,
|
|
204
247
|
branches: cfg.branches,
|
|
205
248
|
mode: cfg.mode
|
|
206
249
|
});
|
|
207
250
|
},
|
|
208
251
|
teardown(api) {
|
|
252
|
+
if (state.configUnregister) {
|
|
253
|
+
try {
|
|
254
|
+
state.configUnregister();
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
state.configUnregister = null;
|
|
258
|
+
}
|
|
209
259
|
if (state.hookUnregister) {
|
|
210
260
|
try {
|
|
211
261
|
state.hookUnregister();
|
package/dist/context-pins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as fs from 'fs';
|
|
2
2
|
import { dirname, resolve, isAbsolute, relative } from 'path';
|
|
3
3
|
|
|
4
4
|
// src/context-pins/index.ts
|
|
@@ -38,7 +38,7 @@ function readConfig(raw) {
|
|
|
38
38
|
function loadPins(filePath) {
|
|
39
39
|
if (!filePath) return { pins: [], nextId: 1 };
|
|
40
40
|
try {
|
|
41
|
-
const raw = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
41
|
+
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
42
42
|
const pins = Array.isArray(raw.pins) ? raw.pins.filter(
|
|
43
43
|
(p) => !!p && typeof p === "object" && typeof p.id === "string" && typeof p.text === "string"
|
|
44
44
|
) : [];
|
|
@@ -51,8 +51,8 @@ function loadPins(filePath) {
|
|
|
51
51
|
function persistPins(filePath) {
|
|
52
52
|
if (!filePath) return true;
|
|
53
53
|
try {
|
|
54
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
55
|
-
writeFileSync(filePath, JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2));
|
|
54
|
+
fs.mkdirSync(dirname(filePath), { recursive: true });
|
|
55
|
+
fs.writeFileSync(filePath, JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2));
|
|
56
56
|
return true;
|
|
57
57
|
} catch {
|
|
58
58
|
state.persistErrors += 1;
|
package/dist/cost-tracker.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { Plugin } from '@wrongstack/core';
|
|
|
11
11
|
* "warningThreshold": 80, // percent of budget before warning
|
|
12
12
|
* "pricingOverrides": { // user-supplied per-model rates (USD/1M tokens)
|
|
13
13
|
* "gpt-4o": { "input": 5.0, "output": 15.0 },
|
|
14
|
-
* "
|
|
14
|
+
* "custom-model": { "input": 3.0, "output": 15.0 }
|
|
15
15
|
* }
|
|
16
16
|
* }
|
|
17
17
|
* ```
|
package/dist/cost-tracker.js
CHANGED
|
@@ -6,9 +6,6 @@ var PRICING = {
|
|
|
6
6
|
"gpt-4o": { input: 5, output: 15 },
|
|
7
7
|
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
8
8
|
"gpt-4-turbo": { input: 10, output: 30 },
|
|
9
|
-
"claude-3-5-sonnet": { input: 3, output: 15 },
|
|
10
|
-
"claude-3-5-haiku": { input: 0.8, output: 4 },
|
|
11
|
-
"claude-3-opus": { input: 15, output: 75 },
|
|
12
9
|
"gemini-1.5-pro": { input: 3.5, output: 10.5 },
|
|
13
10
|
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
|
|
14
11
|
default: { input: 5, output: 15 }
|
package/dist/cron.js
CHANGED
|
@@ -4,12 +4,27 @@ var API_VERSION = "^0.1.10";
|
|
|
4
4
|
var state = {
|
|
5
5
|
jobs: /* @__PURE__ */ new Map(),
|
|
6
6
|
timers: /* @__PURE__ */ new Map(),
|
|
7
|
+
extensionUnregister: null,
|
|
7
8
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8
9
|
};
|
|
9
10
|
function formatNextRun(intervalMs) {
|
|
10
11
|
const ms = Number.isNaN(intervalMs) || intervalMs <= 0 ? 6e4 : intervalMs;
|
|
11
12
|
return new Date(Date.now() + ms).toISOString();
|
|
12
13
|
}
|
|
14
|
+
function clearCronResources() {
|
|
15
|
+
for (const timer of state.timers.values()) {
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
}
|
|
18
|
+
state.timers.clear();
|
|
19
|
+
state.jobs.clear();
|
|
20
|
+
if (state.extensionUnregister) {
|
|
21
|
+
try {
|
|
22
|
+
state.extensionUnregister();
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
state.extensionUnregister = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
var plugin = {
|
|
14
29
|
name: "cron",
|
|
15
30
|
version: "0.1.0",
|
|
@@ -30,8 +45,7 @@ var plugin = {
|
|
|
30
45
|
}
|
|
31
46
|
},
|
|
32
47
|
setup(api) {
|
|
33
|
-
|
|
34
|
-
state.timers.clear();
|
|
48
|
+
clearCronResources();
|
|
35
49
|
state.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36
50
|
const maxConcurrent = api.config.extensions?.["cron"]?.["maxConcurrentJobs"] ?? 5;
|
|
37
51
|
function scheduleNextRun(name) {
|
|
@@ -64,7 +78,7 @@ var plugin = {
|
|
|
64
78
|
}
|
|
65
79
|
state.jobs.delete(name);
|
|
66
80
|
}
|
|
67
|
-
api.extensions.register({
|
|
81
|
+
state.extensionUnregister = api.extensions.register({
|
|
68
82
|
name: "cron-iteration-hooks",
|
|
69
83
|
owner: "cron",
|
|
70
84
|
beforeIteration: async (_ctx, _idx) => {
|
|
@@ -216,11 +230,7 @@ var plugin = {
|
|
|
216
230
|
api.log.info("cron plugin loaded", { version: "0.1.0", maxConcurrent });
|
|
217
231
|
},
|
|
218
232
|
teardown(api) {
|
|
219
|
-
|
|
220
|
-
clearTimeout(timer);
|
|
221
|
-
}
|
|
222
|
-
state.timers.clear();
|
|
223
|
-
state.jobs.clear();
|
|
233
|
+
clearCronResources();
|
|
224
234
|
api.log.info("cron plugin unloaded");
|
|
225
235
|
}
|
|
226
236
|
};
|
package/dist/format-on-save.js
CHANGED
|
@@ -27,6 +27,8 @@ var state = {
|
|
|
27
27
|
coveredSkipCount: 0,
|
|
28
28
|
/** Hook handle for teardown. */
|
|
29
29
|
hookUnregister: null,
|
|
30
|
+
/** Cross-plugin event listener handle for teardown. */
|
|
31
|
+
patternUnregister: null,
|
|
30
32
|
/** Last format result — surfaced by health() + status tool. */
|
|
31
33
|
lastResult: null
|
|
32
34
|
};
|
|
@@ -47,6 +49,22 @@ function readConfig(raw) {
|
|
|
47
49
|
};
|
|
48
50
|
}
|
|
49
51
|
var recentlyCovered = /* @__PURE__ */ new Map();
|
|
52
|
+
function clearRegistrations() {
|
|
53
|
+
if (state.hookUnregister) {
|
|
54
|
+
try {
|
|
55
|
+
state.hookUnregister();
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
state.hookUnregister = null;
|
|
59
|
+
}
|
|
60
|
+
if (state.patternUnregister) {
|
|
61
|
+
try {
|
|
62
|
+
state.patternUnregister();
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
state.patternUnregister = null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
50
68
|
function evictExpired(ttlMs) {
|
|
51
69
|
const cutoff = Date.now() - ttlMs;
|
|
52
70
|
for (const [path, ts] of recentlyCovered) {
|
|
@@ -129,12 +147,12 @@ var plugin = {
|
|
|
129
147
|
}
|
|
130
148
|
},
|
|
131
149
|
setup(api) {
|
|
150
|
+
clearRegistrations();
|
|
132
151
|
state.invocationCount = 0;
|
|
133
152
|
state.formattedCount = 0;
|
|
134
153
|
state.cleanCount = 0;
|
|
135
154
|
state.errorCount = 0;
|
|
136
155
|
state.coveredSkipCount = 0;
|
|
137
|
-
state.hookUnregister = null;
|
|
138
156
|
state.lastResult = null;
|
|
139
157
|
recentlyCovered.clear();
|
|
140
158
|
const cfg = readConfig(api.config.extensions?.["format-on-save"]);
|
|
@@ -203,12 +221,15 @@ var plugin = {
|
|
|
203
221
|
return;
|
|
204
222
|
};
|
|
205
223
|
state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook);
|
|
206
|
-
api.onPattern(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
state.patternUnregister = api.onPattern(
|
|
225
|
+
"import-organizer:done",
|
|
226
|
+
(_eventName, payload) => {
|
|
227
|
+
const p = payload ?? {};
|
|
228
|
+
if (typeof p.path !== "string" || p.path.length === 0) return;
|
|
229
|
+
recentlyCovered.set(p.path, Date.now());
|
|
230
|
+
api.metrics.counter("covered_notice");
|
|
231
|
+
}
|
|
232
|
+
);
|
|
212
233
|
api.tools.register({
|
|
213
234
|
name: "format_on_save_status",
|
|
214
235
|
description: "Reports format-on-save state: biome availability, and per-session formatted/clean/error/skipped counters.",
|
|
@@ -242,13 +263,7 @@ var plugin = {
|
|
|
242
263
|
});
|
|
243
264
|
},
|
|
244
265
|
teardown(api) {
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
state.hookUnregister();
|
|
248
|
-
} catch {
|
|
249
|
-
}
|
|
250
|
-
state.hookUnregister = null;
|
|
251
|
-
}
|
|
266
|
+
clearRegistrations();
|
|
252
267
|
const final = {
|
|
253
268
|
invocations: state.invocationCount,
|
|
254
269
|
formatted: state.formattedCount,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname, resolve, extname, isAbsolute, relative, join, basename } from 'path';
|
|
2
2
|
import { execSync, execFileSync, spawn } from 'child_process';
|
|
3
|
+
import * as fs from 'fs';
|
|
3
4
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, watch, readdirSync, mkdtempSync, rmSync } from 'fs';
|
|
4
5
|
import { expectDefined } from '@wrongstack/core';
|
|
5
6
|
import { tmpdir } from 'os';
|
|
@@ -844,9 +845,11 @@ var state4 = {
|
|
|
844
845
|
blockCount: 0,
|
|
845
846
|
warnCount: 0,
|
|
846
847
|
hookUnregister: null,
|
|
848
|
+
configUnregister: null,
|
|
847
849
|
lastBlock: null
|
|
848
850
|
};
|
|
849
851
|
var DEFAULTS2 = {
|
|
852
|
+
enabled: true,
|
|
850
853
|
branches: ["main", "master"],
|
|
851
854
|
mode: "block",
|
|
852
855
|
blockCommit: true,
|
|
@@ -857,14 +860,36 @@ function readConfig3(raw) {
|
|
|
857
860
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS2 };
|
|
858
861
|
const r = raw;
|
|
859
862
|
const branches = Array.isArray(r["branches"]) ? r["branches"].filter((b) => typeof b === "string") : DEFAULTS2.branches;
|
|
863
|
+
const mode = r["mode"] === "warn" ? "warn" : r["mode"] === "off" ? "off" : "block";
|
|
860
864
|
return {
|
|
865
|
+
enabled: r["enabled"] !== false && mode !== "off",
|
|
861
866
|
branches: branches.length > 0 ? branches : DEFAULTS2.branches,
|
|
862
|
-
mode
|
|
867
|
+
mode,
|
|
863
868
|
blockCommit: r["blockCommit"] !== false,
|
|
864
869
|
blockPush: r["blockPush"] !== false,
|
|
865
870
|
blockMerge: r["blockMerge"] !== false
|
|
866
871
|
};
|
|
867
872
|
}
|
|
873
|
+
function readHostConfig(raw) {
|
|
874
|
+
const host = raw && typeof raw === "object" ? raw : {};
|
|
875
|
+
const extensions = host["extensions"];
|
|
876
|
+
const branchGuardOptions = extensions && typeof extensions === "object" ? extensions["branch-guard"] : void 0;
|
|
877
|
+
const cfg = readConfig3(branchGuardOptions);
|
|
878
|
+
if (hasDisabledPluginEntry(host["plugins"])) {
|
|
879
|
+
return { ...cfg, enabled: false, mode: "off" };
|
|
880
|
+
}
|
|
881
|
+
return cfg;
|
|
882
|
+
}
|
|
883
|
+
function hasDisabledPluginEntry(raw) {
|
|
884
|
+
if (!Array.isArray(raw)) return false;
|
|
885
|
+
return raw.some((entry) => {
|
|
886
|
+
if (!entry || typeof entry !== "object") return false;
|
|
887
|
+
const r = entry;
|
|
888
|
+
if (r["enabled"] !== false) return false;
|
|
889
|
+
const name = typeof r["name"] === "string" ? r["name"] : "";
|
|
890
|
+
return name === "branch-guard" || name === "@wrongstack/plugins/branch-guard";
|
|
891
|
+
});
|
|
892
|
+
}
|
|
868
893
|
function getCurrentBranch(cwd) {
|
|
869
894
|
try {
|
|
870
895
|
const branch = execSync("git branch --show-current", {
|
|
@@ -904,6 +929,16 @@ function detectGitCommand(command) {
|
|
|
904
929
|
}
|
|
905
930
|
return null;
|
|
906
931
|
}
|
|
932
|
+
function detectStructuredGitCommand(input) {
|
|
933
|
+
const command = input["command"];
|
|
934
|
+
if (command === "commit") {
|
|
935
|
+
if (input["dry_run"] === true) return null;
|
|
936
|
+
return { type: "commit", snippet: "git commit" };
|
|
937
|
+
}
|
|
938
|
+
if (command === "push") return { type: "push", snippet: "git push" };
|
|
939
|
+
if (command === "merge") return { type: "merge", snippet: "git merge" };
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
907
942
|
function shouldBlock(op, cfg) {
|
|
908
943
|
if (op === "commit") return cfg.blockCommit;
|
|
909
944
|
if (op === "push") return cfg.blockPush;
|
|
@@ -954,14 +989,18 @@ var plugin4 = {
|
|
|
954
989
|
state4.blockCount = 0;
|
|
955
990
|
state4.warnCount = 0;
|
|
956
991
|
state4.hookUnregister = null;
|
|
992
|
+
state4.configUnregister = null;
|
|
957
993
|
state4.lastBlock = null;
|
|
958
|
-
|
|
994
|
+
let cfg = readHostConfig(api.config);
|
|
995
|
+
state4.configUnregister = api.onConfigChange((next) => {
|
|
996
|
+
cfg = readHostConfig(next);
|
|
997
|
+
});
|
|
959
998
|
const cwd = typeof process.cwd === "function" ? process.cwd() : void 0;
|
|
960
|
-
const protectedSet = new Set(cfg.branches);
|
|
961
999
|
const hook = (input) => {
|
|
962
1000
|
const toolName = input.toolName ?? "";
|
|
963
1001
|
const inp = input.toolInput ?? {};
|
|
964
1002
|
state4.invocationCount += 1;
|
|
1003
|
+
if (!cfg.enabled || cfg.mode === "off") return;
|
|
965
1004
|
let gitOp = null;
|
|
966
1005
|
if (toolName === "git_autocommit") {
|
|
967
1006
|
if (inp["dry_run"] === true) return;
|
|
@@ -970,11 +1009,14 @@ var plugin4 = {
|
|
|
970
1009
|
const command = inp["command"];
|
|
971
1010
|
if (typeof command !== "string") return;
|
|
972
1011
|
gitOp = detectGitCommand(command);
|
|
1012
|
+
} else if (toolName === "git") {
|
|
1013
|
+
gitOp = detectStructuredGitCommand(inp);
|
|
973
1014
|
}
|
|
974
1015
|
if (!gitOp) return;
|
|
975
1016
|
if (!shouldBlock(gitOp.type, cfg)) return;
|
|
976
1017
|
const branch = getCurrentBranch(cwd);
|
|
977
1018
|
if (!branch) return;
|
|
1019
|
+
const protectedSet = new Set(cfg.branches);
|
|
978
1020
|
if (!protectedSet.has(branch)) return;
|
|
979
1021
|
const when = (/* @__PURE__ */ new Date()).toISOString();
|
|
980
1022
|
const opVerb = gitOp.type === "commit" ? "committing to" : gitOp.type === "push" ? "pushing from" : "merging into";
|
|
@@ -1011,7 +1053,7 @@ var plugin4 = {
|
|
|
1011
1053
|
\u26A0\uFE0F branch-guard: you are ${opVerb} protected branch '${branch}'. ` + (hasUncommitted ? `You have uncommitted changes \u2014 consider \`git stash\` before switching branches. ` : "") + `Use a feature branch instead. Protected: ${cfg.branches.join(", ")}.`
|
|
1012
1054
|
};
|
|
1013
1055
|
};
|
|
1014
|
-
state4.hookUnregister = api.registerHook("PreToolUse", "bash|git_autocommit", hook);
|
|
1056
|
+
state4.hookUnregister = api.registerHook("PreToolUse", "bash|git|git_autocommit", hook);
|
|
1015
1057
|
api.tools.register({
|
|
1016
1058
|
name: "branch_guard_status",
|
|
1017
1059
|
description: "Reports branch-guard state: protected branches, mode, and per-session invocation/block/warn counters.",
|
|
@@ -1022,6 +1064,7 @@ var plugin4 = {
|
|
|
1022
1064
|
async execute() {
|
|
1023
1065
|
return {
|
|
1024
1066
|
ok: true,
|
|
1067
|
+
enabled: cfg.enabled,
|
|
1025
1068
|
branches: cfg.branches,
|
|
1026
1069
|
mode: cfg.mode,
|
|
1027
1070
|
blockCommit: cfg.blockCommit,
|
|
@@ -1038,11 +1081,19 @@ var plugin4 = {
|
|
|
1038
1081
|
});
|
|
1039
1082
|
api.log.info("branch-guard plugin loaded", {
|
|
1040
1083
|
version: "0.1.0",
|
|
1084
|
+
enabled: cfg.enabled,
|
|
1041
1085
|
branches: cfg.branches,
|
|
1042
1086
|
mode: cfg.mode
|
|
1043
1087
|
});
|
|
1044
1088
|
},
|
|
1045
1089
|
teardown(api) {
|
|
1090
|
+
if (state4.configUnregister) {
|
|
1091
|
+
try {
|
|
1092
|
+
state4.configUnregister();
|
|
1093
|
+
} catch {
|
|
1094
|
+
}
|
|
1095
|
+
state4.configUnregister = null;
|
|
1096
|
+
}
|
|
1046
1097
|
if (state4.hookUnregister) {
|
|
1047
1098
|
try {
|
|
1048
1099
|
state4.hookUnregister();
|
|
@@ -2535,7 +2586,7 @@ function readConfig8(raw) {
|
|
|
2535
2586
|
function loadPins(filePath) {
|
|
2536
2587
|
if (!filePath) return { pins: [], nextId: 1 };
|
|
2537
2588
|
try {
|
|
2538
|
-
const raw = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
2589
|
+
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
2539
2590
|
const pins = Array.isArray(raw.pins) ? raw.pins.filter(
|
|
2540
2591
|
(p) => !!p && typeof p === "object" && typeof p.id === "string" && typeof p.text === "string"
|
|
2541
2592
|
) : [];
|
|
@@ -2548,8 +2599,8 @@ function loadPins(filePath) {
|
|
|
2548
2599
|
function persistPins(filePath) {
|
|
2549
2600
|
if (!filePath) return true;
|
|
2550
2601
|
try {
|
|
2551
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
2552
|
-
writeFileSync(filePath, JSON.stringify({ pins: state9.pins, nextId: state9.nextId }, null, 2));
|
|
2602
|
+
fs.mkdirSync(dirname(filePath), { recursive: true });
|
|
2603
|
+
fs.writeFileSync(filePath, JSON.stringify({ pins: state9.pins, nextId: state9.nextId }, null, 2));
|
|
2553
2604
|
return true;
|
|
2554
2605
|
} catch {
|
|
2555
2606
|
state9.persistErrors += 1;
|
|
@@ -2747,9 +2798,6 @@ var PRICING = {
|
|
|
2747
2798
|
"gpt-4o": { input: 5, output: 15 },
|
|
2748
2799
|
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
2749
2800
|
"gpt-4-turbo": { input: 10, output: 30 },
|
|
2750
|
-
"claude-3-5-sonnet": { input: 3, output: 15 },
|
|
2751
|
-
"claude-3-5-haiku": { input: 0.8, output: 4 },
|
|
2752
|
-
"claude-3-opus": { input: 15, output: 75 },
|
|
2753
2801
|
"gemini-1.5-pro": { input: 3.5, output: 10.5 },
|
|
2754
2802
|
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
|
|
2755
2803
|
default: { input: 5, output: 15 }
|
|
@@ -3110,12 +3158,27 @@ var API_VERSION5 = "^0.1.10";
|
|
|
3110
3158
|
var state10 = {
|
|
3111
3159
|
jobs: /* @__PURE__ */ new Map(),
|
|
3112
3160
|
timers: /* @__PURE__ */ new Map(),
|
|
3161
|
+
extensionUnregister: null,
|
|
3113
3162
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3114
3163
|
};
|
|
3115
3164
|
function formatNextRun(intervalMs) {
|
|
3116
3165
|
const ms = Number.isNaN(intervalMs) || intervalMs <= 0 ? 6e4 : intervalMs;
|
|
3117
3166
|
return new Date(Date.now() + ms).toISOString();
|
|
3118
3167
|
}
|
|
3168
|
+
function clearCronResources() {
|
|
3169
|
+
for (const timer of state10.timers.values()) {
|
|
3170
|
+
clearTimeout(timer);
|
|
3171
|
+
}
|
|
3172
|
+
state10.timers.clear();
|
|
3173
|
+
state10.jobs.clear();
|
|
3174
|
+
if (state10.extensionUnregister) {
|
|
3175
|
+
try {
|
|
3176
|
+
state10.extensionUnregister();
|
|
3177
|
+
} catch {
|
|
3178
|
+
}
|
|
3179
|
+
state10.extensionUnregister = null;
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3119
3182
|
var plugin11 = {
|
|
3120
3183
|
name: "cron",
|
|
3121
3184
|
version: "0.1.0",
|
|
@@ -3136,8 +3199,7 @@ var plugin11 = {
|
|
|
3136
3199
|
}
|
|
3137
3200
|
},
|
|
3138
3201
|
setup(api) {
|
|
3139
|
-
|
|
3140
|
-
state10.timers.clear();
|
|
3202
|
+
clearCronResources();
|
|
3141
3203
|
state10.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3142
3204
|
const maxConcurrent = api.config.extensions?.["cron"]?.["maxConcurrentJobs"] ?? 5;
|
|
3143
3205
|
function scheduleNextRun(name) {
|
|
@@ -3170,7 +3232,7 @@ var plugin11 = {
|
|
|
3170
3232
|
}
|
|
3171
3233
|
state10.jobs.delete(name);
|
|
3172
3234
|
}
|
|
3173
|
-
api.extensions.register({
|
|
3235
|
+
state10.extensionUnregister = api.extensions.register({
|
|
3174
3236
|
name: "cron-iteration-hooks",
|
|
3175
3237
|
owner: "cron",
|
|
3176
3238
|
beforeIteration: async (_ctx, _idx) => {
|
|
@@ -3322,11 +3384,7 @@ var plugin11 = {
|
|
|
3322
3384
|
api.log.info("cron plugin loaded", { version: "0.1.0", maxConcurrent });
|
|
3323
3385
|
},
|
|
3324
3386
|
teardown(api) {
|
|
3325
|
-
|
|
3326
|
-
clearTimeout(timer);
|
|
3327
|
-
}
|
|
3328
|
-
state10.timers.clear();
|
|
3329
|
-
state10.jobs.clear();
|
|
3387
|
+
clearCronResources();
|
|
3330
3388
|
api.log.info("cron plugin unloaded");
|
|
3331
3389
|
}
|
|
3332
3390
|
};
|
|
@@ -4617,6 +4675,8 @@ var state14 = {
|
|
|
4617
4675
|
coveredSkipCount: 0,
|
|
4618
4676
|
/** Hook handle for teardown. */
|
|
4619
4677
|
hookUnregister: null,
|
|
4678
|
+
/** Cross-plugin event listener handle for teardown. */
|
|
4679
|
+
patternUnregister: null,
|
|
4620
4680
|
/** Last format result — surfaced by health() + status tool. */
|
|
4621
4681
|
lastResult: null
|
|
4622
4682
|
};
|
|
@@ -4637,6 +4697,22 @@ function readConfig12(raw) {
|
|
|
4637
4697
|
};
|
|
4638
4698
|
}
|
|
4639
4699
|
var recentlyCovered = /* @__PURE__ */ new Map();
|
|
4700
|
+
function clearRegistrations() {
|
|
4701
|
+
if (state14.hookUnregister) {
|
|
4702
|
+
try {
|
|
4703
|
+
state14.hookUnregister();
|
|
4704
|
+
} catch {
|
|
4705
|
+
}
|
|
4706
|
+
state14.hookUnregister = null;
|
|
4707
|
+
}
|
|
4708
|
+
if (state14.patternUnregister) {
|
|
4709
|
+
try {
|
|
4710
|
+
state14.patternUnregister();
|
|
4711
|
+
} catch {
|
|
4712
|
+
}
|
|
4713
|
+
state14.patternUnregister = null;
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4640
4716
|
function evictExpired(ttlMs) {
|
|
4641
4717
|
const cutoff = Date.now() - ttlMs;
|
|
4642
4718
|
for (const [path, ts] of recentlyCovered) {
|
|
@@ -4719,12 +4795,12 @@ var plugin16 = {
|
|
|
4719
4795
|
}
|
|
4720
4796
|
},
|
|
4721
4797
|
setup(api) {
|
|
4798
|
+
clearRegistrations();
|
|
4722
4799
|
state14.invocationCount = 0;
|
|
4723
4800
|
state14.formattedCount = 0;
|
|
4724
4801
|
state14.cleanCount = 0;
|
|
4725
4802
|
state14.errorCount = 0;
|
|
4726
4803
|
state14.coveredSkipCount = 0;
|
|
4727
|
-
state14.hookUnregister = null;
|
|
4728
4804
|
state14.lastResult = null;
|
|
4729
4805
|
recentlyCovered.clear();
|
|
4730
4806
|
const cfg = readConfig12(api.config.extensions?.["format-on-save"]);
|
|
@@ -4793,12 +4869,15 @@ var plugin16 = {
|
|
|
4793
4869
|
return;
|
|
4794
4870
|
};
|
|
4795
4871
|
state14.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook);
|
|
4796
|
-
api.onPattern(
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4872
|
+
state14.patternUnregister = api.onPattern(
|
|
4873
|
+
"import-organizer:done",
|
|
4874
|
+
(_eventName, payload) => {
|
|
4875
|
+
const p = payload ?? {};
|
|
4876
|
+
if (typeof p.path !== "string" || p.path.length === 0) return;
|
|
4877
|
+
recentlyCovered.set(p.path, Date.now());
|
|
4878
|
+
api.metrics.counter("covered_notice");
|
|
4879
|
+
}
|
|
4880
|
+
);
|
|
4802
4881
|
api.tools.register({
|
|
4803
4882
|
name: "format_on_save_status",
|
|
4804
4883
|
description: "Reports format-on-save state: biome availability, and per-session formatted/clean/error/skipped counters.",
|
|
@@ -4832,13 +4911,7 @@ var plugin16 = {
|
|
|
4832
4911
|
});
|
|
4833
4912
|
},
|
|
4834
4913
|
teardown(api) {
|
|
4835
|
-
|
|
4836
|
-
try {
|
|
4837
|
-
state14.hookUnregister();
|
|
4838
|
-
} catch {
|
|
4839
|
-
}
|
|
4840
|
-
state14.hookUnregister = null;
|
|
4841
|
-
}
|
|
4914
|
+
clearRegistrations();
|
|
4842
4915
|
const final = {
|
|
4843
4916
|
invocations: state14.invocationCount,
|
|
4844
4917
|
formatted: state14.formattedCount,
|
|
@@ -8018,8 +8091,20 @@ var path_guard_default = plugin26;
|
|
|
8018
8091
|
// src/plugin-stack-observer/index.ts
|
|
8019
8092
|
var state24 = {
|
|
8020
8093
|
wraps: [],
|
|
8021
|
-
contributions: 0
|
|
8094
|
+
contributions: 0,
|
|
8095
|
+
patternUnregister: null
|
|
8022
8096
|
};
|
|
8097
|
+
function clearObserverState() {
|
|
8098
|
+
if (state24.patternUnregister) {
|
|
8099
|
+
try {
|
|
8100
|
+
state24.patternUnregister();
|
|
8101
|
+
} catch {
|
|
8102
|
+
}
|
|
8103
|
+
state24.patternUnregister = null;
|
|
8104
|
+
}
|
|
8105
|
+
state24.wraps = [];
|
|
8106
|
+
state24.contributions = 0;
|
|
8107
|
+
}
|
|
8023
8108
|
var PLUGIN = {
|
|
8024
8109
|
name: "plugin-stack-observer",
|
|
8025
8110
|
version: "0.1.0",
|
|
@@ -8047,26 +8132,28 @@ var PLUGIN = {
|
|
|
8047
8132
|
}
|
|
8048
8133
|
},
|
|
8049
8134
|
setup(api) {
|
|
8050
|
-
|
|
8051
|
-
state24.contributions = 0;
|
|
8135
|
+
clearObserverState();
|
|
8052
8136
|
const cfg = readConfig22(api.config.extensions?.["plugin-stack-observer"]);
|
|
8053
8137
|
if (!cfg.enabled) {
|
|
8054
8138
|
api.log.info("plugin-stack-observer loaded (disabled)");
|
|
8055
8139
|
return;
|
|
8056
8140
|
}
|
|
8057
|
-
api.onPattern(
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8141
|
+
state24.patternUnregister = api.onPattern(
|
|
8142
|
+
"provider.wrap:loaded",
|
|
8143
|
+
(_eventName, payload) => {
|
|
8144
|
+
const p = payload ?? {};
|
|
8145
|
+
if (typeof p.plugin !== "string" || p.plugin.length === 0) return;
|
|
8146
|
+
const wraps = Array.isArray(p.wraps) ? p.wraps.filter((w) => typeof w === "string") : [];
|
|
8147
|
+
const kind = typeof p.kind === "string" ? p.kind : "unknown";
|
|
8148
|
+
state24.wraps.push({
|
|
8149
|
+
plugin: p.plugin,
|
|
8150
|
+
kind,
|
|
8151
|
+
wraps,
|
|
8152
|
+
loadedAt: Date.now()
|
|
8153
|
+
});
|
|
8154
|
+
api.metrics.counter("wrap_loaded");
|
|
8155
|
+
}
|
|
8156
|
+
);
|
|
8070
8157
|
if (cfg.injectIntoSystemPrompt) {
|
|
8071
8158
|
api.registerSystemPromptContributor(async () => {
|
|
8072
8159
|
if (state24.wraps.length === 0) return [];
|
|
@@ -8114,8 +8201,7 @@ Any failure or latency above is attributable to one of the above.`
|
|
|
8114
8201
|
wrapCount: state24.wraps.length,
|
|
8115
8202
|
contributions: state24.contributions
|
|
8116
8203
|
};
|
|
8117
|
-
|
|
8118
|
-
state24.contributions = 0;
|
|
8204
|
+
clearObserverState();
|
|
8119
8205
|
api.log.info("plugin-stack-observer: teardown complete", { final });
|
|
8120
8206
|
},
|
|
8121
8207
|
async health() {
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
// src/plugin-stack-observer/index.ts
|
|
2
2
|
var state = {
|
|
3
3
|
wraps: [],
|
|
4
|
-
contributions: 0
|
|
4
|
+
contributions: 0,
|
|
5
|
+
patternUnregister: null
|
|
5
6
|
};
|
|
7
|
+
function clearObserverState() {
|
|
8
|
+
if (state.patternUnregister) {
|
|
9
|
+
try {
|
|
10
|
+
state.patternUnregister();
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
state.patternUnregister = null;
|
|
14
|
+
}
|
|
15
|
+
state.wraps = [];
|
|
16
|
+
state.contributions = 0;
|
|
17
|
+
}
|
|
6
18
|
var PLUGIN = {
|
|
7
19
|
name: "plugin-stack-observer",
|
|
8
20
|
version: "0.1.0",
|
|
@@ -30,26 +42,28 @@ var PLUGIN = {
|
|
|
30
42
|
}
|
|
31
43
|
},
|
|
32
44
|
setup(api) {
|
|
33
|
-
|
|
34
|
-
state.contributions = 0;
|
|
45
|
+
clearObserverState();
|
|
35
46
|
const cfg = readConfig(api.config.extensions?.["plugin-stack-observer"]);
|
|
36
47
|
if (!cfg.enabled) {
|
|
37
48
|
api.log.info("plugin-stack-observer loaded (disabled)");
|
|
38
49
|
return;
|
|
39
50
|
}
|
|
40
|
-
api.onPattern(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
state.patternUnregister = api.onPattern(
|
|
52
|
+
"provider.wrap:loaded",
|
|
53
|
+
(_eventName, payload) => {
|
|
54
|
+
const p = payload ?? {};
|
|
55
|
+
if (typeof p.plugin !== "string" || p.plugin.length === 0) return;
|
|
56
|
+
const wraps = Array.isArray(p.wraps) ? p.wraps.filter((w) => typeof w === "string") : [];
|
|
57
|
+
const kind = typeof p.kind === "string" ? p.kind : "unknown";
|
|
58
|
+
state.wraps.push({
|
|
59
|
+
plugin: p.plugin,
|
|
60
|
+
kind,
|
|
61
|
+
wraps,
|
|
62
|
+
loadedAt: Date.now()
|
|
63
|
+
});
|
|
64
|
+
api.metrics.counter("wrap_loaded");
|
|
65
|
+
}
|
|
66
|
+
);
|
|
53
67
|
if (cfg.injectIntoSystemPrompt) {
|
|
54
68
|
api.registerSystemPromptContributor(async () => {
|
|
55
69
|
if (state.wraps.length === 0) return [];
|
|
@@ -97,8 +111,7 @@ Any failure or latency above is attributable to one of the above.`
|
|
|
97
111
|
wrapCount: state.wraps.length,
|
|
98
112
|
contributions: state.contributions
|
|
99
113
|
};
|
|
100
|
-
|
|
101
|
-
state.contributions = 0;
|
|
114
|
+
clearObserverState();
|
|
102
115
|
api.log.info("plugin-stack-observer: teardown complete", { final });
|
|
103
116
|
},
|
|
104
117
|
async health() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.282.
|
|
3
|
+
"version": "0.282.2",
|
|
4
4
|
"description": "Official WrongStack plugin collection — 62 focused, single-purpose plugins for code quality, security, observability, planning, and agent coordination",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -275,8 +275,8 @@
|
|
|
275
275
|
"vitest": "^4.1.9"
|
|
276
276
|
},
|
|
277
277
|
"dependencies": {
|
|
278
|
-
"@wrongstack/core": "0.282.
|
|
279
|
-
"@wrongstack/tools": "0.282.
|
|
278
|
+
"@wrongstack/core": "0.282.2",
|
|
279
|
+
"@wrongstack/tools": "0.282.2"
|
|
280
280
|
},
|
|
281
281
|
"scripts": {
|
|
282
282
|
"build": "tsup",
|