kimaki 0.4.12 → 0.4.14
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/dist/cli.js +81 -12
- package/dist/discordBot.js +225 -114
- package/dist/tools.js +3 -3
- package/package.json +11 -12
- package/src/cli.ts +108 -11
- package/src/discordBot.ts +268 -164
- package/src/opencode-command-send-to-discord.md +12 -0
- package/src/opencode-command-upload-to-discord.md +22 -0
- package/src/tools.ts +3 -3
- package/src/opencode-command.md +0 -4
- package/src/opencode-plugin.ts +0 -75
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cac } from 'cac';
|
|
|
3
3
|
import { intro, outro, text, password, note, cancel, isCancel, confirm, log, multiselect, spinner, } from '@clack/prompts';
|
|
4
4
|
import { deduplicateByKey, generateBotInstallUrl } from './utils.js';
|
|
5
5
|
import { getChannelsWithDescriptions, createDiscordClient, getDatabase, startDiscordBot, initializeOpencodeForDirectory, ensureKimakiCategory, createProjectChannels, } from './discordBot.js';
|
|
6
|
-
import { Events, ChannelType, REST, Routes, SlashCommandBuilder, } from 'discord.js';
|
|
6
|
+
import { Events, ChannelType, REST, Routes, SlashCommandBuilder, AttachmentBuilder, } from 'discord.js';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import { createRequire } from 'node:module';
|
|
@@ -78,12 +78,16 @@ async function registerCommands(token, appId) {
|
|
|
78
78
|
.toJSON(),
|
|
79
79
|
new SlashCommandBuilder()
|
|
80
80
|
.setName('accept-always')
|
|
81
|
-
.setDescription('Accept and auto-approve future requests matching this pattern
|
|
81
|
+
.setDescription('Accept and auto-approve future requests matching this pattern')
|
|
82
82
|
.toJSON(),
|
|
83
83
|
new SlashCommandBuilder()
|
|
84
84
|
.setName('reject')
|
|
85
85
|
.setDescription('Reject a pending permission request')
|
|
86
86
|
.toJSON(),
|
|
87
|
+
new SlashCommandBuilder()
|
|
88
|
+
.setName('abort')
|
|
89
|
+
.setDescription('Abort the current OpenCode request in this thread')
|
|
90
|
+
.toJSON(),
|
|
87
91
|
];
|
|
88
92
|
const rest = new REST().setToken(token);
|
|
89
93
|
try {
|
|
@@ -558,22 +562,87 @@ cli
|
|
|
558
562
|
}
|
|
559
563
|
});
|
|
560
564
|
cli
|
|
561
|
-
.command('
|
|
565
|
+
.command('upload-to-discord [...files]', 'Upload files to a Discord thread for a session')
|
|
566
|
+
.option('-s, --session <sessionId>', 'OpenCode session ID')
|
|
567
|
+
.action(async (files, options) => {
|
|
568
|
+
try {
|
|
569
|
+
const { session: sessionId } = options;
|
|
570
|
+
if (!sessionId) {
|
|
571
|
+
cliLogger.error('Session ID is required. Use --session <sessionId>');
|
|
572
|
+
process.exit(EXIT_NO_RESTART);
|
|
573
|
+
}
|
|
574
|
+
if (!files || files.length === 0) {
|
|
575
|
+
cliLogger.error('At least one file path is required');
|
|
576
|
+
process.exit(EXIT_NO_RESTART);
|
|
577
|
+
}
|
|
578
|
+
const resolvedFiles = files.map((f) => path.resolve(f));
|
|
579
|
+
for (const file of resolvedFiles) {
|
|
580
|
+
if (!fs.existsSync(file)) {
|
|
581
|
+
cliLogger.error(`File not found: ${file}`);
|
|
582
|
+
process.exit(EXIT_NO_RESTART);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const db = getDatabase();
|
|
586
|
+
const threadRow = db
|
|
587
|
+
.prepare('SELECT thread_id FROM thread_sessions WHERE session_id = ?')
|
|
588
|
+
.get(sessionId);
|
|
589
|
+
if (!threadRow) {
|
|
590
|
+
cliLogger.error(`No Discord thread found for session: ${sessionId}`);
|
|
591
|
+
cliLogger.error('Make sure the session has been sent to Discord first using /send-to-kimaki-discord');
|
|
592
|
+
process.exit(EXIT_NO_RESTART);
|
|
593
|
+
}
|
|
594
|
+
const botRow = db
|
|
595
|
+
.prepare('SELECT app_id, token FROM bot_tokens ORDER BY created_at DESC LIMIT 1')
|
|
596
|
+
.get();
|
|
597
|
+
if (!botRow) {
|
|
598
|
+
cliLogger.error('No bot credentials found. Run `kimaki` first to set up the bot.');
|
|
599
|
+
process.exit(EXIT_NO_RESTART);
|
|
600
|
+
}
|
|
601
|
+
const s = spinner();
|
|
602
|
+
s.start(`Uploading ${resolvedFiles.length} file(s)...`);
|
|
603
|
+
for (const file of resolvedFiles) {
|
|
604
|
+
const buffer = fs.readFileSync(file);
|
|
605
|
+
const formData = new FormData();
|
|
606
|
+
formData.append('payload_json', JSON.stringify({
|
|
607
|
+
attachments: [{ id: 0, filename: path.basename(file) }]
|
|
608
|
+
}));
|
|
609
|
+
formData.append('files[0]', new Blob([buffer]), path.basename(file));
|
|
610
|
+
const response = await fetch(`https://discord.com/api/v10/channels/${threadRow.thread_id}/messages`, {
|
|
611
|
+
method: 'POST',
|
|
612
|
+
headers: {
|
|
613
|
+
'Authorization': `Bot ${botRow.token}`,
|
|
614
|
+
},
|
|
615
|
+
body: formData,
|
|
616
|
+
});
|
|
617
|
+
if (!response.ok) {
|
|
618
|
+
const error = await response.text();
|
|
619
|
+
throw new Error(`Discord API error: ${response.status} - ${error}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
s.stop(`Uploaded ${resolvedFiles.length} file(s)!`);
|
|
623
|
+
note(`Files uploaded to Discord thread!\n\nFiles: ${resolvedFiles.map((f) => path.basename(f)).join(', ')}`, '✅ Success');
|
|
624
|
+
process.exit(0);
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
cliLogger.error('Error:', error instanceof Error ? error.message : String(error));
|
|
628
|
+
process.exit(EXIT_NO_RESTART);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
cli
|
|
632
|
+
.command('install-plugin', 'Install the OpenCode commands for kimaki Discord integration')
|
|
562
633
|
.action(async () => {
|
|
563
634
|
try {
|
|
564
635
|
const require = createRequire(import.meta.url);
|
|
565
|
-
const
|
|
566
|
-
const
|
|
636
|
+
const sendCommandSrc = require.resolve('./opencode-command-send-to-discord.md');
|
|
637
|
+
const uploadCommandSrc = require.resolve('./opencode-command-upload-to-discord.md');
|
|
567
638
|
const opencodeConfig = path.join(os.homedir(), '.config', 'opencode');
|
|
568
|
-
const pluginDir = path.join(opencodeConfig, 'plugin');
|
|
569
639
|
const commandDir = path.join(opencodeConfig, 'command');
|
|
570
|
-
fs.mkdirSync(pluginDir, { recursive: true });
|
|
571
640
|
fs.mkdirSync(commandDir, { recursive: true });
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
fs.copyFileSync(
|
|
575
|
-
fs.copyFileSync(
|
|
576
|
-
note(`
|
|
641
|
+
const sendCommandDest = path.join(commandDir, 'send-to-kimaki-discord.md');
|
|
642
|
+
const uploadCommandDest = path.join(commandDir, 'upload-to-discord.md');
|
|
643
|
+
fs.copyFileSync(sendCommandSrc, sendCommandDest);
|
|
644
|
+
fs.copyFileSync(uploadCommandSrc, uploadCommandDest);
|
|
645
|
+
note(`Commands installed:\n- ${sendCommandDest}\n- ${uploadCommandDest}\n\nUse /send-to-kimaki-discord to send session to Discord.\nUse /upload-to-discord to upload files to the thread.`, '✅ Installed');
|
|
577
646
|
process.exit(0);
|
|
578
647
|
}
|
|
579
648
|
catch (error) {
|