@tjamescouch/niki 0.5.6 → 0.5.8
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/bin/niki +39 -1
- package/package.json +1 -1
package/bin/niki
CHANGED
|
@@ -55,12 +55,16 @@ Options:
|
|
|
55
55
|
--max-restarts <n> Max restart attempts, 0=unlimited (default: 0)
|
|
56
56
|
--restart-delay <secs> Delay between restarts with ±30% jitter (default: 5)
|
|
57
57
|
--kill-orphaned-mcp Kill stale agentchat-mcp processes on startup (default: off)
|
|
58
|
+
--on-kill <command> Run shell command when agent is killed (receives context via env vars)
|
|
59
|
+
Env vars: NIKI_KILL_REASON, NIKI_TOKENS, NIKI_BUDGET, NIKI_DURATION,
|
|
60
|
+
NIKI_SENDS, NIKI_TOOL_CALLS, NIKI_PID, NIKI_CMD
|
|
58
61
|
|
|
59
62
|
Examples:
|
|
60
63
|
niki --profile longrun -- gro --persistent --model sonnet
|
|
61
64
|
niki --budget 500000 -- claude -p "your prompt" --verbose
|
|
62
65
|
niki --timeout 1800 --max-sends 5 -- claude -p "..." --model sonnet --verbose
|
|
63
|
-
niki --restart --max-restarts 10 -- gro --model gpt-5.2 "your prompt"
|
|
66
|
+
niki --restart --max-restarts 10 -- gro --model gpt-5.2 "your prompt"
|
|
67
|
+
niki --on-kill 'curl -d "$NIKI_KILL_REASON: $NIKI_TOKENS tokens" ntfy.sh/my-agents' -- claude -p "..."`);
|
|
64
68
|
process.exit(1);
|
|
65
69
|
}
|
|
66
70
|
|
|
@@ -128,6 +132,8 @@ const { values: opts } = parseArgs({
|
|
|
128
132
|
'max-restarts': { type: 'string', default: D["max-restarts"] },
|
|
129
133
|
'restart-delay': { type: 'string', default: D["restart-delay"] },
|
|
130
134
|
'kill-orphaned-mcp': { type: 'boolean', default: false },
|
|
135
|
+
'on-kill': { type: 'string' },
|
|
136
|
+
nick: { type: 'string' },
|
|
131
137
|
},
|
|
132
138
|
});
|
|
133
139
|
|
|
@@ -149,6 +155,7 @@ const RESTART = opts.restart;
|
|
|
149
155
|
const MAX_RESTARTS = parseInt(opts['max-restarts'], 10);
|
|
150
156
|
const RESTART_DELAY_S = parseFloat(opts['restart-delay']);
|
|
151
157
|
const KILL_ORPHANED_MCP = opts['kill-orphaned-mcp'];
|
|
158
|
+
const ON_KILL = opts['on-kill'];
|
|
152
159
|
const LOG_JSON = opts['log-json'];
|
|
153
160
|
|
|
154
161
|
// --- Invocation rate limiting (prevent tight crash loops) ---
|
|
@@ -417,6 +424,35 @@ function checkRateLimits() {
|
|
|
417
424
|
}
|
|
418
425
|
return null;
|
|
419
426
|
}
|
|
427
|
+
// --- Kill notification hook ---
|
|
428
|
+
|
|
429
|
+
function fireOnKill(reason) {
|
|
430
|
+
if (!ON_KILL) return;
|
|
431
|
+
const duration = Math.round((Date.now() - new Date(state.startedAt).getTime()) / 1000);
|
|
432
|
+
const env = {
|
|
433
|
+
...process.env,
|
|
434
|
+
NIKI_KILL_REASON: reason,
|
|
435
|
+
NIKI_TOKENS: String(state.tokensTotal),
|
|
436
|
+
NIKI_BUDGET: String(BUDGET),
|
|
437
|
+
NIKI_DURATION: String(duration),
|
|
438
|
+
NIKI_SENDS: String(state.sendCalls),
|
|
439
|
+
NIKI_TOOL_CALLS: String(state.toolCalls),
|
|
440
|
+
NIKI_PID: String(state.pid),
|
|
441
|
+
NIKI_CMD: childCmd,
|
|
442
|
+
};
|
|
443
|
+
try {
|
|
444
|
+
const hook = spawn('sh', ['-c', ON_KILL], {
|
|
445
|
+
env,
|
|
446
|
+
stdio: 'ignore',
|
|
447
|
+
detached: true,
|
|
448
|
+
});
|
|
449
|
+
hook.unref();
|
|
450
|
+
log(`on-kill hook fired: ${ON_KILL}`, 'debug');
|
|
451
|
+
} catch (err) {
|
|
452
|
+
log(`on-kill hook failed: ${err.message}`, 'warn');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
420
456
|
// --- Kill logic ---
|
|
421
457
|
|
|
422
458
|
let child = null;
|
|
@@ -443,6 +479,8 @@ function killChild(reason) {
|
|
|
443
479
|
}
|
|
444
480
|
log(`KILL — reason: ${reason} | tokens: ${state.tokensTotal}/${BUDGET} | sends: ${state.sendCallsThisMinute}/min | tools: ${state.toolCallsThisMinute}/min`, 'error');
|
|
445
481
|
|
|
482
|
+
fireOnKill(reason);
|
|
483
|
+
|
|
446
484
|
child.kill('SIGTERM');
|
|
447
485
|
|
|
448
486
|
// Grace period, then SIGKILL
|