thepopebot 1.2.76-beta.10 → 1.2.76-beta.12
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 +22 -54
- package/drizzle/0022_organic_apocalypse.sql +16 -0
- package/drizzle/0023_needy_ender_wiggin.sql +1 -0
- package/drizzle/meta/0021_snapshot.json +639 -0
- package/drizzle/meta/0022_snapshot.json +743 -0
- package/drizzle/meta/0023_snapshot.json +750 -0
- package/drizzle/meta/_journal.json +14 -0
- package/lib/CLAUDE.md +2 -2
- package/lib/actions.js +9 -1
- package/lib/ai/index.js +19 -9
- package/lib/ai/scope.js +26 -0
- package/lib/ai/sdk-adapters/claude-code.js +20 -9
- package/lib/ai/system-prompt.js +23 -5
- package/lib/ai/tools.js +22 -5
- 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/code/actions.js +23 -4
- package/lib/config.js +0 -5
- package/lib/db/code-workspaces.js +2 -1
- package/lib/db/config.js +0 -1
- package/lib/db/schema.js +23 -1
- package/lib/db/user-channels.js +129 -0
- package/lib/tools/create-agent-job.js +3 -0
- package/lib/tools/docker.js +14 -3
- 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 +24 -1
- package/templates/agent-job/SYSTEM.md +12 -5
- 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
|
@@ -86,12 +86,12 @@ function getTemplateFiles(templatesDir) {
|
|
|
86
86
|
return files;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
async function init() {
|
|
89
|
+
async function init(options = {}) {
|
|
90
90
|
let cwd = process.cwd();
|
|
91
91
|
const packageDir = path.join(__dirname, '..');
|
|
92
92
|
const templatesDir = path.join(packageDir, 'templates');
|
|
93
|
-
const noManaged = args.includes('--no-managed');
|
|
94
|
-
const noInstall = args.includes('--no-install');
|
|
93
|
+
const noManaged = options.noManaged ?? args.includes('--no-managed');
|
|
94
|
+
const noInstall = options.noInstall ?? args.includes('--no-install');
|
|
95
95
|
|
|
96
96
|
// Guard: warn if the directory is not empty (unless it's an existing thepopebot project)
|
|
97
97
|
const entries = fs.readdirSync(cwd);
|
|
@@ -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) {
|
|
@@ -681,6 +646,9 @@ const PROTECTED_PATHS = [
|
|
|
681
646
|
'package.json',
|
|
682
647
|
'docker-compose.custom.yml',
|
|
683
648
|
'.claude/',
|
|
649
|
+
'.codex/',
|
|
650
|
+
'.gemini/',
|
|
651
|
+
'.kimi/',
|
|
684
652
|
'.pi/',
|
|
685
653
|
'skills/',
|
|
686
654
|
'node_modules/',
|
|
@@ -774,10 +742,10 @@ async function resetAll() {
|
|
|
774
742
|
|
|
775
743
|
console.log(`\n Moved ${filesToMove.length} file(s) to .backups/${ts}/`);
|
|
776
744
|
|
|
777
|
-
// Run init to rebuild from templates
|
|
745
|
+
// Run init to rebuild from templates (call directly to use the same package version)
|
|
778
746
|
console.log('\n Running init to rebuild project...\n');
|
|
779
747
|
try {
|
|
780
|
-
|
|
748
|
+
await init({ noInstall: true });
|
|
781
749
|
} catch {
|
|
782
750
|
console.error('\n Init failed. Your backup is at .backups/' + ts + '/\n');
|
|
783
751
|
process.exit(1);
|
|
@@ -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`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE `code_workspaces` ADD `scope` text;
|