lazy-gravity 0.0.3 → 0.1.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/README.md +7 -4
- package/dist/bin/commands/doctor.js +24 -19
- package/dist/bot/index.js +133 -8
- package/dist/commands/registerSlashCommands.js +5 -0
- package/dist/commands/workspaceCommandHandler.js +17 -28
- package/dist/events/interactionCreateHandler.js +312 -26
- package/dist/events/messageCreateHandler.js +9 -0
- package/dist/services/approvalDetector.js +1 -0
- package/dist/services/assistantDomExtractor.js +339 -0
- package/dist/services/cdpBridgeManager.js +188 -4
- package/dist/services/cdpConnectionPool.js +56 -0
- package/dist/services/cdpService.js +0 -2
- package/dist/services/errorPopupDetector.js +265 -0
- package/dist/services/planningDetector.js +312 -0
- package/dist/services/responseMonitor.js +183 -46
- package/dist/services/retryStore.js +46 -0
- package/dist/ui/buttonUtils.js +33 -0
- package/dist/ui/modelsUi.js +24 -13
- package/dist/ui/projectListUi.js +83 -0
- package/dist/utils/configLoader.js +8 -0
- package/dist/utils/discordFormatter.js +149 -16
- package/dist/utils/htmlToDiscordMarkdown.js +184 -0
- package/dist/utils/logFileTransport.js +147 -0
- package/dist/utils/logger.js +15 -10
- package/dist/utils/processLogBuffer.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="docs/assets/LazyGravityBanner.png" alt="LazyGravity Banner" width="100%" />
|
|
2
|
+
<img src="https://raw.githubusercontent.com/tokyoweb3/LazyGravity/main/docs/assets/LazyGravityBanner.png" alt="LazyGravity Banner" width="100%" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<img src="https://img.shields.io/badge/version-0.0.
|
|
6
|
+
<img src="https://img.shields.io/badge/version-0.0.4-blue?style=flat-square" alt="Version" />
|
|
7
7
|
<img src="https://img.shields.io/badge/node-18.x+-brightgreen?style=flat-square&logo=node.js" alt="Node.js" />
|
|
8
8
|
<img src="https://img.shields.io/badge/discord.js-14.x-5865F2?style=flat-square&logo=discord&logoColor=white" alt="discord.js" />
|
|
9
9
|
<img src="https://img.shields.io/badge/protocol-CDP%20%2F%20WebSocket-orange?style=flat-square" alt="CDP/WebSocket" />
|
|
@@ -117,7 +117,10 @@ lazy-gravity setup
|
|
|
117
117
|
|
|
118
118
|
The wizard guides you through 4 steps:
|
|
119
119
|
|
|
120
|
-
1. **Discord Bot Token** — create a bot at the [Discord Developer Portal](https://discord.com/developers/applications)
|
|
120
|
+
1. **Discord Bot Token** — create a bot at the [Discord Developer Portal](https://discord.com/developers/applications).
|
|
121
|
+
- Enable Privileged Gateway Intents: **PRESENCE, SERVER MEMBERS, MESSAGE CONTENT**.
|
|
122
|
+
- Generate an OAuth2 invite URL with the following bot permissions: **Manage Channels** (required for `/project`), **Send Messages**, **Embed Links**, **Attach Files**, **Read Message History**, and **Add Reactions**.
|
|
123
|
+
- Invite the bot to your server, then copy the bot token. Client ID is extracted from the token automatically.
|
|
121
124
|
2. **Guild (Server) ID** — for instant slash command registration (optional; press Enter to skip).
|
|
122
125
|
3. **Allowed User IDs** — Discord users authorized to interact with the bot.
|
|
123
126
|
4. **Workspace Directory** — parent directory where your coding projects live.
|
|
@@ -210,7 +213,7 @@ Run `lazy-gravity doctor` to diagnose configuration and connectivity issues.
|
|
|
210
213
|
## How CDP Connection Works
|
|
211
214
|
|
|
212
215
|
<p align="center">
|
|
213
|
-
<img src="docs/images/architecture.svg" alt="LazyGravity Architecture" width="100%" />
|
|
216
|
+
<img src="https://raw.githubusercontent.com/tokyoweb3/LazyGravity/main/docs/images/architecture.svg" alt="LazyGravity Architecture" width="100%" />
|
|
214
217
|
</p>
|
|
215
218
|
|
|
216
219
|
1. The bot scans debug ports (default: 9222) and auto-detects the Antigravity target
|
|
@@ -39,6 +39,11 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const cdpPorts_1 = require("../../utils/cdpPorts");
|
|
41
41
|
const configLoader_1 = require("../../utils/configLoader");
|
|
42
|
+
const logger_1 = require("../../utils/logger");
|
|
43
|
+
const ok = (msg) => console.log(` ${logger_1.COLORS.green}[OK]${logger_1.COLORS.reset} ${msg}`);
|
|
44
|
+
const warn = (msg) => console.log(` ${logger_1.COLORS.yellow}[--]${logger_1.COLORS.reset} ${msg}`);
|
|
45
|
+
const fail = (msg) => console.log(` ${logger_1.COLORS.red}[!!]${logger_1.COLORS.reset} ${msg}`);
|
|
46
|
+
const hint = (msg) => console.log(` ${logger_1.COLORS.dim}${msg}${logger_1.COLORS.reset}`);
|
|
42
47
|
function checkPort(port) {
|
|
43
48
|
return new Promise((resolve) => {
|
|
44
49
|
const req = http.get(`http://127.0.0.1:${port}/json/list`, (res) => {
|
|
@@ -73,84 +78,84 @@ function checkRequiredEnvVars() {
|
|
|
73
78
|
}));
|
|
74
79
|
}
|
|
75
80
|
async function doctorAction() {
|
|
76
|
-
console.log(
|
|
81
|
+
console.log(`\n${logger_1.COLORS.cyan}lazy-gravity doctor${logger_1.COLORS.reset}\n`);
|
|
77
82
|
let allOk = true;
|
|
78
83
|
// 1. Config directory check
|
|
79
84
|
const configDir = configLoader_1.ConfigLoader.getConfigDir();
|
|
80
85
|
if (fs.existsSync(configDir)) {
|
|
81
|
-
|
|
86
|
+
ok(`Config directory exists: ${configDir}`);
|
|
82
87
|
}
|
|
83
88
|
else {
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
warn(`Config directory not found: ${configDir}`);
|
|
90
|
+
hint('Run: lazy-gravity setup (optional if using .env)');
|
|
86
91
|
}
|
|
87
92
|
// 2. Config file check
|
|
88
93
|
const configFilePath = configLoader_1.ConfigLoader.getConfigFilePath();
|
|
89
94
|
if (configLoader_1.ConfigLoader.configExists()) {
|
|
90
|
-
|
|
95
|
+
ok(`Config file found: ${configFilePath}`);
|
|
91
96
|
}
|
|
92
97
|
else {
|
|
93
|
-
|
|
98
|
+
warn(`Config file not found: ${configFilePath} (optional — .env fallback used)`);
|
|
94
99
|
}
|
|
95
100
|
// 3. .env file check
|
|
96
101
|
const env = checkEnvFile();
|
|
97
102
|
if (env.exists) {
|
|
98
103
|
// Load .env so subsequent checks can see the variables
|
|
99
104
|
require('dotenv').config({ path: env.path });
|
|
100
|
-
|
|
105
|
+
ok(`.env file found: ${env.path}`);
|
|
101
106
|
}
|
|
102
107
|
else {
|
|
103
108
|
if (!configLoader_1.ConfigLoader.configExists()) {
|
|
104
|
-
|
|
109
|
+
fail(`.env file not found: ${env.path}`);
|
|
105
110
|
allOk = false;
|
|
106
111
|
}
|
|
107
112
|
else {
|
|
108
|
-
|
|
113
|
+
warn(`.env file not found: ${env.path} (not needed — config.json used)`);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
// 4. Required environment variables (check both env and config.json sources)
|
|
112
117
|
const vars = checkRequiredEnvVars();
|
|
113
118
|
for (const v of vars) {
|
|
114
119
|
if (v.set) {
|
|
115
|
-
|
|
120
|
+
ok(`${v.name} is set`);
|
|
116
121
|
}
|
|
117
122
|
else {
|
|
118
|
-
|
|
123
|
+
fail(`${v.name} is NOT set`);
|
|
119
124
|
allOk = false;
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
// 5. CDP port check
|
|
123
|
-
console.log(
|
|
128
|
+
console.log(`\n ${logger_1.COLORS.dim}Checking CDP ports...${logger_1.COLORS.reset}`);
|
|
124
129
|
let cdpOk = false;
|
|
125
130
|
for (const port of cdpPorts_1.CDP_PORTS) {
|
|
126
131
|
const alive = await checkPort(port);
|
|
127
132
|
if (alive) {
|
|
128
|
-
|
|
133
|
+
ok(`CDP port ${port} is responding`);
|
|
129
134
|
cdpOk = true;
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
if (!cdpOk) {
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
fail('No CDP ports responding');
|
|
139
|
+
hint('Run: open -a Antigravity --args --remote-debugging-port=9222');
|
|
135
140
|
allOk = false;
|
|
136
141
|
}
|
|
137
142
|
// 6. Node.js version check
|
|
138
143
|
const nodeVersion = process.versions.node;
|
|
139
144
|
const major = parseInt(nodeVersion.split('.')[0], 10);
|
|
140
145
|
if (major >= 18) {
|
|
141
|
-
|
|
146
|
+
ok(`Node.js ${nodeVersion}`);
|
|
142
147
|
}
|
|
143
148
|
else {
|
|
144
|
-
|
|
149
|
+
fail(`Node.js ${nodeVersion} (>= 18.0.0 required)`);
|
|
145
150
|
allOk = false;
|
|
146
151
|
}
|
|
147
152
|
// Summary
|
|
148
153
|
console.log('');
|
|
149
154
|
if (allOk) {
|
|
150
|
-
console.log(
|
|
155
|
+
console.log(` ${logger_1.COLORS.green}All checks passed!${logger_1.COLORS.reset}`);
|
|
151
156
|
}
|
|
152
157
|
else {
|
|
153
|
-
console.log(
|
|
158
|
+
console.log(` ${logger_1.COLORS.red}Some checks failed. Please fix the issues above.${logger_1.COLORS.reset}`);
|
|
154
159
|
process.exitCode = 1;
|
|
155
160
|
}
|
|
156
161
|
}
|
package/dist/bot/index.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -60,6 +93,8 @@ const PHASE_ICONS = {
|
|
|
60
93
|
};
|
|
61
94
|
const MAX_OUTBOUND_GENERATED_IMAGES = 4;
|
|
62
95
|
const RESPONSE_DELIVERY_MODE = (0, config_1.resolveResponseDeliveryMode)();
|
|
96
|
+
/** Tracks channel IDs where /stop was explicitly invoked by the user */
|
|
97
|
+
const userStopRequestedChannels = new Set();
|
|
63
98
|
const getResponseDeliveryModeForTest = () => RESPONSE_DELIVERY_MODE;
|
|
64
99
|
exports.getResponseDeliveryModeForTest = getResponseDeliveryModeForTest;
|
|
65
100
|
function createSerialTaskQueueForTest(queueName, traceId) {
|
|
@@ -387,7 +422,7 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
387
422
|
onProgress: (text) => {
|
|
388
423
|
if (isFinalized)
|
|
389
424
|
return;
|
|
390
|
-
//
|
|
425
|
+
// Live output streaming disabled: RESPONSE_TEXT currently includes process logs (see #1).
|
|
391
426
|
const separated = (0, discordFormatter_1.splitOutputAndLogs)(text);
|
|
392
427
|
if (separated.output && separated.output.trim().length > 0) {
|
|
393
428
|
lastProgressText = separated.output;
|
|
@@ -395,8 +430,49 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
395
430
|
},
|
|
396
431
|
onComplete: async (finalText) => {
|
|
397
432
|
isFinalized = true;
|
|
433
|
+
// If the user explicitly pressed /stop, skip output display entirely
|
|
434
|
+
const wasStoppedByUser = userStopRequestedChannels.delete(message.channelId);
|
|
435
|
+
if (wasStoppedByUser) {
|
|
436
|
+
logger_1.logger.info(`[sendPromptToAntigravity:${monitorTraceId}] Stopped by user — skipping output`);
|
|
437
|
+
await clearWatchingReaction();
|
|
438
|
+
await message.react('⏹️').catch(() => { });
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
398
441
|
try {
|
|
399
442
|
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
443
|
+
const isQuotaError = monitor.getPhase() === 'quotaReached' || monitor.getQuotaDetected();
|
|
444
|
+
// Quota early exit — skip text extraction, output logging, and embed entirely
|
|
445
|
+
if (isQuotaError) {
|
|
446
|
+
const finalLogText = lastActivityLogText || processLogBuffer.snapshot();
|
|
447
|
+
if (finalLogText && finalLogText.trim().length > 0) {
|
|
448
|
+
logger_1.logger.divider('Process Log');
|
|
449
|
+
console.info(finalLogText);
|
|
450
|
+
}
|
|
451
|
+
logger_1.logger.divider();
|
|
452
|
+
liveActivityUpdateVersion += 1;
|
|
453
|
+
await upsertLiveActivityEmbeds(`${PHASE_ICONS.thinking} Process Log`, finalLogText || ACTIVITY_PLACEHOLDER, PHASE_COLORS.thinking, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Process log`), {
|
|
454
|
+
source: 'complete',
|
|
455
|
+
expectedVersion: liveActivityUpdateVersion,
|
|
456
|
+
});
|
|
457
|
+
liveResponseUpdateVersion += 1;
|
|
458
|
+
await upsertLiveResponseEmbeds('⚠️ Model Quota Reached', 'Model quota limit reached. Please wait or switch to a different model.', 0xFF6B6B, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Quota Reached`), {
|
|
459
|
+
source: 'complete',
|
|
460
|
+
expectedVersion: liveResponseUpdateVersion,
|
|
461
|
+
});
|
|
462
|
+
try {
|
|
463
|
+
const modelsPayload = await (0, modelsUi_1.buildModelsUI)(cdp, () => bridge.quota.fetchQuota());
|
|
464
|
+
if (modelsPayload && channel) {
|
|
465
|
+
await channel.send({ ...modelsPayload });
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
catch (e) {
|
|
469
|
+
logger_1.logger.error('[Quota] Failed to send model selection UI:', e);
|
|
470
|
+
}
|
|
471
|
+
await clearWatchingReaction();
|
|
472
|
+
await message.react('⚠️').catch(() => { });
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
// Normal path — extract final text
|
|
400
476
|
const responseText = (finalText && finalText.trim().length > 0)
|
|
401
477
|
? finalText
|
|
402
478
|
: lastProgressText;
|
|
@@ -464,12 +540,6 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
464
540
|
logger_1.logger.error('[Rename] Failed to get title from Antigravity and rename:', e);
|
|
465
541
|
}
|
|
466
542
|
}
|
|
467
|
-
if (monitor.getPhase() === 'quotaReached' || monitor.getQuotaDetected()) {
|
|
468
|
-
await sendEmbed('⚠️ Model Quota Reached', 'Model quota limit reached. Please wait or switch to a different model with `/model`.', 0xFF6B6B, undefined, 'Quota Reached — consider switching models');
|
|
469
|
-
await clearWatchingReaction();
|
|
470
|
-
await message.react('⚠️').catch(() => { });
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
543
|
await sendGeneratedImages(finalOutputText || '');
|
|
474
544
|
await clearWatchingReaction();
|
|
475
545
|
await message.react(finalOutputText && finalOutputText.trim().length > 0 ? '✅' : '⚠️').catch(() => { });
|
|
@@ -511,6 +581,21 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
511
581
|
},
|
|
512
582
|
});
|
|
513
583
|
await monitor.start();
|
|
584
|
+
// 1-second elapsed timer — updates footer independently of process log events
|
|
585
|
+
const elapsedTimer = setInterval(() => {
|
|
586
|
+
if (isFinalized) {
|
|
587
|
+
clearInterval(elapsedTimer);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
591
|
+
liveActivityUpdateVersion += 1;
|
|
592
|
+
const activityVersion = liveActivityUpdateVersion;
|
|
593
|
+
upsertLiveActivityEmbeds(`${PHASE_ICONS.thinking} Process Log`, lastActivityLogText || ACTIVITY_PLACEHOLDER, PHASE_COLORS.thinking, (0, i18n_1.t)(`⏱️ Elapsed: ${elapsed}s | Process log`), {
|
|
594
|
+
source: 'elapsed-tick',
|
|
595
|
+
expectedVersion: activityVersion,
|
|
596
|
+
skipWhenFinalized: true,
|
|
597
|
+
}).catch(() => { });
|
|
598
|
+
}, 1000);
|
|
514
599
|
}
|
|
515
600
|
catch (e) {
|
|
516
601
|
isFinalized = true;
|
|
@@ -559,13 +644,43 @@ const startBot = async () => {
|
|
|
559
644
|
]
|
|
560
645
|
});
|
|
561
646
|
client.once(discord_js_1.Events.ClientReady, async (readyClient) => {
|
|
562
|
-
logger_1.logger.info(`Ready! Logged in as ${readyClient.user.tag}`);
|
|
647
|
+
logger_1.logger.info(`Ready! Logged in as ${readyClient.user.tag} | extractionMode=${config.extractionMode}`);
|
|
563
648
|
try {
|
|
564
649
|
await (0, registerSlashCommands_1.registerSlashCommands)(config.discordToken, config.clientId, config.guildId);
|
|
565
650
|
}
|
|
566
651
|
catch (error) {
|
|
567
652
|
logger_1.logger.warn('Failed to register slash commands, but text commands remain available.');
|
|
568
653
|
}
|
|
654
|
+
// Startup dashboard embed
|
|
655
|
+
try {
|
|
656
|
+
const os = await Promise.resolve().then(() => __importStar(require('os')));
|
|
657
|
+
const pkg = await Promise.resolve().then(() => __importStar(require('../../package.json')));
|
|
658
|
+
const version = pkg.default?.version ?? pkg.version ?? 'unknown';
|
|
659
|
+
const projects = workspaceService.scanWorkspaces();
|
|
660
|
+
// Check CDP connection status
|
|
661
|
+
const activeWorkspaces = bridge.pool.getActiveWorkspaceNames();
|
|
662
|
+
const cdpStatus = activeWorkspaces.length > 0
|
|
663
|
+
? `Connected (${activeWorkspaces.join(', ')})`
|
|
664
|
+
: 'Not connected';
|
|
665
|
+
const dashboardEmbed = new discord_js_1.EmbedBuilder()
|
|
666
|
+
.setTitle('LazyGravity Online')
|
|
667
|
+
.setColor(0x57F287)
|
|
668
|
+
.addFields({ name: 'Version', value: version, inline: true }, { name: 'Node.js', value: process.versions.node, inline: true }, { name: 'OS', value: `${os.platform()} ${os.release()}`, inline: true }, { name: 'CDP', value: cdpStatus, inline: true }, { name: 'Model', value: modelService.getCurrentModel(), inline: true }, { name: 'Mode', value: modeService.getCurrentMode(), inline: true }, { name: 'Projects', value: `${projects.length} registered`, inline: true }, { name: 'Extraction', value: config.extractionMode, inline: true })
|
|
669
|
+
.setFooter({ text: `Started at ${new Date().toLocaleString()}` })
|
|
670
|
+
.setTimestamp();
|
|
671
|
+
// Send to the first available text channel in the guild
|
|
672
|
+
const guild = readyClient.guilds.cache.first();
|
|
673
|
+
if (guild) {
|
|
674
|
+
const channel = guild.channels.cache.find((ch) => ch.isTextBased() && !ch.isVoiceBased() && ch.permissionsFor(readyClient.user)?.has('SendMessages'));
|
|
675
|
+
if (channel && channel.isTextBased()) {
|
|
676
|
+
await channel.send({ embeds: [dashboardEmbed] });
|
|
677
|
+
logger_1.logger.info('Startup dashboard embed sent.');
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
catch (error) {
|
|
682
|
+
logger_1.logger.warn('Failed to send startup dashboard embed:', error);
|
|
683
|
+
}
|
|
569
684
|
});
|
|
570
685
|
// [Discord Interactions API] Slash command interaction handler
|
|
571
686
|
client.on(discord_js_1.Events.InteractionCreate, (0, interactionCreateHandler_1.createInteractionCreateHandler)({
|
|
@@ -583,6 +698,8 @@ const startBot = async () => {
|
|
|
583
698
|
sendAutoAcceptUI: autoAcceptUi_1.sendAutoAcceptUI,
|
|
584
699
|
getCurrentCdp: cdpBridgeManager_1.getCurrentCdp,
|
|
585
700
|
parseApprovalCustomId: cdpBridgeManager_1.parseApprovalCustomId,
|
|
701
|
+
parseErrorPopupCustomId: cdpBridgeManager_1.parseErrorPopupCustomId,
|
|
702
|
+
parsePlanningCustomId: cdpBridgeManager_1.parsePlanningCustomId,
|
|
586
703
|
handleSlashInteraction: async (interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg) => handleSlashInteraction(interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg, promptDispatcher, templateRepo),
|
|
587
704
|
handleTemplateUse: async (interaction, templateId) => {
|
|
588
705
|
const template = templateRepo.findById(templateId);
|
|
@@ -609,6 +726,8 @@ const startBot = async () => {
|
|
|
609
726
|
(0, cdpBridgeManager_1.registerApprovalSessionChannel)(bridge, dirName, session.displayName, interaction.channel);
|
|
610
727
|
}
|
|
611
728
|
(0, cdpBridgeManager_1.ensureApprovalDetector)(bridge, cdp, dirName, client);
|
|
729
|
+
(0, cdpBridgeManager_1.ensureErrorPopupDetector)(bridge, cdp, dirName, client);
|
|
730
|
+
(0, cdpBridgeManager_1.ensurePlanningDetector)(bridge, cdp, dirName, client);
|
|
612
731
|
}
|
|
613
732
|
catch (e) {
|
|
614
733
|
await interaction.followUp({
|
|
@@ -858,6 +977,7 @@ async function handleSlashInteraction(interaction, handler, bridge, wsHandler, c
|
|
|
858
977
|
const result = await cdp.call('Runtime.evaluate', callParams);
|
|
859
978
|
const value = result?.result?.value;
|
|
860
979
|
if (value?.ok) {
|
|
980
|
+
userStopRequestedChannels.add(interaction.channelId);
|
|
861
981
|
const embed = new discord_js_1.EmbedBuilder()
|
|
862
982
|
.setTitle('⏹️ Generation Interrupted')
|
|
863
983
|
.setDescription('AI response generation was safely stopped.')
|
|
@@ -906,6 +1026,11 @@ async function handleSlashInteraction(interaction, handler, bridge, wsHandler, c
|
|
|
906
1026
|
await cleanupHandler.handleCleanup(interaction);
|
|
907
1027
|
break;
|
|
908
1028
|
}
|
|
1029
|
+
case 'ping': {
|
|
1030
|
+
const apiLatency = interaction.client.ws.ping;
|
|
1031
|
+
await interaction.editReply({ content: `🏓 Pong! API Latency is **${apiLatency}ms**.` });
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
909
1034
|
default:
|
|
910
1035
|
await interaction.editReply({
|
|
911
1036
|
content: `Unknown command: /${commandName}`,
|
|
@@ -102,6 +102,10 @@ const cleanupCommand = new discord_js_1.SlashCommandBuilder()
|
|
|
102
102
|
const helpCommand = new discord_js_1.SlashCommandBuilder()
|
|
103
103
|
.setName('help')
|
|
104
104
|
.setDescription((0, i18n_1.t)('Display list of available commands'));
|
|
105
|
+
/** /ping command definition */
|
|
106
|
+
const pingCommand = new discord_js_1.SlashCommandBuilder()
|
|
107
|
+
.setName('ping')
|
|
108
|
+
.setDescription((0, i18n_1.t)('Check bot latency'));
|
|
105
109
|
/** Array of commands to register */
|
|
106
110
|
exports.slashCommands = [
|
|
107
111
|
helpCommand,
|
|
@@ -116,6 +120,7 @@ exports.slashCommands = [
|
|
|
116
120
|
newCommand,
|
|
117
121
|
chatCommand,
|
|
118
122
|
cleanupCommand,
|
|
123
|
+
pingCommand,
|
|
119
124
|
];
|
|
120
125
|
/**
|
|
121
126
|
* Register slash commands with Discord
|
|
@@ -7,10 +7,11 @@ exports.WorkspaceCommandHandler = exports.WORKSPACE_SELECT_ID = exports.PROJECT_
|
|
|
7
7
|
const i18n_1 = require("../utils/i18n");
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const discord_js_1 = require("discord.js");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
exports.
|
|
10
|
+
const projectListUi_1 = require("../ui/projectListUi");
|
|
11
|
+
// Re-export for backward compatibility
|
|
12
|
+
var projectListUi_2 = require("../ui/projectListUi");
|
|
13
|
+
Object.defineProperty(exports, "PROJECT_SELECT_ID", { enumerable: true, get: function () { return projectListUi_2.PROJECT_SELECT_ID; } });
|
|
14
|
+
Object.defineProperty(exports, "WORKSPACE_SELECT_ID", { enumerable: true, get: function () { return projectListUi_2.WORKSPACE_SELECT_ID; } });
|
|
14
15
|
/**
|
|
15
16
|
* Handler for the /project slash command.
|
|
16
17
|
* When a project is selected, auto-creates a Discord category + session-1 channel and binds them.
|
|
@@ -31,31 +32,19 @@ class WorkspaceCommandHandler {
|
|
|
31
32
|
* /project list -- Display project list via select menu
|
|
32
33
|
*/
|
|
33
34
|
async handleShow(interaction) {
|
|
34
|
-
const embed = new discord_js_1.EmbedBuilder()
|
|
35
|
-
.setTitle('📁 Projects')
|
|
36
|
-
.setColor(0x5865F2)
|
|
37
|
-
.setDescription((0, i18n_1.t)('Select a project to auto-create a category and session channel'))
|
|
38
|
-
.setTimestamp();
|
|
39
|
-
const components = [];
|
|
40
35
|
const workspaces = this.workspaceService.scanWorkspaces();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
components.push(new discord_js_1.ActionRowBuilder().addComponents(selectMenu));
|
|
54
|
-
}
|
|
55
|
-
await interaction.editReply({
|
|
56
|
-
embeds: [embed],
|
|
57
|
-
components,
|
|
58
|
-
});
|
|
36
|
+
const { embeds, components } = (0, projectListUi_1.buildProjectListUI)(workspaces, 0);
|
|
37
|
+
await interaction.editReply({ embeds, components });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Handle page navigation button press.
|
|
41
|
+
* Re-scans workspaces and renders the requested page.
|
|
42
|
+
*/
|
|
43
|
+
async handlePageButton(interaction, page) {
|
|
44
|
+
await interaction.deferUpdate();
|
|
45
|
+
const workspaces = this.workspaceService.scanWorkspaces();
|
|
46
|
+
const { embeds, components } = (0, projectListUi_1.buildProjectListUI)(workspaces, page);
|
|
47
|
+
await interaction.editReply({ embeds, components });
|
|
59
48
|
}
|
|
60
49
|
/**
|
|
61
50
|
* Handler for when a project is selected from the select menu.
|