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/src/cli.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
REST,
|
|
34
34
|
Routes,
|
|
35
35
|
SlashCommandBuilder,
|
|
36
|
+
AttachmentBuilder,
|
|
36
37
|
} from 'discord.js'
|
|
37
38
|
import path from 'node:path'
|
|
38
39
|
import fs from 'node:fs'
|
|
@@ -134,12 +135,16 @@ async function registerCommands(token: string, appId: string) {
|
|
|
134
135
|
.toJSON(),
|
|
135
136
|
new SlashCommandBuilder()
|
|
136
137
|
.setName('accept-always')
|
|
137
|
-
.setDescription('Accept and auto-approve future requests matching this pattern
|
|
138
|
+
.setDescription('Accept and auto-approve future requests matching this pattern')
|
|
138
139
|
.toJSON(),
|
|
139
140
|
new SlashCommandBuilder()
|
|
140
141
|
.setName('reject')
|
|
141
142
|
.setDescription('Reject a pending permission request')
|
|
142
143
|
.toJSON(),
|
|
144
|
+
new SlashCommandBuilder()
|
|
145
|
+
.setName('abort')
|
|
146
|
+
.setDescription('Abort the current OpenCode request in this thread')
|
|
147
|
+
.toJSON(),
|
|
143
148
|
]
|
|
144
149
|
|
|
145
150
|
const rest = new REST().setToken(token)
|
|
@@ -832,28 +837,120 @@ cli
|
|
|
832
837
|
})
|
|
833
838
|
|
|
834
839
|
cli
|
|
835
|
-
.command('
|
|
840
|
+
.command('upload-to-discord [...files]', 'Upload files to a Discord thread for a session')
|
|
841
|
+
.option('-s, --session <sessionId>', 'OpenCode session ID')
|
|
842
|
+
.action(async (files: string[], options: { session?: string }) => {
|
|
843
|
+
try {
|
|
844
|
+
const { session: sessionId } = options
|
|
845
|
+
|
|
846
|
+
if (!sessionId) {
|
|
847
|
+
cliLogger.error('Session ID is required. Use --session <sessionId>')
|
|
848
|
+
process.exit(EXIT_NO_RESTART)
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (!files || files.length === 0) {
|
|
852
|
+
cliLogger.error('At least one file path is required')
|
|
853
|
+
process.exit(EXIT_NO_RESTART)
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const resolvedFiles = files.map((f) => path.resolve(f))
|
|
857
|
+
for (const file of resolvedFiles) {
|
|
858
|
+
if (!fs.existsSync(file)) {
|
|
859
|
+
cliLogger.error(`File not found: ${file}`)
|
|
860
|
+
process.exit(EXIT_NO_RESTART)
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const db = getDatabase()
|
|
865
|
+
|
|
866
|
+
const threadRow = db
|
|
867
|
+
.prepare('SELECT thread_id FROM thread_sessions WHERE session_id = ?')
|
|
868
|
+
.get(sessionId) as { thread_id: string } | undefined
|
|
869
|
+
|
|
870
|
+
if (!threadRow) {
|
|
871
|
+
cliLogger.error(`No Discord thread found for session: ${sessionId}`)
|
|
872
|
+
cliLogger.error('Make sure the session has been sent to Discord first using /send-to-kimaki-discord')
|
|
873
|
+
process.exit(EXIT_NO_RESTART)
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
const botRow = db
|
|
877
|
+
.prepare(
|
|
878
|
+
'SELECT app_id, token FROM bot_tokens ORDER BY created_at DESC LIMIT 1',
|
|
879
|
+
)
|
|
880
|
+
.get() as { app_id: string; token: string } | undefined
|
|
881
|
+
|
|
882
|
+
if (!botRow) {
|
|
883
|
+
cliLogger.error('No bot credentials found. Run `kimaki` first to set up the bot.')
|
|
884
|
+
process.exit(EXIT_NO_RESTART)
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
const s = spinner()
|
|
888
|
+
s.start(`Uploading ${resolvedFiles.length} file(s)...`)
|
|
889
|
+
|
|
890
|
+
for (const file of resolvedFiles) {
|
|
891
|
+
const buffer = fs.readFileSync(file)
|
|
892
|
+
|
|
893
|
+
const formData = new FormData()
|
|
894
|
+
formData.append('payload_json', JSON.stringify({
|
|
895
|
+
attachments: [{ id: 0, filename: path.basename(file) }]
|
|
896
|
+
}))
|
|
897
|
+
formData.append('files[0]', new Blob([buffer]), path.basename(file))
|
|
898
|
+
|
|
899
|
+
const response = await fetch(
|
|
900
|
+
`https://discord.com/api/v10/channels/${threadRow.thread_id}/messages`,
|
|
901
|
+
{
|
|
902
|
+
method: 'POST',
|
|
903
|
+
headers: {
|
|
904
|
+
'Authorization': `Bot ${botRow.token}`,
|
|
905
|
+
},
|
|
906
|
+
body: formData,
|
|
907
|
+
}
|
|
908
|
+
)
|
|
909
|
+
|
|
910
|
+
if (!response.ok) {
|
|
911
|
+
const error = await response.text()
|
|
912
|
+
throw new Error(`Discord API error: ${response.status} - ${error}`)
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
s.stop(`Uploaded ${resolvedFiles.length} file(s)!`)
|
|
917
|
+
|
|
918
|
+
note(
|
|
919
|
+
`Files uploaded to Discord thread!\n\nFiles: ${resolvedFiles.map((f) => path.basename(f)).join(', ')}`,
|
|
920
|
+
'✅ Success',
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
process.exit(0)
|
|
924
|
+
} catch (error) {
|
|
925
|
+
cliLogger.error(
|
|
926
|
+
'Error:',
|
|
927
|
+
error instanceof Error ? error.message : String(error),
|
|
928
|
+
)
|
|
929
|
+
process.exit(EXIT_NO_RESTART)
|
|
930
|
+
}
|
|
931
|
+
})
|
|
932
|
+
|
|
933
|
+
cli
|
|
934
|
+
.command('install-plugin', 'Install the OpenCode commands for kimaki Discord integration')
|
|
836
935
|
.action(async () => {
|
|
837
936
|
try {
|
|
838
937
|
const require = createRequire(import.meta.url)
|
|
839
|
-
const
|
|
840
|
-
const
|
|
938
|
+
const sendCommandSrc = require.resolve('./opencode-command-send-to-discord.md')
|
|
939
|
+
const uploadCommandSrc = require.resolve('./opencode-command-upload-to-discord.md')
|
|
841
940
|
|
|
842
941
|
const opencodeConfig = path.join(os.homedir(), '.config', 'opencode')
|
|
843
|
-
const pluginDir = path.join(opencodeConfig, 'plugin')
|
|
844
942
|
const commandDir = path.join(opencodeConfig, 'command')
|
|
845
943
|
|
|
846
|
-
fs.mkdirSync(pluginDir, { recursive: true })
|
|
847
944
|
fs.mkdirSync(commandDir, { recursive: true })
|
|
848
945
|
|
|
849
|
-
const
|
|
850
|
-
const
|
|
946
|
+
const sendCommandDest = path.join(commandDir, 'send-to-kimaki-discord.md')
|
|
947
|
+
const uploadCommandDest = path.join(commandDir, 'upload-to-discord.md')
|
|
851
948
|
|
|
852
|
-
fs.copyFileSync(
|
|
853
|
-
fs.copyFileSync(
|
|
949
|
+
fs.copyFileSync(sendCommandSrc, sendCommandDest)
|
|
950
|
+
fs.copyFileSync(uploadCommandSrc, uploadCommandDest)
|
|
854
951
|
|
|
855
952
|
note(
|
|
856
|
-
`
|
|
953
|
+
`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.`,
|
|
857
954
|
'✅ Installed',
|
|
858
955
|
)
|
|
859
956
|
|