kimaki 0.1.4 → 0.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/dist/cli.js +63 -12
- package/dist/discordBot.js +341 -42
- package/dist/genai-worker-wrapper.js +3 -0
- package/dist/genai-worker.js +5 -0
- package/dist/tools.js +46 -5
- package/package.json +1 -1
- package/src/cli.ts +80 -10
- package/src/discordBot.ts +453 -45
- package/src/genai-worker-wrapper.ts +4 -0
- package/src/genai-worker.ts +5 -0
- package/src/tools.ts +59 -4
- package/src/worker-types.ts +3 -0
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Events, ChannelType, REST, Routes, SlashCommandBuilder, } from 'discord
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import { createLogger } from './logger.js';
|
|
10
|
+
import { spawnSync, execSync } from 'node:child_process';
|
|
10
11
|
const cliLogger = createLogger('CLI');
|
|
11
12
|
const cli = cac('kimaki');
|
|
12
13
|
process.title = 'kimaki';
|
|
@@ -75,6 +76,56 @@ async function ensureKimakiCategory(guild) {
|
|
|
75
76
|
async function run({ restart, addChannels }) {
|
|
76
77
|
const forceSetup = Boolean(restart);
|
|
77
78
|
intro('🤖 Discord Bot Setup');
|
|
79
|
+
// Step 0: Check if OpenCode CLI is available
|
|
80
|
+
const opencodeCheck = spawnSync('which', ['opencode'], { shell: true });
|
|
81
|
+
if (opencodeCheck.status !== 0) {
|
|
82
|
+
note('OpenCode CLI is required but not found in your PATH.', '⚠️ OpenCode Not Found');
|
|
83
|
+
const shouldInstall = await confirm({
|
|
84
|
+
message: 'Would you like to install OpenCode right now?',
|
|
85
|
+
});
|
|
86
|
+
if (isCancel(shouldInstall) || !shouldInstall) {
|
|
87
|
+
cancel('OpenCode CLI is required to run this bot');
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
const s = spinner();
|
|
91
|
+
s.start('Installing OpenCode CLI...');
|
|
92
|
+
try {
|
|
93
|
+
execSync('curl -fsSL https://opencode.ai/install | bash', {
|
|
94
|
+
stdio: 'inherit',
|
|
95
|
+
shell: '/bin/bash',
|
|
96
|
+
});
|
|
97
|
+
s.stop('OpenCode CLI installed successfully!');
|
|
98
|
+
// The install script adds opencode to PATH via shell configuration
|
|
99
|
+
// For the current process, we need to check common installation paths
|
|
100
|
+
const possiblePaths = [
|
|
101
|
+
`${process.env.HOME}/.local/bin/opencode`,
|
|
102
|
+
`${process.env.HOME}/.opencode/bin/opencode`,
|
|
103
|
+
'/usr/local/bin/opencode',
|
|
104
|
+
'/opt/opencode/bin/opencode',
|
|
105
|
+
];
|
|
106
|
+
const installedPath = possiblePaths.find((p) => {
|
|
107
|
+
try {
|
|
108
|
+
fs.accessSync(p, fs.constants.F_OK);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
if (!installedPath) {
|
|
116
|
+
note('OpenCode was installed but may not be available in this session.\n' +
|
|
117
|
+
'Please restart your terminal and run this command again.', '⚠️ Restart Required');
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
// For subsequent spawn calls in this session, we can use the full path
|
|
121
|
+
process.env.OPENCODE_PATH = installedPath;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
s.stop('Failed to install OpenCode CLI');
|
|
125
|
+
cliLogger.error('Installation error:', error instanceof Error ? error.message : String(error));
|
|
126
|
+
process.exit(EXIT_NO_RESTART);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
78
129
|
const db = getDatabase();
|
|
79
130
|
let appId;
|
|
80
131
|
let token;
|
|
@@ -231,7 +282,7 @@ async function run({ restart, addChannels }) {
|
|
|
231
282
|
s.start('Fetching OpenCode projects...');
|
|
232
283
|
let projects = [];
|
|
233
284
|
try {
|
|
234
|
-
const projectsResponse = await getClient().project.list();
|
|
285
|
+
const projectsResponse = await getClient().project.list({});
|
|
235
286
|
if (!projectsResponse.data) {
|
|
236
287
|
throw new Error('Failed to fetch projects');
|
|
237
288
|
}
|
|
@@ -270,23 +321,23 @@ async function run({ restart, addChannels }) {
|
|
|
270
321
|
}
|
|
271
322
|
if (guilds.length === 1) {
|
|
272
323
|
targetGuild = guilds[0];
|
|
324
|
+
note(`Using server: ${targetGuild.name}`, 'Server Selected');
|
|
273
325
|
}
|
|
274
326
|
else {
|
|
275
|
-
const
|
|
276
|
-
message: '
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
},
|
|
327
|
+
const guildSelection = await multiselect({
|
|
328
|
+
message: 'Select a Discord server to create channels in:',
|
|
329
|
+
options: guilds.map((guild) => ({
|
|
330
|
+
value: guild.id,
|
|
331
|
+
label: `${guild.name} (${guild.memberCount} members)`,
|
|
332
|
+
})),
|
|
333
|
+
required: true,
|
|
334
|
+
maxItems: 1,
|
|
284
335
|
});
|
|
285
|
-
if (isCancel(
|
|
336
|
+
if (isCancel(guildSelection)) {
|
|
286
337
|
cancel('Setup cancelled');
|
|
287
338
|
process.exit(0);
|
|
288
339
|
}
|
|
289
|
-
targetGuild = guilds.find((g) => g.id ===
|
|
340
|
+
targetGuild = guilds.find((g) => g.id === guildSelection[0]);
|
|
290
341
|
}
|
|
291
342
|
s.start('Creating Discord channels...');
|
|
292
343
|
for (const projectId of selectedProjects) {
|