kimaki 0.28.0 → 0.30.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/agent-model.e2e.test.js +33 -33
- package/dist/anthropic-account-identity.js +1 -1
- package/dist/anthropic-auth-plugin.js +5 -5
- package/dist/anthropic-auth-plugin.test.js +30 -2
- package/dist/anthropic-auth-state.js +1 -1
- package/dist/bash-tool-schema-plugin.js +18 -0
- package/dist/bash-tool-schema-plugin.test.js +20 -1
- package/dist/bin.js +7 -3
- package/dist/bot-lifecycle.test.js +206 -0
- package/dist/cache-drift-plugin.js +25 -18
- package/dist/cache-rewrite.js +39 -0
- package/dist/cache-rewrite.test.js +41 -0
- package/dist/channel-management.js +113 -51
- package/dist/cli-commands/misc.js +4 -1
- package/dist/cli-commands/project.js +7 -4
- package/dist/cli-commands/session.js +118 -36
- package/dist/cli-commands/thread.js +63 -0
- package/dist/cli-parsing.test.js +3 -3
- package/dist/cli-runner.js +11 -1
- package/dist/cli-send-thread.e2e.test.js +2 -2
- package/dist/cli.js +6 -4
- package/dist/commands/ask-question.js +72 -23
- package/dist/commands/queue.js +84 -36
- package/dist/commands/queue.test.js +15 -0
- package/dist/commands/restart-opencode-server.js +7 -1
- package/dist/commands/session-id.js +5 -5
- package/dist/database.js +149 -6
- package/dist/db.js +34 -0
- package/dist/db.test.js +199 -1
- package/dist/default-channel-provisioning.test.js +2 -1
- package/dist/discord-bot.js +220 -146
- package/dist/discord-command-registration.js +1 -1
- package/dist/external-directory-permissions.e2e.test.js +3 -3
- package/dist/external-directory-project-deny.e2e.test.js +1 -1
- package/dist/forum-sync/watchers.js +15 -0
- package/dist/gateway-proxy.e2e.test.js +9 -9
- package/dist/guild-categories.test.js +225 -0
- package/dist/hrana-server.js +68 -14
- package/dist/interaction-handler.js +5 -1
- package/dist/kimaki-opencode-plugin.js +2 -0
- package/dist/kimaki-opencode-plugin.test.js +28 -0
- package/dist/list-channel-threads.js +163 -0
- package/dist/list-channel-threads.test.js +80 -0
- package/dist/markdown.js +164 -102
- package/dist/markdown.test.js +88 -20
- package/dist/message-formatting.js +29 -18
- package/dist/message-formatting.test.js +111 -3
- package/dist/opencode.js +27 -12
- package/dist/question-abort-clears-dropdown.e2e.test.js +1 -1
- package/dist/question-abort-resume.e2e.test.js +100 -0
- package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +1 -1
- package/dist/question-text-before-dropdown.e2e.test.js +1 -1
- package/dist/queue-advanced-abort.e2e.test.js +3 -3
- package/dist/queue-advanced-action-buttons.e2e.test.js +5 -5
- package/dist/queue-advanced-e2e-setup.js +63 -0
- package/dist/queue-advanced-footer.e2e.test.js +18 -18
- package/dist/queue-advanced-model-switch.e2e.test.js +3 -4
- package/dist/queue-advanced-permissions-typing.e2e.test.js +2 -2
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +3 -3
- package/dist/queue-delete-message.e2e.test.js +4 -4
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +3 -3
- package/dist/queue-interrupt-drain.e2e.test.js +10 -10
- package/dist/queue-question-select-drain.e2e.test.js +5 -5
- package/dist/runtime-lifecycle.e2e.test.js +95 -11
- package/dist/schema.js +21 -0
- package/dist/session-handler/event-stream-state.js +240 -6
- package/dist/session-handler/event-stream-state.test.js +1116 -130
- package/dist/session-handler/thread-runtime-state.js +4 -0
- package/dist/session-handler/thread-session-runtime.js +499 -89
- package/dist/sleep.e2e.test.js +7 -7
- package/dist/store.js +1 -1
- package/dist/system-message.js +64 -23
- package/dist/system-message.test.js +69 -23
- package/dist/task-id-plugin.js +16 -0
- package/dist/task-runner.js +7 -0
- package/dist/task-schedule.test.js +1 -1
- package/dist/test-utils.js +5 -3
- package/dist/thread-message-queue.e2e.test.js +30 -31
- package/dist/undo-redo.e2e.test.js +3 -3
- package/dist/voice-message.e2e.test.js +64 -26
- package/dist/voice-routing-input.e2e.test.js +4 -4
- package/dist/voice-routing-question.e2e.test.js +4 -4
- package/dist/voice.js +107 -21
- package/dist/voice.test.js +52 -1
- package/dist/wait-session.js +24 -2
- package/dist/worktree-lifecycle.e2e.test.js +8 -8
- package/package.json +7 -7
- package/skills/egaki/SKILL.md +14 -0
- package/skills/holocron/SKILL.md +125 -42
- package/skills/opensrc/SKILL.md +20 -3
- package/skills/spiceflow/SKILL.md +53 -172
- package/skills/strada/SKILL.md +61 -232
- package/src/agent-model.e2e.test.ts +33 -33
- package/src/anthropic-account-identity.ts +1 -1
- package/src/anthropic-auth-plugin.test.ts +37 -2
- package/src/anthropic-auth-plugin.ts +9 -7
- package/src/anthropic-auth-state.ts +1 -0
- package/src/bash-tool-schema-plugin.test.ts +29 -0
- package/src/bash-tool-schema-plugin.ts +31 -0
- package/src/bin.ts +7 -3
- package/src/bot-lifecycle.test.ts +252 -0
- package/src/cache-drift-plugin.ts +34 -24
- package/src/cache-rewrite.test.ts +49 -0
- package/src/cache-rewrite.ts +96 -0
- package/src/channel-management.ts +144 -65
- package/src/cli-commands/misc.ts +4 -1
- package/src/cli-commands/project.ts +9 -4
- package/src/cli-commands/session.ts +167 -38
- package/src/cli-commands/thread.ts +86 -0
- package/src/cli-parsing.test.ts +3 -3
- package/src/cli-runner.ts +11 -0
- package/src/cli-send-thread.e2e.test.ts +2 -2
- package/src/cli.ts +8 -6
- package/src/commands/ask-question.ts +88 -25
- package/src/commands/queue.test.ts +19 -0
- package/src/commands/queue.ts +111 -45
- package/src/commands/restart-opencode-server.ts +12 -1
- package/src/commands/session-id.ts +5 -5
- package/src/database.ts +219 -6
- package/src/db.test.ts +236 -0
- package/src/db.ts +38 -0
- package/src/default-channel-provisioning.test.ts +2 -1
- package/src/discord-bot.ts +272 -185
- package/src/discord-command-registration.ts +3 -1
- package/src/external-directory-permissions.e2e.test.ts +3 -3
- package/src/external-directory-project-deny.e2e.test.ts +1 -1
- package/src/forum-sync/watchers.ts +20 -0
- package/src/gateway-proxy.e2e.test.ts +9 -9
- package/src/guild-categories.test.ts +260 -0
- package/src/hrana-server.ts +96 -16
- package/src/interaction-handler.ts +7 -0
- package/src/kimaki-opencode-plugin.test.ts +34 -0
- package/src/kimaki-opencode-plugin.ts +2 -0
- package/src/list-channel-threads.test.ts +90 -0
- package/src/list-channel-threads.ts +252 -0
- package/src/markdown.test.ts +108 -22
- package/src/markdown.ts +216 -103
- package/src/message-formatting.test.ts +129 -2
- package/src/message-formatting.ts +28 -14
- package/src/opencode.ts +28 -13
- package/src/question-abort-clears-dropdown.e2e.test.ts +1 -1
- package/src/question-abort-resume.e2e.test.ts +121 -0
- package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +1 -1
- package/src/question-text-before-dropdown.e2e.test.ts +1 -1
- package/src/queue-advanced-abort.e2e.test.ts +3 -3
- package/src/queue-advanced-action-buttons.e2e.test.ts +5 -5
- package/src/queue-advanced-e2e-setup.ts +65 -0
- package/src/queue-advanced-footer.e2e.test.ts +18 -18
- package/src/queue-advanced-model-switch.e2e.test.ts +3 -4
- package/src/queue-advanced-permissions-typing.e2e.test.ts +2 -2
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +3 -3
- package/src/queue-delete-message.e2e.test.ts +4 -4
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +3 -3
- package/src/queue-interrupt-drain.e2e.test.ts +10 -10
- package/src/queue-question-select-drain.e2e.test.ts +5 -5
- package/src/runtime-lifecycle.e2e.test.ts +104 -10
- package/src/schema.sql +16 -0
- package/src/schema.ts +23 -0
- package/src/session-handler/event-stream-state.test.ts +1184 -133
- package/src/session-handler/event-stream-state.ts +322 -8
- package/src/session-handler/thread-runtime-state.ts +5 -0
- package/src/session-handler/thread-session-runtime.ts +597 -95
- package/src/sleep.e2e.test.ts +7 -7
- package/src/store.ts +2 -2
- package/src/system-message.test.ts +70 -23
- package/src/system-message.ts +67 -22
- package/src/task-id-plugin.ts +17 -0
- package/src/task-runner.ts +8 -0
- package/src/task-schedule.test.ts +1 -1
- package/src/test-utils.ts +5 -3
- package/src/thread-message-queue.e2e.test.ts +30 -31
- package/src/undo-redo.e2e.test.ts +3 -3
- package/src/voice-message.e2e.test.ts +70 -26
- package/src/voice-routing-input.e2e.test.ts +4 -4
- package/src/voice-routing-question.e2e.test.ts +4 -4
- package/src/voice.test.ts +56 -0
- package/src/voice.ts +135 -25
- package/src/wait-session.ts +25 -2
- package/src/worktree-lifecycle.e2e.test.ts +8 -8
package/dist/db.test.js
CHANGED
|
@@ -7,7 +7,7 @@ import { afterAll, describe, expect, test } from 'vitest';
|
|
|
7
7
|
import { closeDb, getDb } from './db.js';
|
|
8
8
|
import * as orm from 'drizzle-orm';
|
|
9
9
|
import * as schema from './schema.js';
|
|
10
|
-
import { appendSessionEventsSinceLastTimestamp, createPendingWorkspace, getDueSessionSleeps, getSessionEventSnapshot, getSessionModel, getSessionSleep, setSessionModel, upsertSessionSleep, } from './database.js';
|
|
10
|
+
import { appendSessionEventsSinceLastTimestamp, cleanupDeletedThread, completeIpcRequest, createIpcRequest, createScheduledTask, createPendingWorkspace, deleteChannelDirectoryById, deleteThreadQueueItem, getChannelDirectory, getDueSessionSleeps, getIpcRequestById, getScheduledTask, getSessionEventSnapshot, getSessionModel, getSessionSleep, getThreadSession, insertThreadQueueItem, listAllThreadQueueItems, listThreadQueueItems, setChannelDirectory, setChannelVerbosity, setSessionModel, setThreadSession, updateThreadQueueItemPayload, upsertSessionSleep, } from './database.js';
|
|
11
11
|
import { createClient } from '@libsql/client';
|
|
12
12
|
import { startHranaServer, stopHranaServer } from './hrana-server.js';
|
|
13
13
|
import { chooseLockPort } from './test-utils.js';
|
|
@@ -27,6 +27,204 @@ describe('getDb', () => {
|
|
|
27
27
|
].map((match) => match[1]);
|
|
28
28
|
expect(new Set(tablesFromSql)).toEqual(new Set(tablesFromTs));
|
|
29
29
|
expect(tablesFromSql).toContain('session_sleeps');
|
|
30
|
+
expect(tablesFromSql).toContain('thread_queue_items');
|
|
31
|
+
});
|
|
32
|
+
test('persists local queue items in FIFO order', async () => {
|
|
33
|
+
const db = await getDb();
|
|
34
|
+
const threadId = `test-queue-thread-${crypto.randomUUID()}`;
|
|
35
|
+
const firstId = `queue-${crypto.randomUUID()}`;
|
|
36
|
+
const secondId = `queue-${crypto.randomUUID()}`;
|
|
37
|
+
await insertThreadQueueItem({
|
|
38
|
+
queueId: firstId,
|
|
39
|
+
threadId,
|
|
40
|
+
payloadJson: JSON.stringify({ prompt: 'first', userId: '1', username: 'tommy' }),
|
|
41
|
+
});
|
|
42
|
+
await insertThreadQueueItem({
|
|
43
|
+
queueId: secondId,
|
|
44
|
+
threadId,
|
|
45
|
+
payloadJson: JSON.stringify({ prompt: 'second', userId: '1', username: 'tommy' }),
|
|
46
|
+
});
|
|
47
|
+
const rows = await listThreadQueueItems(threadId);
|
|
48
|
+
expect(rows.map((row) => JSON.parse(row.payload_json).prompt)).toEqual([
|
|
49
|
+
'first',
|
|
50
|
+
'second',
|
|
51
|
+
]);
|
|
52
|
+
await updateThreadQueueItemPayload({
|
|
53
|
+
queueId: firstId,
|
|
54
|
+
payloadJson: JSON.stringify({ prompt: 'first-edited', userId: '1', username: 'tommy' }),
|
|
55
|
+
});
|
|
56
|
+
await deleteThreadQueueItem(secondId);
|
|
57
|
+
const after = await listAllThreadQueueItems();
|
|
58
|
+
const remaining = after.filter((row) => row.thread_id === threadId);
|
|
59
|
+
expect(remaining).toHaveLength(1);
|
|
60
|
+
expect(JSON.parse(remaining[0].payload_json).prompt).toBe('first-edited');
|
|
61
|
+
await db.delete(schema.thread_queue_items).where(orm.eq(schema.thread_queue_items.thread_id, threadId));
|
|
62
|
+
});
|
|
63
|
+
test('cancels channel tasks before deleting a channel mapping', async () => {
|
|
64
|
+
const channelId = `channel-${crypto.randomUUID()}`;
|
|
65
|
+
await setChannelDirectory({
|
|
66
|
+
channelId,
|
|
67
|
+
directory: `/tmp/${channelId}`,
|
|
68
|
+
channelType: 'text',
|
|
69
|
+
});
|
|
70
|
+
await setChannelVerbosity(channelId, 'text_only');
|
|
71
|
+
const taskId = await createScheduledTask({
|
|
72
|
+
scheduleKind: 'at',
|
|
73
|
+
nextRunAt: new Date('2099-01-01T00:00:00.000Z'),
|
|
74
|
+
payloadJson: JSON.stringify({ kind: 'channel', channelId, prompt: 'later' }),
|
|
75
|
+
promptPreview: 'later',
|
|
76
|
+
channelId,
|
|
77
|
+
});
|
|
78
|
+
expect(await deleteChannelDirectoryById(channelId)).toBe(true);
|
|
79
|
+
const db = await getDb();
|
|
80
|
+
expect({
|
|
81
|
+
mapping: await getChannelDirectory(channelId),
|
|
82
|
+
task: await getScheduledTask(taskId),
|
|
83
|
+
verbosity: await db.query.channel_verbosity.findFirst({
|
|
84
|
+
where: { channel_id: channelId },
|
|
85
|
+
}),
|
|
86
|
+
}).toMatchObject({
|
|
87
|
+
mapping: undefined,
|
|
88
|
+
task: {
|
|
89
|
+
status: 'cancelled',
|
|
90
|
+
last_error: 'Discord channel was deleted',
|
|
91
|
+
},
|
|
92
|
+
verbosity: undefined,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
test('cleans pending work when a Discord thread is deleted', async () => {
|
|
96
|
+
const threadId = `thread-${crypto.randomUUID()}`;
|
|
97
|
+
const sessionId = `session-${crypto.randomUUID()}`;
|
|
98
|
+
const queueId = `queue-${crypto.randomUUID()}`;
|
|
99
|
+
await setThreadSession(threadId, sessionId);
|
|
100
|
+
await insertThreadQueueItem({
|
|
101
|
+
queueId,
|
|
102
|
+
threadId,
|
|
103
|
+
payloadJson: JSON.stringify({ prompt: 'queued' }),
|
|
104
|
+
});
|
|
105
|
+
await upsertSessionSleep({
|
|
106
|
+
sessionId,
|
|
107
|
+
wakeAt: new Date('2099-01-01T00:00:00.000Z'),
|
|
108
|
+
reason: 'later',
|
|
109
|
+
});
|
|
110
|
+
const ipcRequest = await createIpcRequest({
|
|
111
|
+
type: 'file_upload',
|
|
112
|
+
sessionId,
|
|
113
|
+
threadId,
|
|
114
|
+
payload: '{}',
|
|
115
|
+
});
|
|
116
|
+
const taskId = await createScheduledTask({
|
|
117
|
+
scheduleKind: 'at',
|
|
118
|
+
nextRunAt: new Date('2099-01-01T00:00:00.000Z'),
|
|
119
|
+
payloadJson: JSON.stringify({ kind: 'thread', threadId, prompt: 'later' }),
|
|
120
|
+
promptPreview: 'later',
|
|
121
|
+
threadId,
|
|
122
|
+
sessionId,
|
|
123
|
+
});
|
|
124
|
+
await cleanupDeletedThread(threadId);
|
|
125
|
+
await completeIpcRequest({ id: ipcRequest.id, response: 'late response' });
|
|
126
|
+
expect({
|
|
127
|
+
ipc: await getIpcRequestById({ id: ipcRequest.id }),
|
|
128
|
+
queue: await listThreadQueueItems(threadId),
|
|
129
|
+
session: await getThreadSession(threadId),
|
|
130
|
+
sleep: await getSessionSleep({ sessionId }),
|
|
131
|
+
task: await getScheduledTask(taskId),
|
|
132
|
+
}).toMatchObject({
|
|
133
|
+
ipc: { status: 'cancelled' },
|
|
134
|
+
queue: [],
|
|
135
|
+
session: sessionId,
|
|
136
|
+
sleep: { status: 'cancelled' },
|
|
137
|
+
task: {
|
|
138
|
+
status: 'cancelled',
|
|
139
|
+
last_error: 'Discord thread was deleted',
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
test('deleting an old resumed thread preserves the current session sleep', async () => {
|
|
144
|
+
const db = await getDb();
|
|
145
|
+
const sessionId = `resumed-session-${crypto.randomUUID()}`;
|
|
146
|
+
const oldThreadId = `old-thread-${crypto.randomUUID()}`;
|
|
147
|
+
const currentThreadId = `current-thread-${crypto.randomUUID()}`;
|
|
148
|
+
await setThreadSession(oldThreadId, sessionId);
|
|
149
|
+
await setThreadSession(currentThreadId, sessionId);
|
|
150
|
+
await db.update(schema.thread_sessions)
|
|
151
|
+
.set({ updated_at: new Date('2020-01-01T00:00:00.000Z') })
|
|
152
|
+
.where(orm.eq(schema.thread_sessions.thread_id, oldThreadId));
|
|
153
|
+
await db.update(schema.thread_sessions)
|
|
154
|
+
.set({ updated_at: new Date('2021-01-01T00:00:00.000Z') })
|
|
155
|
+
.where(orm.eq(schema.thread_sessions.thread_id, currentThreadId));
|
|
156
|
+
await upsertSessionSleep({
|
|
157
|
+
sessionId,
|
|
158
|
+
wakeAt: new Date('2099-01-01T00:00:00.000Z'),
|
|
159
|
+
reason: 'still current',
|
|
160
|
+
});
|
|
161
|
+
await cleanupDeletedThread(oldThreadId);
|
|
162
|
+
expect(await getSessionSleep({ sessionId })).toMatchObject({
|
|
163
|
+
status: 'planned',
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
test('rebuilds thread_queue_items that still use queue_id as the primary key', async () => {
|
|
167
|
+
await closeDb();
|
|
168
|
+
const previousDbUrl = process.env['KIMAKI_DB_URL'];
|
|
169
|
+
const dbPath = path.join(process.cwd(), `tmp/test-db-legacy-queue-${crypto.randomUUID().slice(0, 8)}.db`);
|
|
170
|
+
try {
|
|
171
|
+
const client = createClient({ url: `file:${dbPath}` });
|
|
172
|
+
await client.execute(`
|
|
173
|
+
CREATE TABLE thread_queue_items (
|
|
174
|
+
queue_id text PRIMARY KEY,
|
|
175
|
+
thread_id text NOT NULL,
|
|
176
|
+
payload_json text NOT NULL,
|
|
177
|
+
created_at datetime DEFAULT CURRENT_TIMESTAMP
|
|
178
|
+
)
|
|
179
|
+
`);
|
|
180
|
+
await client.execute(`
|
|
181
|
+
CREATE INDEX thread_queue_items_thread_id_created_at_queue_id_idx
|
|
182
|
+
ON thread_queue_items (thread_id, created_at, queue_id)
|
|
183
|
+
`);
|
|
184
|
+
await client.execute(`
|
|
185
|
+
INSERT INTO thread_queue_items (queue_id, thread_id, payload_json, created_at)
|
|
186
|
+
VALUES
|
|
187
|
+
('queue-second', 'thr-legacy-queue', '{"prompt":"second"}', '2026-09-17 10:00:02'),
|
|
188
|
+
('queue-first', 'thr-legacy-queue', '{"prompt":"first"}', '2026-09-17 10:00:01')
|
|
189
|
+
`);
|
|
190
|
+
client.close();
|
|
191
|
+
process.env['KIMAKI_DB_URL'] = `file:${dbPath}`;
|
|
192
|
+
await getDb();
|
|
193
|
+
const rows = await listThreadQueueItems('thr-legacy-queue');
|
|
194
|
+
expect(rows.map((row) => JSON.parse(row.payload_json).prompt)).toEqual([
|
|
195
|
+
'first',
|
|
196
|
+
'second',
|
|
197
|
+
]);
|
|
198
|
+
expect(rows.map((row) => row.id)).toEqual([1, 2]);
|
|
199
|
+
await insertThreadQueueItem({
|
|
200
|
+
queueId: 'queue-third',
|
|
201
|
+
threadId: 'thr-legacy-queue',
|
|
202
|
+
payloadJson: JSON.stringify({ prompt: 'third' }),
|
|
203
|
+
});
|
|
204
|
+
const after = await listThreadQueueItems('thr-legacy-queue');
|
|
205
|
+
expect(after.map((row) => JSON.parse(row.payload_json).prompt)).toEqual([
|
|
206
|
+
'first',
|
|
207
|
+
'second',
|
|
208
|
+
'third',
|
|
209
|
+
]);
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
await closeDb();
|
|
213
|
+
if (previousDbUrl === undefined) {
|
|
214
|
+
delete process.env['KIMAKI_DB_URL'];
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
process.env['KIMAKI_DB_URL'] = previousDbUrl;
|
|
218
|
+
}
|
|
219
|
+
for (const file of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
220
|
+
try {
|
|
221
|
+
fs.unlinkSync(file);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Test cleanup best effort.
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
30
228
|
});
|
|
31
229
|
test('removes part_messages rows whose thread_sessions parent is gone', async () => {
|
|
32
230
|
await closeDb();
|
|
@@ -97,11 +97,12 @@ for (const setup of ['legacy mapping', 'explicit onboarding']) {
|
|
|
97
97
|
const guild = client.guilds.cache.get(trustedGuildId);
|
|
98
98
|
if (setup === 'legacy mapping') {
|
|
99
99
|
await setChannelDirectory({ channelId: projectChannelId, directory, channelType: 'text' });
|
|
100
|
+
expect((await findChannelsByDirectory({}))[0]?.guild_id).toBeNull();
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
103
|
await createProjectChannels({ guild, projectDirectory: path.join(directory, 'project'), analyticsSource: 'onboarding' });
|
|
104
|
+
expect((await findChannelsByDirectory({}))[0]?.guild_id).toBe(trustedGuildId);
|
|
103
105
|
}
|
|
104
|
-
expect((await findChannelsByDirectory({}))[0]?.guild_id).toBeNull();
|
|
105
106
|
// Fetching actual guild channels must work even when startup cache is empty.
|
|
106
107
|
guild.channels.cache.clear();
|
|
107
108
|
const created = await ensureDefaultChannelsWithWelcome({
|