@wrongstack/plugins 0.291.0 → 0.291.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * process-guard plugin — prevents the LLM/coding agent from killing active
3
+ * WrongStack processes or their host terminals.
4
+ *
5
+ * Two-layer defense:
6
+ * 1. **Tool-level guards** (primary): `bash-kill-guard.ts` in the bash tool
7
+ * and `exec-kill-guard.ts` in the exec tool intercept kill commands at
8
+ * the tool-execution level, consulting the cross-instance persistent
9
+ * process registry (`~/.wrongstack/process-registry.json`).
10
+ * 2. **This plugin** (observability + configuration layer): provides the
11
+ * `process_guard_status` diagnostic tool, logs all blocked kill attempts,
12
+ * and surfaces protection state to the user via `/process-guard status`.
13
+ *
14
+ * The tool-level guards handle:
15
+ * - taskkill /F /IM node.exe, taskkill /PID X
16
+ * - PowerShell Stop-Process / kill alias
17
+ * - WMIC process ... delete
18
+ * - Script-based kills (kill*.ps1, kill*.sh, etc.)
19
+ * - POSIX kill, pkill, killall
20
+ * - node -e "process.kill(...)" (via exec-kill-guard.ts)
21
+ *
22
+ * Cross-instance protection: the persistent process registry at
23
+ * `~/.wrongstack/process-registry.json` tracks every WrongStack instance's
24
+ * PID, and the tool-level guards read it to determine which PIDs/names are
25
+ * protected. This plugin registers the current process + parent terminal at
26
+ * setup.
27
+ *
28
+ * Config (`config.extensions['process-guard']`):
29
+ * ```jsonc
30
+ * {
31
+ * "enabled": true,
32
+ * "mode": "block" // "block" | "warn" | "off"
33
+ * }
34
+ * ```
35
+ *
36
+ * @public
37
+ */
38
+ import type { Plugin } from '@wrongstack/core';
39
+ declare const plugin: Plugin;
40
+ export default plugin;
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/process-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAiD/C,QAAA,MAAM,MAAM,EAAE,MAoKb,CAAC;eAEa,MAAM"}
@@ -0,0 +1,2 @@
1
+ export * from './process-guard/index.js';
2
+ export { default } from './process-guard/index.js';
@@ -0,0 +1,150 @@
1
+ // src/process-guard/index.ts
2
+ import * as os from "node:os";
3
+ var state = {
4
+ invocations: 0,
5
+ detections: 0,
6
+ warns: 0,
7
+ lastDetection: null,
8
+ hookUnregister: null
9
+ };
10
+ var DEFAULTS = {
11
+ enabled: true,
12
+ mode: "block"
13
+ };
14
+ function readConfig(raw) {
15
+ if (!raw || typeof raw !== "object") return { ...DEFAULTS };
16
+ const r = raw;
17
+ return {
18
+ enabled: r["enabled"] !== false,
19
+ mode: r["mode"] === "warn" ? "warn" : r["mode"] === "off" ? "off" : "block"
20
+ };
21
+ }
22
+ var plugin = {
23
+ name: "process-guard",
24
+ version: "0.1.0",
25
+ description: "Blocks kill commands (taskkill, Stop-Process, kill, pkill, wmic) that target active WrongStack processes or their host terminals.",
26
+ apiVersion: "^0.1.10",
27
+ capabilities: { tools: true, hooks: true },
28
+ defaultConfig: { ...DEFAULTS },
29
+ configSchema: {
30
+ type: "object",
31
+ properties: {
32
+ enabled: { type: "boolean", default: true, description: "Master switch." },
33
+ mode: {
34
+ type: "string",
35
+ enum: ["block", "warn", "off"],
36
+ default: "block",
37
+ description: "block = refuse the operation; warn = inject context; off = disable."
38
+ }
39
+ }
40
+ },
41
+ setup(api) {
42
+ state.invocations = 0;
43
+ state.detections = 0;
44
+ state.warns = 0;
45
+ state.lastDetection = null;
46
+ if (state.hookUnregister) {
47
+ try {
48
+ state.hookUnregister();
49
+ } catch {
50
+ }
51
+ state.hookUnregister = null;
52
+ }
53
+ const cfg = readConfig(api.config.extensions?.["process-guard"]);
54
+ if (cfg.mode === "off") {
55
+ api.log.info("[process-guard] loaded but mode=off \u2014 protection disabled");
56
+ return;
57
+ }
58
+ const hook = (input) => {
59
+ if (!cfg.enabled || cfg.mode === "off") return;
60
+ state.invocations += 1;
61
+ const toolName = input.toolName ?? "";
62
+ if (toolName !== "bash" && toolName !== "exec") return;
63
+ const ti = input.toolInput ?? {};
64
+ const command = typeof ti["command"] === "string" ? ti["command"] : "";
65
+ if (!command) return;
66
+ const cmdLower = command.toLowerCase();
67
+ const isKillRelated = cmdLower.includes("kill") || cmdLower.includes("taskkill") || cmdLower.includes("stop-process") || cmdLower.includes("tskill") || cmdLower.includes("pkill") || cmdLower.includes("killall") || cmdLower.includes("wmic");
68
+ if (!isKillRelated) return;
69
+ state.detections += 1;
70
+ state.lastDetection = {
71
+ target: command.slice(0, 100),
72
+ tool: toolName,
73
+ when: (/* @__PURE__ */ new Date()).toISOString()
74
+ };
75
+ api.metrics.counter("detections");
76
+ api.log.warn?.(
77
+ "[process-guard] kill-related command detected; tool-level guard will evaluate it",
78
+ {
79
+ tool: toolName,
80
+ command: command.slice(0, 200)
81
+ }
82
+ );
83
+ };
84
+ state.hookUnregister = api.registerHook("PreToolUse", "bash|exec", hook, {
85
+ name: "process-guard",
86
+ stage: "validate",
87
+ failurePolicy: "closed",
88
+ policy: true
89
+ });
90
+ api.tools.register({
91
+ name: "process_guard_status",
92
+ description: "Reports process-guard state: mode, counters, and last detected kill-related command.",
93
+ inputSchema: { type: "object", properties: {} },
94
+ permission: "auto",
95
+ category: "Diagnostics",
96
+ mutating: false,
97
+ async execute() {
98
+ return {
99
+ ok: true,
100
+ enabled: cfg.enabled,
101
+ mode: cfg.mode,
102
+ platform: os.platform(),
103
+ selfPid: process.pid,
104
+ parentPid: process.ppid,
105
+ counters: {
106
+ invocations: state.invocations,
107
+ detections: state.detections,
108
+ warns: state.warns
109
+ },
110
+ lastDetection: state.lastDetection
111
+ };
112
+ }
113
+ });
114
+ api.log.info("[process-guard] loaded", {
115
+ version: "0.1.0",
116
+ enabled: cfg.enabled,
117
+ mode: cfg.mode,
118
+ selfPid: process.pid,
119
+ parentPid: process.ppid
120
+ });
121
+ },
122
+ teardown(api) {
123
+ if (state.hookUnregister) {
124
+ try {
125
+ state.hookUnregister();
126
+ } catch {
127
+ }
128
+ state.hookUnregister = null;
129
+ }
130
+ const final = {
131
+ invocations: state.invocations,
132
+ detections: state.detections,
133
+ warns: state.warns
134
+ };
135
+ state.invocations = 0;
136
+ state.detections = 0;
137
+ state.warns = 0;
138
+ api.log.info("[process-guard] teardown complete", { final });
139
+ },
140
+ async health() {
141
+ return {
142
+ ok: true,
143
+ message: state.lastDetection === null ? `process-guard: ${state.invocations} invocation(s), ${state.detections} detection(s), ${state.warns} warn(s)` : `process-guard: last detection on "${state.lastDetection.tool}" at ${state.lastDetection.when}`
144
+ };
145
+ }
146
+ };
147
+ var process_guard_default = plugin;
148
+ export {
149
+ process_guard_default as default
150
+ };