kimaki 0.4.58 → 0.4.60
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.js +1 -1
- package/dist/bin.js +68 -0
- package/dist/cli-parsing.test.js +50 -0
- package/dist/cli.js +611 -163
- package/dist/commands/abort.js +5 -6
- package/dist/commands/agent.js +35 -2
- package/dist/commands/compact.js +9 -9
- package/dist/commands/diff.js +7 -11
- package/dist/commands/file-upload.js +276 -0
- package/dist/commands/fork.js +8 -6
- package/dist/commands/merge-worktree.js +82 -212
- package/dist/commands/permissions.js +30 -2
- package/dist/commands/queue.js +5 -6
- package/dist/commands/restart-opencode-server.js +9 -21
- package/dist/commands/run-command.js +77 -0
- package/dist/commands/share.js +5 -6
- package/dist/commands/undo-redo.js +9 -10
- package/dist/commands/upgrade.js +38 -0
- package/dist/commands/worktree.js +32 -54
- package/dist/db.js +9 -2
- package/dist/discord-bot.js +114 -89
- package/dist/discord-utils.js +179 -23
- package/dist/errors.js +48 -0
- package/dist/format-tables.js +60 -41
- package/dist/format-tables.test.js +173 -392
- package/dist/heap-monitor.js +92 -0
- package/dist/interaction-handler.js +46 -0
- package/dist/logger.js +3 -1
- package/dist/message-formatting.js +9 -0
- package/dist/opencode-plugin.js +83 -118
- package/dist/opencode.js +2 -1
- package/dist/session-handler.js +39 -11
- package/dist/system-message.js +64 -2
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +12 -0
- package/dist/voice-handler.js +20 -28
- package/dist/worktree-utils.js +484 -19
- package/package.json +6 -8
- package/src/bin.ts +82 -0
- package/src/cli-parsing.test.ts +65 -0
- package/src/cli.ts +764 -212
- package/src/commands/abort.ts +7 -7
- package/src/commands/agent.ts +49 -2
- package/src/commands/compact.ts +11 -10
- package/src/commands/diff.ts +9 -11
- package/src/commands/file-upload.ts +365 -0
- package/src/commands/fork.ts +9 -6
- package/src/commands/merge-worktree.ts +93 -288
- package/src/commands/permissions.ts +41 -2
- package/src/commands/queue.ts +5 -7
- package/src/commands/restart-opencode-server.ts +12 -20
- package/src/commands/run-command.ts +94 -0
- package/src/commands/share.ts +7 -7
- package/src/commands/undo-redo.ts +12 -11
- package/src/commands/upgrade.ts +46 -0
- package/src/commands/worktree.ts +41 -63
- package/src/db.ts +11 -2
- package/src/discord-bot.ts +128 -96
- package/src/discord-utils.ts +230 -23
- package/src/errors.ts +60 -0
- package/src/format-tables.test.ts +186 -412
- package/src/format-tables.ts +78 -45
- package/src/heap-monitor.ts +112 -0
- package/src/interaction-handler.ts +55 -1
- package/src/logger.ts +3 -1
- package/src/message-formatting.ts +11 -0
- package/src/opencode-plugin.ts +88 -131
- package/src/opencode.ts +2 -1
- package/src/session-handler.ts +46 -13
- package/src/system-message.ts +66 -2
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +14 -0
- package/src/voice-handler.ts +22 -32
- package/src/worktree-utils.ts +588 -24
package/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import './dist/
|
|
2
|
+
import './dist/bin.js'
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Respawn wrapper for the kimaki bot process.
|
|
2
|
+
// When running the default command (no subcommand) with --auto-restart,
|
|
3
|
+
// spawns cli.js as a child process and restarts it on non-zero exit codes
|
|
4
|
+
// (crash, OOM kill, etc). Intentional exits (code 0 or EXIT_NO_RESTART=64)
|
|
5
|
+
// are not restarted.
|
|
6
|
+
//
|
|
7
|
+
// Subcommands (send, tunnel, project, etc.) run directly without the wrapper
|
|
8
|
+
// since they are short-lived and don't need crash recovery.
|
|
9
|
+
//
|
|
10
|
+
// When __KIMAKI_CHILD is set, we're the child process -- just run cli.js directly.
|
|
11
|
+
import { spawn } from 'node:child_process';
|
|
12
|
+
// First arg after node + script is either a subcommand or a flag.
|
|
13
|
+
// If it doesn't start with '-', it's a subcommand (e.g. "send", "tunnel", "project").
|
|
14
|
+
const firstArg = process.argv[2];
|
|
15
|
+
const isSubcommand = firstArg && !firstArg.startsWith('-');
|
|
16
|
+
const hasAutoRestart = process.argv.includes('--auto-restart');
|
|
17
|
+
if (process.env.__KIMAKI_CHILD || isSubcommand || !hasAutoRestart) {
|
|
18
|
+
await import('./cli.js');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const EXIT_NO_RESTART = 64;
|
|
22
|
+
const MAX_RAPID_RESTARTS = 5;
|
|
23
|
+
const RAPID_RESTART_WINDOW_MS = 60_000;
|
|
24
|
+
const RESTART_DELAY_MS = 2_000;
|
|
25
|
+
const restartTimestamps = [];
|
|
26
|
+
let child = null;
|
|
27
|
+
// Track when we forwarded a termination signal so we don't restart after graceful shutdown
|
|
28
|
+
let shutdownRequested = false;
|
|
29
|
+
function start() {
|
|
30
|
+
child = spawn(process.argv[0], [...process.execArgv, ...process.argv.slice(1)], {
|
|
31
|
+
stdio: 'inherit',
|
|
32
|
+
env: { ...process.env, __KIMAKI_CHILD: '1' },
|
|
33
|
+
});
|
|
34
|
+
child.on('exit', (code, signal) => {
|
|
35
|
+
if (code === 0 || code === EXIT_NO_RESTART || shutdownRequested) {
|
|
36
|
+
process.exit(code ?? 0);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
restartTimestamps.push(now);
|
|
41
|
+
while (restartTimestamps.length > 0 && restartTimestamps[0] < now - RAPID_RESTART_WINDOW_MS) {
|
|
42
|
+
restartTimestamps.shift();
|
|
43
|
+
}
|
|
44
|
+
if (restartTimestamps.length > MAX_RAPID_RESTARTS) {
|
|
45
|
+
console.error(`[kimaki] Crash loop detected (${MAX_RAPID_RESTARTS} crashes in ${RAPID_RESTART_WINDOW_MS / 1000}s), exiting`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const reason = signal ? `signal ${signal}` : `code ${code}`;
|
|
50
|
+
console.error(`[kimaki] Process exited with ${reason}, restarting in ${RESTART_DELAY_MS / 1000}s...`);
|
|
51
|
+
setTimeout(start, RESTART_DELAY_MS);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Forward signals to child so graceful shutdown and heap snapshots work.
|
|
55
|
+
// SIGTERM/SIGINT mark shutdownRequested so we don't restart after graceful exit.
|
|
56
|
+
for (const sig of ['SIGTERM', 'SIGINT']) {
|
|
57
|
+
process.on(sig, () => {
|
|
58
|
+
shutdownRequested = true;
|
|
59
|
+
child?.kill(sig);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
for (const sig of ['SIGUSR1', 'SIGUSR2']) {
|
|
63
|
+
process.on(sig, () => {
|
|
64
|
+
child?.kill(sig);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
start();
|
|
68
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Regression tests for CLI argument parsing around Discord ID string preservation.
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
import { goke } from 'goke';
|
|
4
|
+
function createCliForIdParsing() {
|
|
5
|
+
const cli = goke('kimaki');
|
|
6
|
+
cli
|
|
7
|
+
.command('send', 'Send a message')
|
|
8
|
+
.option('-c, --channel <channelId>', 'Discord channel ID')
|
|
9
|
+
.option('--thread <threadId>', 'Thread ID')
|
|
10
|
+
.option('--session <sessionId>', 'Session ID');
|
|
11
|
+
cli
|
|
12
|
+
.command('session archive <threadId>', 'Archive a thread');
|
|
13
|
+
cli
|
|
14
|
+
.command('add-project', 'Add a project')
|
|
15
|
+
.option('-g, --guild <guildId>', 'Discord guild/server ID');
|
|
16
|
+
return cli;
|
|
17
|
+
}
|
|
18
|
+
describe('goke CLI ID parsing', () => {
|
|
19
|
+
test('keeps large Discord IDs as strings', () => {
|
|
20
|
+
const cli = createCliForIdParsing();
|
|
21
|
+
const channelId = '1234567890123456789';
|
|
22
|
+
const threadId = '9876543210987654321';
|
|
23
|
+
const sessionId = '1111222233334444555';
|
|
24
|
+
const channelResult = cli.parse(['node', 'kimaki', 'send', '--channel', channelId], { run: false });
|
|
25
|
+
expect(channelResult.options.channel).toBe(channelId);
|
|
26
|
+
expect(typeof channelResult.options.channel).toBe('string');
|
|
27
|
+
const threadResult = cli.parse(['node', 'kimaki', 'send', '--thread', threadId], { run: false });
|
|
28
|
+
expect(threadResult.options.thread).toBe(threadId);
|
|
29
|
+
expect(typeof threadResult.options.thread).toBe('string');
|
|
30
|
+
const sessionResult = cli.parse(['node', 'kimaki', 'send', '--session', sessionId], { run: false });
|
|
31
|
+
expect(sessionResult.options.session).toBe(sessionId);
|
|
32
|
+
expect(typeof sessionResult.options.session).toBe('string');
|
|
33
|
+
});
|
|
34
|
+
test('preserves leading zeros in Discord IDs', () => {
|
|
35
|
+
const cli = createCliForIdParsing();
|
|
36
|
+
const guildId = '001230045600789';
|
|
37
|
+
const result = cli.parse(['node', 'kimaki', 'add-project', '--guild', guildId], { run: false });
|
|
38
|
+
expect(result.options.guild).toBe(guildId);
|
|
39
|
+
expect(typeof result.options.guild).toBe('string');
|
|
40
|
+
});
|
|
41
|
+
test('keeps session archive thread ID as string', () => {
|
|
42
|
+
const cli = createCliForIdParsing();
|
|
43
|
+
const threadId = '0098765432109876543';
|
|
44
|
+
const result = cli.parse(['node', 'kimaki', 'session', 'archive', threadId], {
|
|
45
|
+
run: false,
|
|
46
|
+
});
|
|
47
|
+
expect(result.args[0]).toBe(threadId);
|
|
48
|
+
expect(typeof result.args[0]).toBe('string');
|
|
49
|
+
});
|
|
50
|
+
});
|