thepopebot 1.2.76-beta.10 → 1.2.76-beta.11
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/api/index.js +52 -28
- package/bin/cli.js +14 -49
- package/drizzle/0022_organic_apocalypse.sql +16 -0
- package/drizzle/meta/0021_snapshot.json +639 -0
- package/drizzle/meta/0022_snapshot.json +743 -0
- package/drizzle/meta/_journal.json +7 -0
- package/lib/ai/index.js +17 -9
- package/lib/ai/scope.js +26 -0
- package/lib/ai/system-prompt.js +5 -2
- package/lib/ai/tools.js +13 -3
- package/lib/ai/workspace-setup.js +1 -31
- package/lib/channels/CLAUDE.md +2 -2
- package/lib/channels/base.js +6 -2
- package/lib/channels/commands/index.js +42 -0
- package/lib/channels/commands/session.js +53 -0
- package/lib/channels/commands/verify.js +18 -0
- package/lib/channels/telegram.js +9 -29
- package/lib/chat/actions.js +48 -61
- package/lib/chat/api.js +39 -1
- package/lib/chat/components/chat.js +20 -3
- package/lib/chat/components/chat.jsx +23 -2
- package/lib/chat/components/index.js +1 -1
- package/lib/chat/components/profile-page.js +182 -4
- package/lib/chat/components/profile-page.jsx +196 -1
- package/lib/chat/components/scope-picker.js +21 -0
- package/lib/chat/components/scope-picker.jsx +27 -0
- package/lib/chat/components/settings-secrets-page.js +1 -95
- package/lib/chat/components/settings-secrets-page.jsx +0 -116
- package/lib/chat/telegram-profile.js +33 -0
- package/lib/config.js +0 -5
- package/lib/db/config.js +0 -1
- package/lib/db/schema.js +22 -1
- package/lib/db/user-channels.js +129 -0
- package/lib/tools/docker.js +10 -2
- package/lib/tools/telegram.js +0 -9
- package/lib/utils/render-md.js +43 -17
- package/package.json +2 -1
- package/setup/lib/targets.mjs +0 -2
- package/setup/lib/telegram.mjs +0 -1
- package/setup/setup-telegram.mjs +5 -36
- package/templates/.env.example +0 -7
- package/templates/.gitignore.template +0 -2
- package/templates/CLAUDE.md.template +1 -1
- package/templates/agent-job/SYSTEM.md +4 -4
- package/templates/docker-compose.yml +1 -0
- package/templates/skills/CLAUDE.md.template +16 -23
- package/templates/skills/{library/agent-job-secrets → agent-job-secrets}/SKILL.md +2 -2
- package/setup/lib/telegram-verify.mjs +0 -63
- package/templates/skills/active/.gitkeep +0 -0
- /package/templates/skills/{library/agent-job-secrets → agent-job-secrets}/agent-job-secrets.js +0 -0
- /package/templates/skills/{library/playwright-cli → playwright-cli}/SKILL.md +0 -0
package/api/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { createHash, timingSafeEqual } from 'crypto';
|
|
1
|
+
import { createHash, timingSafeEqual, randomUUID } from 'crypto';
|
|
2
2
|
import { createAgentJob } from '../lib/tools/create-agent-job.js';
|
|
3
3
|
import { setWebhook } from '../lib/tools/telegram.js';
|
|
4
4
|
import { getAgentJobStatus, fetchAgentJobLog } from '../lib/tools/github.js';
|
|
5
5
|
import { getTelegramAdapter } from '../lib/channels/index.js';
|
|
6
|
+
import { dispatchCommand, dispatchPreAuthCommand } from '../lib/channels/commands/index.js';
|
|
7
|
+
import { getByChannelChatId, setActiveThread } from '../lib/db/user-channels.js';
|
|
6
8
|
import { chat, chatStream, summarizeAgentJob } from '../lib/ai/index.js';
|
|
7
9
|
import { createNotification } from '../lib/db/notifications.js';
|
|
8
10
|
import { loadTriggers } from '../lib/triggers.js';
|
|
@@ -209,43 +211,65 @@ async function handleTelegramWebhook(request) {
|
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* Uses chatStream() for progressive tool-call rendering when the adapter
|
|
216
|
-
* supports it (Telegram: sends each tool call as a message, reacts on completion).
|
|
217
|
-
* Falls back to chat() for adapters without streamChatResponse.
|
|
214
|
+
* Resolve the incoming channel message to a user, dispatch any slash command,
|
|
215
|
+
* and otherwise stream the message through the AI layer using the user's
|
|
216
|
+
* active session.
|
|
218
217
|
*/
|
|
219
218
|
async function processChannelMessage(adapter, normalized) {
|
|
220
|
-
|
|
221
|
-
const
|
|
219
|
+
const { channel, channelChatId, metadata } = normalized;
|
|
220
|
+
const binding = getByChannelChatId(channel, channelChatId);
|
|
221
|
+
|
|
222
|
+
// Unbound chat → only /verify is accepted; everything else is silently ignored.
|
|
223
|
+
if (!binding || !binding.verifiedAt) {
|
|
224
|
+
const result = await dispatchPreAuthCommand(normalized, { channel, channelChatId });
|
|
225
|
+
if (result?.handled) {
|
|
226
|
+
await adapter.sendResponse(channelChatId, result.reply, metadata);
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const ctx = { channel, channelChatId, userId: binding.userId };
|
|
232
|
+
|
|
233
|
+
// Post-auth slash commands short-circuit the AI path.
|
|
234
|
+
const cmd = await dispatchCommand(normalized, ctx);
|
|
235
|
+
if (cmd?.handled) {
|
|
236
|
+
await adapter.sendResponse(channelChatId, cmd.reply, metadata);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
await adapter.acknowledge(metadata);
|
|
241
|
+
const stopIndicator = adapter.startProcessingIndicator(metadata);
|
|
222
242
|
|
|
223
243
|
try {
|
|
244
|
+
let threadId = binding.activeThreadId;
|
|
245
|
+
if (!threadId) {
|
|
246
|
+
threadId = randomUUID();
|
|
247
|
+
setActiveThread(binding.userId, channel, threadId);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const envRepo = process.env.GH_OWNER && process.env.GH_REPO
|
|
251
|
+
? `${process.env.GH_OWNER}/${process.env.GH_REPO}`
|
|
252
|
+
: '';
|
|
253
|
+
const streamOptions = {
|
|
254
|
+
userId: binding.userId,
|
|
255
|
+
chatTitle: 'Telegram',
|
|
256
|
+
repo: envRepo,
|
|
257
|
+
branch: 'main',
|
|
258
|
+
codeMode: false,
|
|
259
|
+
codeModeType: 'code',
|
|
260
|
+
};
|
|
261
|
+
|
|
224
262
|
if (adapter.streamChatResponse) {
|
|
225
|
-
const chunks = chatStream(
|
|
226
|
-
|
|
227
|
-
normalized.text,
|
|
228
|
-
normalized.attachments,
|
|
229
|
-
{ userId: 'telegram', chatTitle: 'Telegram' }
|
|
230
|
-
);
|
|
231
|
-
await adapter.streamChatResponse(normalized.metadata.chatId, chunks);
|
|
263
|
+
const chunks = chatStream(threadId, normalized.text, normalized.attachments, streamOptions);
|
|
264
|
+
await adapter.streamChatResponse(channelChatId, chunks);
|
|
232
265
|
} else {
|
|
233
|
-
const response = await chat(
|
|
234
|
-
|
|
235
|
-
normalized.text,
|
|
236
|
-
normalized.attachments,
|
|
237
|
-
{ userId: 'telegram', chatTitle: 'Telegram' }
|
|
238
|
-
);
|
|
239
|
-
await adapter.sendResponse(normalized.threadId, response, normalized.metadata);
|
|
266
|
+
const response = await chat(threadId, normalized.text, normalized.attachments, streamOptions);
|
|
267
|
+
await adapter.sendResponse(channelChatId, response, metadata);
|
|
240
268
|
}
|
|
241
269
|
} catch (err) {
|
|
242
270
|
console.error('Failed to process message with AI:', err);
|
|
243
271
|
await adapter
|
|
244
|
-
.sendResponse(
|
|
245
|
-
normalized.threadId,
|
|
246
|
-
'Sorry, I encountered an error processing your message.',
|
|
247
|
-
normalized.metadata
|
|
248
|
-
)
|
|
272
|
+
.sendResponse(channelChatId, 'Sorry, I encountered an error processing your message.', metadata)
|
|
249
273
|
.catch(() => {});
|
|
250
274
|
} finally {
|
|
251
275
|
stopIndicator();
|
package/bin/cli.js
CHANGED
|
@@ -277,58 +277,23 @@ async function init() {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
// Create
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
280
|
+
// Create agent skill bridge symlinks (point to ../skills)
|
|
281
|
+
const skillBridges = [
|
|
282
|
+
{ dir: '.pi', name: 'Pi' },
|
|
283
|
+
{ dir: '.claude', name: 'Claude' },
|
|
284
|
+
{ dir: '.codex', name: 'Codex' },
|
|
285
|
+
{ dir: '.gemini', name: 'Gemini' },
|
|
286
|
+
{ dir: '.kimi', name: 'Kimi' },
|
|
287
|
+
];
|
|
288
|
+
for (const { dir, name } of skillBridges) {
|
|
289
|
+
const link = path.join(cwd, dir, 'skills');
|
|
290
|
+
if (!fs.existsSync(link)) {
|
|
291
|
+
fs.mkdirSync(path.dirname(link), { recursive: true });
|
|
292
|
+
createDirLink('../skills', link);
|
|
293
|
+
console.log(` Created ${dir}/skills → ../skills`);
|
|
289
294
|
}
|
|
290
295
|
}
|
|
291
296
|
|
|
292
|
-
// Create .pi/skills → ../skills/active symlink
|
|
293
|
-
const piSkillsLink = path.join(cwd, '.pi', 'skills');
|
|
294
|
-
if (!fs.existsSync(piSkillsLink)) {
|
|
295
|
-
fs.mkdirSync(path.dirname(piSkillsLink), { recursive: true });
|
|
296
|
-
createDirLink('../skills/active', piSkillsLink);
|
|
297
|
-
console.log(' Created .pi/skills → ../skills/active');
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Create .claude/skills → ../skills/active symlink
|
|
301
|
-
const claudeSkillsLink = path.join(cwd, '.claude', 'skills');
|
|
302
|
-
if (!fs.existsSync(claudeSkillsLink)) {
|
|
303
|
-
fs.mkdirSync(path.dirname(claudeSkillsLink), { recursive: true });
|
|
304
|
-
createDirLink('../skills/active', claudeSkillsLink);
|
|
305
|
-
console.log(' Created .claude/skills → ../skills/active');
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Create .codex/skills → ../skills/active symlink
|
|
309
|
-
const codexSkillsLink = path.join(cwd, '.codex', 'skills');
|
|
310
|
-
if (!fs.existsSync(codexSkillsLink)) {
|
|
311
|
-
fs.mkdirSync(path.dirname(codexSkillsLink), { recursive: true });
|
|
312
|
-
createDirLink('../skills/active', codexSkillsLink);
|
|
313
|
-
console.log(' Created .codex/skills → ../skills/active');
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Create .gemini/skills → ../skills/active symlink
|
|
317
|
-
const geminiSkillsLink = path.join(cwd, '.gemini', 'skills');
|
|
318
|
-
if (!fs.existsSync(geminiSkillsLink)) {
|
|
319
|
-
fs.mkdirSync(path.dirname(geminiSkillsLink), { recursive: true });
|
|
320
|
-
createDirLink('../skills/active', geminiSkillsLink);
|
|
321
|
-
console.log(' Created .gemini/skills → ../skills/active');
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Create .kimi/skills → ../skills/active symlink
|
|
325
|
-
const kimiSkillsLink = path.join(cwd, '.kimi', 'skills');
|
|
326
|
-
if (!fs.existsSync(kimiSkillsLink)) {
|
|
327
|
-
fs.mkdirSync(path.dirname(kimiSkillsLink), { recursive: true });
|
|
328
|
-
createDirLink('../skills/active', kimiSkillsLink);
|
|
329
|
-
console.log(' Created .kimi/skills → ../skills/active');
|
|
330
|
-
}
|
|
331
|
-
|
|
332
297
|
|
|
333
298
|
// Report backed-up files
|
|
334
299
|
if (backedUp.length > 0) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
CREATE TABLE `user_channels` (
|
|
2
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`user_id` text NOT NULL,
|
|
4
|
+
`channel` text NOT NULL,
|
|
5
|
+
`channel_chat_id` text,
|
|
6
|
+
`code` text,
|
|
7
|
+
`code_expires_at` integer,
|
|
8
|
+
`verified_at` integer,
|
|
9
|
+
`active_thread_id` text,
|
|
10
|
+
`created_at` integer NOT NULL,
|
|
11
|
+
`updated_at` integer NOT NULL
|
|
12
|
+
);
|
|
13
|
+
--> statement-breakpoint
|
|
14
|
+
CREATE UNIQUE INDEX `user_channels_user_channel_unique` ON `user_channels` (`user_id`,`channel`);--> statement-breakpoint
|
|
15
|
+
CREATE UNIQUE INDEX `user_channels_channel_chat_id_unique` ON `user_channels` (`channel`,`channel_chat_id`);--> statement-breakpoint
|
|
16
|
+
CREATE INDEX `user_channels_code_lookup` ON `user_channels` (`code`);
|