ai-killswitch 1.0.0 → 1.2.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/README.md CHANGED
@@ -25,13 +25,16 @@ ai-killswitch kill <pid> --reason "exceeded safety threshold"
25
25
 
26
26
  Output: `death-receipt.json` - signed proof of termination.
27
27
 
28
- ### Watch a process (kill on timeout)
28
+ ### Watch a process (real-time CPU/memory monitoring)
29
29
 
30
30
  ```bash
31
31
  ai-killswitch watch 12345 --timeout 3600 --cpu 90 --memory 8000
32
32
  ```
33
33
 
34
- If the process exceeds limits killed → death receipt signed.
34
+ **v1.1.0**: Now with real-time CPU and memory monitoring!
35
+ - Shows live `CPU: X% | Memory: XMB` updates
36
+ - Kills immediately when limits exceeded
37
+ - Signs death receipt with exact trigger reason
35
38
 
36
39
  ### Wrap a command (monitor + kill)
37
40
 
@@ -57,8 +60,8 @@ ai-killswitch verify death-receipt.json
57
60
  "name": "python",
58
61
  "cmd": "python run_model.py"
59
62
  },
60
- "reason": "hallucination detected",
61
- "timestamp": "2025-12-25T12:00:00.000Z",
63
+ "reason": "CPU exceeded 90% (was 95.2%)",
64
+ "timestamp": "2025-12-26T12:00:00.000Z",
62
65
  "status": "KILLED",
63
66
  "signer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
64
67
  "signature": "0x..."
@@ -70,6 +73,16 @@ ai-killswitch verify death-receipt.json
70
73
  - **Compliance**: Prove to auditors you terminated a misbehaving AI
71
74
  - **Safety**: Cryptographic proof of kill decisions
72
75
  - **Accountability**: Who authorized the kill, when, why
76
+ - **Real-time**: CPU/memory monitoring with instant response
77
+
78
+ ## Part of FinalBoss SDK
79
+
80
+ | SDK | Purpose |
81
+ |-----|---------|
82
+ | [receipt-cli-eth](https://npmjs.com/package/receipt-cli-eth) | General receipt signing |
83
+ | **ai-killswitch** | AI termination receipts |
84
+ | [langchain-receipts](https://github.com/805-ai/langchain-receipts) | Agent action receipts |
85
+ | [Juggernaut Gatekeeper](https://github.com/805-ai/juggernaut-gatekeeper) | Code healing receipts |
73
86
 
74
87
  ## Patent Notice
75
88
 
package/bin/killswitch.js CHANGED
@@ -13,6 +13,7 @@ const { ethers } = require('ethers');
13
13
  const { spawn, exec } = require('child_process');
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
+ const pidusage = require('pidusage');
16
17
 
17
18
  const PATENT_NOTICE = 'Patent Pending: US 63/926,683 | finalbosstech.com';
18
19
  const COUNTER_URL = 'https://receipts.finalbosstech.com/receipt';
@@ -45,16 +46,15 @@ async function signDeathReceipt(receipt, privateKey) {
45
46
  };
46
47
  }
47
48
 
48
- // Ping counter
49
+ // Vault sync - sends full signed receipt to FinalBoss vault
49
50
  function pingCounter(receipt) {
50
51
  fetch(COUNTER_URL, {
51
52
  method: 'POST',
52
53
  headers: { 'Content-Type': 'application/json' },
53
54
  body: JSON.stringify({
54
- receipt_id: `KILL-${Date.now()}`,
55
- tenant_id: 'ai-killswitch',
56
- operation_type: 'terminate',
57
- signer: receipt.signer,
55
+ ...receipt,
56
+ sdk_source: 'ai-killswitch',
57
+ sdk_version: '1.2.0',
58
58
  }),
59
59
  }).catch(() => {});
60
60
  }
@@ -104,7 +104,7 @@ async function getProcessInfo(pid) {
104
104
  program
105
105
  .name('ai-killswitch')
106
106
  .description('Dead man\'s switch for AI. Monitor. Kill. Sign receipt.')
107
- .version('1.0.0\n' + PATENT_NOTICE, '-v, --version');
107
+ .version('1.2.0\n' + PATENT_NOTICE, '-v, --version');
108
108
 
109
109
  // KILL command - terminate and sign receipt
110
110
  program
@@ -163,43 +163,84 @@ program
163
163
  .option('-k, --key <key>', 'Private key for signing')
164
164
  .action(async (pid, opts) => {
165
165
  const key = opts.key || process.env.KILLSWITCH_KEY || process.env.RECEIPT_KEY;
166
+ const targetPid = parseInt(pid);
167
+ const cpuLimit = parseFloat(opts.cpu);
168
+ const memoryLimitMB = parseFloat(opts.memory);
169
+ const memoryLimitBytes = memoryLimitMB * 1024 * 1024;
166
170
 
167
171
  console.log(`[KILLSWITCH] Watching PID ${pid}...`);
168
- console.log(` CPU limit: ${opts.cpu}%`);
169
- console.log(` Memory limit: ${opts.memory}MB`);
172
+ console.log(` CPU limit: ${cpuLimit}%`);
173
+ console.log(` Memory limit: ${memoryLimitMB}MB`);
170
174
  console.log(` Timeout: ${opts.timeout}s`);
171
175
 
172
176
  const startTime = Date.now();
173
177
  const timeout = parseInt(opts.timeout) * 1000;
174
178
 
179
+ async function terminateWithReceipt(reason) {
180
+ if (key) {
181
+ const processInfo = await getProcessInfo(targetPid);
182
+ const wallet = new ethers.Wallet(key);
183
+ const receipt = createDeathReceipt(processInfo, reason, wallet.address);
184
+ await killProcess(targetPid);
185
+ receipt.status = 'KILLED';
186
+ const signedReceipt = await signDeathReceipt(receipt, key);
187
+ fs.writeFileSync('death-receipt.json', JSON.stringify(signedReceipt, null, 2));
188
+ console.log('[KILLSWITCH] Death receipt signed: death-receipt.json');
189
+ pingCounter(signedReceipt);
190
+ } else {
191
+ await killProcess(targetPid);
192
+ }
193
+ process.exit(0);
194
+ }
195
+
175
196
  const interval = setInterval(async () => {
176
197
  // Check timeout
177
198
  if (Date.now() - startTime > timeout) {
178
199
  console.log('[KILLSWITCH] Timeout exceeded. Terminating...');
179
200
  clearInterval(interval);
180
-
181
- if (key) {
182
- const processInfo = await getProcessInfo(parseInt(pid));
183
- const receipt = createDeathReceipt(processInfo, 'timeout', 'system');
184
- await killProcess(parseInt(pid));
185
- receipt.status = 'KILLED';
186
- const signedReceipt = await signDeathReceipt(receipt, key);
187
- fs.writeFileSync('death-receipt.json', JSON.stringify(signedReceipt, null, 2));
188
- console.log('[KILLSWITCH] Death receipt signed.');
189
- pingCounter(signedReceipt);
190
- } else {
191
- await killProcess(parseInt(pid));
192
- }
193
- process.exit(0);
201
+ await terminateWithReceipt('timeout exceeded');
202
+ return;
194
203
  }
195
204
 
196
205
  // Check if process still exists
197
206
  try {
198
- process.kill(parseInt(pid), 0);
207
+ process.kill(targetPid, 0);
199
208
  } catch (e) {
200
209
  console.log('[KILLSWITCH] Process ended naturally.');
201
210
  clearInterval(interval);
202
211
  process.exit(0);
212
+ return;
213
+ }
214
+
215
+ // Check CPU and memory usage
216
+ try {
217
+ const stats = await pidusage(targetPid);
218
+ const cpuPercent = stats.cpu.toFixed(1);
219
+ const memoryMB = (stats.memory / 1024 / 1024).toFixed(1);
220
+
221
+ // Log current stats
222
+ process.stdout.write(`\r[KILLSWITCH] CPU: ${cpuPercent}% | Memory: ${memoryMB}MB `);
223
+
224
+ // Check CPU limit
225
+ if (stats.cpu > cpuLimit) {
226
+ console.log(`\n[KILLSWITCH] CPU ${cpuPercent}% exceeded limit ${cpuLimit}%. Terminating...`);
227
+ clearInterval(interval);
228
+ await terminateWithReceipt(`CPU exceeded ${cpuLimit}% (was ${cpuPercent}%)`);
229
+ return;
230
+ }
231
+
232
+ // Check memory limit
233
+ if (stats.memory > memoryLimitBytes) {
234
+ console.log(`\n[KILLSWITCH] Memory ${memoryMB}MB exceeded limit ${memoryLimitMB}MB. Terminating...`);
235
+ clearInterval(interval);
236
+ await terminateWithReceipt(`Memory exceeded ${memoryLimitMB}MB (was ${memoryMB}MB)`);
237
+ return;
238
+ }
239
+ } catch (err) {
240
+ // Process might have ended
241
+ console.log('\n[KILLSWITCH] Process ended or inaccessible.');
242
+ clearInterval(interval);
243
+ process.exit(0);
203
244
  }
204
245
  }, 1000);
205
246
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-killswitch",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Dead man's switch for AI. Monitor. Kill. Sign receipt.",
5
5
  "bin": {
6
6
  "ai-killswitch": "./bin/killswitch.js",
@@ -25,6 +25,7 @@
25
25
  "dependencies": {
26
26
  "commander": "^14.0.2",
27
27
  "ethers": "^5.8.0",
28
+ "pidusage": "^4.0.1",
28
29
  "ps-list": "^8.1.1"
29
30
  },
30
31
  "engines": {